Using stateful TCP connection to a server

we have a server that uses a custom TCP connection as a transport (very similar to websocket concept) we already have a jar that can be used to connect and send api’s to it.
I’d like to create a web ui wrapper for it, and I’m thinking about using an instance of this jar client as in vaadin session
that upon login it would be stored like so:

VaadinSession.getCurrent().setAttribute(Client.class, commClient);

and retrieved later on by each view to be used.
is that feasible?

I’m not sure if the VaadinSession is the best place, but that sure could work. Depending if your Client needs to be UI, Session or Application specific, I’d store the reference directly to the UI class or create some appropriately scoped Spring bean to store it (and possibly wrap its API).

i’m not using spring.
why do you think it’s not the best place?
i don’t see this thing as being Application scoped because each TCP connection, is specific to a user.
it can’t be UI scoped cause that would mean closing and opening it all the time, when switching between ui classes, which doesn’t make sense as not feasible as some api’s actually cause async message to start following, it’s entire concept is almost like a websocket in nature.

If you are on CDI, same approach naturally ;-)

VaadinSesssion is completely untyped, thus I’d prefer some actual Java field to store the reference.

UI class in Vaadin is essentially browser window. It doesn’t change if you navigate to different views (@Route annotated classes). But in your case that don’t help too much as with Vaadin 10+ it has not been feasible to override the UI class → UI scoped Spring/CDI bean has become the defacto place for browser window specific data.

A tiny hack to workaround missing DI framework (if you are on “plain servlet”): If you have a navigation/main layout in use, store the reference there. Then you can access it from all other components for example like this:

findAncestor(TopLayout.class).getClient().doSomething();

TopLayout would be your main layout class and getClient a public method there.

thanks the findAncestor sure looks nice, but i have 2 concerns with it, the api will tie me up the MainView, and i would repeating this call every time, and and it also ties me up to AppLayout pattern.

I’m aware VaadinSession is untyped that’s why i thought about doing this wrapper class
so eventually every class would just call AppSession.get().getClient that would abstract away the VaadinSession implementation.

public class AppSession {

    private static final AppSession APP_SESSION;

    static {
        APP_SESSION = new AppSession();
    }

    public static AppSession get() {
        return APP_SESSION;
    }

    public CommClient getCommClient() {
        final CommClient attribute = VaadinSession.getCurrent().getAttribute(CommClient.class);
        return attribute;
    }

    public void setCommClient(CommClient commClient) {
        VaadinSession.getCurrent().setAttribute(CommClient.class, commClient);
    }
}

can i use the RequestHandler to always check for each request if my client is there and otherwise always redirect it to a login form?
i know this is sort of authentication scheme, but since the actual authentication is done elsewhere i’m thinking about using it this way.

 event.addRequestHandler(new RequestHandler() {
            @Override
            public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException {
                final VaadinService service = response.getService();
                final UI ui = service.findUI(request);
                ui.navigate(LoginView.class);
                return false;
            }
        });

That AppSession looks like a solution that can work. It is just bit how you want to structure your UI code. If you (probably) have an abstract super class for your views, you could hide the findAncestor hack (or the VaadinSession usage) also there.

I don’t remember by heart if the UI is already available in handleRequest. I’d put that check into BeforeEnterListener/BeforeEnterObserver instead. Bit like the ViewAccessChecker is typically set up: Securing Plain Java Applications | Advanced Security Topics | Security | Vaadin Docs

thanks that NavigationAccessControl looked exactly what i needed, however it kept looking for principal which i didn’t have so i had to use the UIInitListener directly
the strange part is that i couldn’t exactly figure out why it was denying me, i could even looking into the source, because it kept saying that AnnotatedViewAccessChecker bytecode was different from the source code i downloaded using maven.

If you enable trace logging for “com.vaadin.flow.server.auth” it tells you everything about its decision making.

yes i’ve allready tried that, the thing is ArtifactView extends from an class which extends another abstract class which has PermitAll annotation, but it’s still can’t see it.
i’ve tried to walk though the hasAccess which returns false, and it returns in PermitAll,
but my evaluation give it true.

[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.NavigationAccessControl - Checking access for view org.example.ArtifactView
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.AnnotatedViewAccessChecker - Access to view 'org.example.ArtifactView' with path 'ArtifactView' is denied
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.DefaultAccessCheckDecisionResolver - Access to view 'org.example.ArtifactView' with path 'ArtifactView' denied by 1 out of 1 navigation checkers  (0 neutral).
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.NavigationAccessControl - Decision against 1 checker results: Access decision: DENY. Consider adding one of the following annotations to make the view accessible: @AnonymousAllowed, @PermitAll, @RolesAllowed.
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.NavigationAccessControl - Checking access for view com.vaadin.flow.router.RouteAccessDeniedError
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.AnnotatedViewAccessChecker - Access to view 'com.vaadin.flow.router.RouteAccessDeniedError' with path 'ArtifactView' is allowed
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.DefaultAccessCheckDecisionResolver - Access to view 'com.vaadin.flow.router.RouteAccessDeniedError' with path 'ArtifactView' allowed by 1 out of 1 navigation checkers  (0 neutral).
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.NavigationAccessControl - Decision against 1 checker results: Access decision: ALLOW
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.NavigationAccessControl - Checking access for view com.vaadin.flow.router.RouteNotFoundError
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.AnnotatedViewAccessChecker - Access to view 'com.vaadin.flow.router.RouteNotFoundError' with path 'ArtifactView' is allowed
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.DefaultAccessCheckDecisionResolver - Access to view 'com.vaadin.flow.router.RouteNotFoundError' with path 'ArtifactView' allowed by 1 out of 1 navigation checkers  (0 neutral).
[qtp2106959639-32] DEBUG com.vaadin.flow.server.auth.NavigationAccessControl - Decision against 1 checker results: Access decision: ALLOW
[qtp2106959639-32] DEBUG com.vaadin.flow.router.RouteNotFoundError - Consider adding one of the following annotations to make the view accessible: @AnonymousAllowed, @PermitAll, @RolesAllowed.
com.vaadin.flow.router.NotFoundException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at com.vaadin.flow.internal.ReflectTools.createProxyInstance(ReflectTools.java:484)

I doubt that this is supported because it could easily lead to a security problem. So the annotation should be on the real view / class

@marcoc_753 can probably correct me if I’m wrong here

I am not sure if I understood the problem, but PermitAll annotation means that the view is accessible by authenticated users; if you want a public view it should be annotated with AnonymousAllowed

@knoobie I was also eager to say that the security annotation are not inherited, but I found this paragraph on the docs Enabling Security | Security | Vaadin Docs.

I will check tomorrow if I’m wrong or if the docs are incorrect (most likely the first one :sweat_smile:)

1 Like

the original objective was to be automatically re-directed to a loginView if a url with any other view is entered and there was no authentication was peformed.
but as it seems, it doesn’t even think the view is annotated

I’m guessing on your login screen you submit credentials to the “Client” library and open the connection? If that is the case, and all your views require login, I think applying the role based security to your app is simply an overkill. You could just have a customized version of the ViewAccessChecker that only checks if the connection is open/authenticated or not.

Ok, of course I was wrong :grin:
The AccessAnnotationChecker component scans the view class hierarchy until it finds the first security annotation.
So, @PermitAll on a parent class should work as expected.

Just a reminder that ViewAccessChecker has been deprecated since 24.3. The replacement is AnnotatedViewAccessChecker that however is not meant to be extended; its intended hook is AccessAnnotationChecker.

I’m still missing who is performing the authentication, but if it is a custom logic invoked by the login view, I would maybe put something in the HttpSession and then have a servlet Filter that wraps the request to override getUserPrincipal(...) and isUserInRole(...) according to that attribute.

I didn’t mean to extend ViewAccessChecker we ship in our jar files, but to create something similar for this app.

Ah, ok. Now I understand your point.

If you didn’t get if my friend, maybe it wasn’t that trivial. Drafted a three class example here:

1 Like