Hi,
I am trying to use the authentication by URL mechanism as described in the https://github.com/cuba-labs/authentication-by-url and I’ve noticed the following (I am using the first approach that is described in the sample application)
When any user -the first time- tries to login into the application using a url that includes an appropriate token, then everything is working as expected. Now, if the same user tries to connect from his browser changing the token in the url in order to login as a different user -he can use either the same open browser window or create a new tab), then it is logged in as the old user! It seems that the CUBA application ignores the new URL, using instead the available session. So, I would like to ask you if we could somehow invalidate the current session in the provided first sample to allow users login any time with the current URL token. If not, we could somehow create a logout link to the application? Although this type of link seems not be provided by the CUBA framework I’ve found some instructions on the Forum describing a way to make a similar operation but I’ve found all of the them very advanced - Is there an easy way or a ready-to-use sample code to bypass the aforementioned problem?
Since you have logged in the application from your browser, the link with navigation params will not work because CubaLoginScreenFilter will proceed without opening the Login screen. For the appropriate work, you need to log out, before handling the link with another token.
I can suggest you to use NavigationFilter (see documentation). It checks access for the given route and here we can process our navigation params.
In the filter, we should check that we are navigating to the login screen and then check the secret token and user.
Example:
@Override
public AccessCheckResult allowed(NavigationState fromState, NavigationState toState) {
String loginWindowRoute = windowConfig.findRoute("loginWindow");
if (Objects.equals(loginWindowRoute, toState.getRoot())) {
// check if current connection is authenticated
Connection connection = App.getInstance().getConnection();
if (connection.isAuthenticated()) {
// get secret token from params
Map<String, String> params = toState.getParams();
String st = params.get("st");
User user = connection.getSessionNN().getUser();
// if current user is auth, but ST does not correspond to the user do logout
if (!isSecretTokenForUser(user, st)) {
connection.logout();
}
}
}
return AccessCheckResult.allowed();
}
I slightly changed demo: logindemo.zip (89.2 KB)
Use the following links to check:
localhost:8080/app/#login?st=e63cacd4-646b-4232-bd72-36ddff780bbf // admin
localhost:8080/app/#login?st=93de5933-4aed-4ad7-bfac-97a0ec802352 // test
Hi,
I would like to thank you for your reply.It’s working now! I just have one question - based on the current implementation, when the second user tries to login, the initial user is logged out and the login screen is displayed. In this case, when the second user tries to login, is it possible for the system to automatically logout the first user and login the second one? Basically, we need to integrate our CUBA application with a third-party system using an iframe - Both systems share the same users and we need a transparent integration between these two systems…
When we enter a link for the second user in NavigationFilter we log out the first user. Then the application tries to open the Login screen, but in onAfterShow() we handle token and immediately do log in.
Could you clarify steps to reproduce when the second user tries to log in and the Login screen is displayed? Or if it is possible to share a small demo project where it can be reproduced?
I tried to open an application in BrowserFrame (iframe) and change the URL on button click, but there is no Login screen is shown.
On the same browser, I add a new tab and enter the url for the second user:
localhost:8080/app/#login?st=93de5933-4aed-4ad7-bfac-97a0ec802352
In this case, I get the login screen - What I am expecting is the second user to login automatically.
Debugging the application, I’ve noticed that in the following code at step(2) the value of state.getParams().get(“st”) is always null (see attached image)! Am I missing something?
@Subscribe
public void onAfterShow(AfterShowEvent event) {
String st = state.getParams().get("st");
if (stMap.containsKey(st)) {
doLogin(new ExternalUserCredentials(stMap.get(st)));
}
}
I reproduced this case. It seems when we try to use a link from another tab navigation state is missed when we do log out.
With this case, we can try process login/logout in the NavigationFilter.
@Override
public AccessCheckResult allowed(NavigationState fromState, NavigationState toState) {
String loginWindowRoute = windowConfig.findRoute("loginWindow");
if (Objects.equals(loginWindowRoute, toState.getRoot())) {
// get secret token from params
Map<String, String> params = toState.getParams();
String st = params.get("st");
// check if current connection is authenticated
Connection connection = App.getInstance().getConnection();
if (connection.isAuthenticated()) {
User user = connection.getSessionNN().getUser();
// if current user is auth, but ST does not correspond to the user do logout
if (!isSecretTokenForUser(user, st)) {
connection.logout();
// check if url was entered in another browser tab
if (!connection.isAuthenticated()) {
connection.login(new ExternalUserCredentials(stMap.get(st)));
}
}
}
return AccessCheckResult.rejected();
}
return AccessCheckResult.allowed();
}
Upd. notice, that if we enter URL on the same tab, user will be logged in twice. So code above was changed, now it should handle all cases.