5.5.9.3. Web Login
This section describes how the web client authentication works and how to extend it in your project. For information about authentication on the middle tier, see Login.
Implementation of the login procedure of the Web Client block has the following mechanisms:
-
Connectionimplemented byConnectionImpl. -
LoginProviderimplementations. -
HttpRequestFilterimplementations.
The main interface of Web login subsystem is Connection which contains the following key methods:
-
login() - authenticates a user, starts a session and changes the state of the connection.
-
logout() - log out of the system.
-
substituteUser() - substitute a user in the current session with another user. This method creates a new UserSession instance, but with the same session ID.
-
getSession() - get the current user session.
After successful login, Connection sets UserSession object to the attribute of VaadinSession and sets SecurityContext. The Connection object is bound to VaadinSession thus it cannot be used from non-UI threads, it throws IllegalConcurrentAccessException in case of login/logout call from a non UI thread.
Usually, login is performed from the AppLoginWindow screen that supports login with login/password and "remember me" credentials.
The default implementation of Connection is ConnectionImpl, which delegates login to a chain of LoginProvider instances. A LoginProvider is a login module that can process a specific Credentials implementation, also it has a special supports() method to allow the caller to query if it supports a given Credentials type.
Standard user login process:
-
Users enter their username and password.
-
Web client block creates a
LoginPasswordCredentialsobject passing the login and password to its constructor and invokesConnection.login()method with this credentials. -
Connectionuses chain ofLoginProviderobjects. There isLoginPasswordLoginProviderthat works withLoginPasswordCredentialsinstances. It hashes the password using thegetPlainHash()method ofPasswordEncryptionbean and invokesAuthenticationService.login(Credentials). -
If the authentication is successful, the created
AuthenticationDetailsinstance with the active UserSession is passed back toConnection. -
Connectioncreates aClientUserSessionwrapper and sets it toVaadinSession. -
Connectioncreates aSecurityContextinstance and sets it toAppContext. -
ConnectionfiresStateChangeEventthat triggers UI update and leads to theAppMainWindowinitialization.
All LoginProvider implementations must:
-
Authenticate user using
Credentialsobject. -
Start a new user session with
AuthenticationServiceor return another active session (for instance, anonymous). -
Return authentication details or null if it cannot login user with this
Credentialsobject, for instance, if the login provider is disabled or is not properly configured. -
Throw
LoginExceptionin case of incorrectCredentialsor passLoginExceptionfrom the middleware to the caller.
HttpRequestFilter - marker interface for beans that will be automatically added to the application filter chain as HTTP filter: https://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html. You can use it to implement additional authentication, pre- and post-processing of request and response.
You can expose additional Filter if you create Spring Framework component and implement HttpRequestFilter interface:
@Component
public class CustomHttpFilter implements HttpRequestFilter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// delegate to the next filter/servlet
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
Please note that the minimal implementation has to delegate execution to FilterChain otherwise your application will not work. By default, filters added as HttpRequestFilter beans will not receive requests to VAADIN directory and other paths specified in cuba.web.cubaHttpFilterBypassUrls app property.
- Built-in login providers
-
The platform contains the following implementations of
LoginProviderinterface:-
AnonymousLoginProvider- provides anonymous login for non-logged-in users. -
LoginPasswordLoginProvider- delegates login toAuthenticationServicewithLoginPasswordCredentials. -
RememberMeLoginProvider- delegates login toAuthenticationServicewithRememberMeCredentials. -
LdapLoginProvider- performs authentication using LDAP and logs in users withExternalUserCredentials. -
ExternalUserLoginProvider- can be used from event handlers to perform login as provided user name.
All the implementations create an active user session using
AuthenticationService.login().You can override any of them using Spring Framework mechanisms.
-
- Events
-
Standard implementation of
Connection-ConnectionImplfires the following application events during login procedure:-
BeforeLoginEvent/AfterLoginEvent -
LoginFailureEvent -
UserConnectedEvent/UserDisconnectedEvent -
UserSessionStartedEvent/UserSessionFinishedEvent -
UserSessionSubstitutedEvent
Event handlers of
BeforeLoginEventandLoginFailureEventmay throwLoginExceptionto cancel login process or override the original login failure exception.For instance, you can permit login to Web Client only for users with login that includes a company domain using
BeforeLoginEvent.@Component public class BeforeLoginEventListener { @Order(10) @EventListener protected void onBeforeLogin(BeforeLoginEvent event) throws LoginException { if (event.getCredentials() instanceof LoginPasswordCredentials) { LoginPasswordCredentials loginPassword = (LoginPasswordCredentials) event.getCredentials(); if (loginPassword.getLogin() != null && !loginPassword.getLogin().contains("@company")) { throw new LoginException( "Only users from @company are allowed to login"); } } } }Additionally, the standard application class -
DefaultAppfires the following events:-
AppInitializedEvent- fired afterAppinitialization, performed once per HTTP session. -
AppStartedEvent- fired on the first request processing of anAppright before login as anonymous user. Event handlers may login the user using theConnectionobject bound toApp. -
AppLoggedInEvent- fired after UI initialization ofAppwhen a user is logged in. -
AppLoggedOutEvent- fired after UI initialization ofAppwhen a user is logged out. -
SessionHeartbeatEvent- fired on heartbeat requests from a client web browser.
AppStartedEventcan be used to implement SSO login with third-party authentication system, for instance Jasig CAS. Usually, it is used together with a customHttpRequestFilterbean that should collect and provide additional authentication data.Let’s assume that we will automatically log in users if they have a special cookie value -
PROMO_USER.@Order(10) @Component public class AppStartedEventListener implements ApplicationListener<AppStartedEvent> { private static final String PROMO_USER_COOKIE = "PROMO_USER"; @Inject private Logger log; @Override public void onApplicationEvent(AppStartedEvent event) { String promoUserLogin = event.getApp().getCookieValue(PROMO_USER_COOKIE); if (promoUserLogin != null) { Connection connection = event.getApp().getConnection(); if (!connection.isAuthenticated()) { try { connection.login(new ExternalUserCredentials(promoUserLogin)); } catch (LoginException e) { log.warn("Unable to login promo user {}: {}", promoUserLogin, e.getMessage()); } finally { event.getApp().removeCookie(PROMO_USER_COOKIE); } } } } }Thus if users have "PROMO_USER" cookie and open the application, they will be automatically logged in as
promoUserLogin.If you want to perform additional actions after login and UI initialization you could use
AppLoggedInEvent. Keep in mind that you have to check if a user is authenticated or not in event handlers, all the events are fired foranonymoususer as well. -
- Extension points
-
You can extend login mechanisms using the following types of extension points:
-
Connection- replace existingConnectionImpl. -
HttpRequestFilter- implement additionalHttpRequestFilter. -
LoginProviderimplementations - implement additional or replace existingLoginProvider. -
Events - implement event handler for one of the available events.
You can replace existing beans using Spring Framework mechanisms, for instance by registering a new bean in Spring XML config of the web module.
<bean id="cuba_LoginPasswordLoginProvider" class="com.company.demo.web.CustomLoginProvider"/> -
- Obsolete/Deprecated
-
Custom implementation of the
CubaAuthProviderinterface can be enabled by setting the following application properties:cuba.web.externalAuthentication = true cuba.web.externalAuthenticationProviderClass = com.company.sample.web.MyAuthProviderThe following components are now deprecated:
-
CubaAuthProviderand its implementations are available in compatibility mode. Use events,LoginProviderandHttpRequestFilterinstead. -
LdapAuthProviderhas been replaced withLdapLoginProviderthat can be enabled as described here: LDAP integration -
IdpAuthProviderhas been replaced withIdpLoginProviderthat can be enabled as described here: IDP SSO
Do not use these components. They will be removed in the next major version of the platform.
Use Web login extension points instead.
-