Documentation

Documentation versions (currently viewingVaadin 23)
New Acceleration Kits: Observability Kit, SSO Kit, and Swing Kit. Read the blog post.

Configuring Servlet-Container Authentication

Configuring session-based and servlet container authentication.

Servlet containers have different mechanisms to create the user Principal object and run security checks when authentication is required for secured endpoints.

For reference, this page has configuration examples of custom session-based authentication with two popular containers.

Session-Based Authentication

Configuring a Custom Servlet Filter

For customized authentication, you need to implement a custom HttpServletRequest to wrap the default authentication using a WebFilter.

The following example contains a customized Principal object. It’s assumed that this principal is set as a Session attribute at some point by the application.

public class CustomPrincipal implements Principal {
    private final String name;
    private final List<String> roles;

    public CustomPrincipal(String name, String ...roles) {
        this.name = name;
        this.roles = Arrays.asList(roles);
    }

    public String getName() {
        return name;
    }

    public boolean isUserInRole(String role) {
        return roles.contains(role);
    }
}
public class CustomHttpServletRequest extends HttpServletRequestWrapper {
    public CustomHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    public Principal getUserPrincipal() {
        Principal myUser = (Principal) getSession().getAttribute("User");
        return myUser != null ? myUser : super.getUserPrincipal();
    }

    @Override
    public boolean isUserInRole(String role) {
        return getUserPrincipal() instanceof CustomPrincipal
                && ((CustomPrincipal) getUserPrincipal()).isUserInRole(role)
                || super.isUserInRole(role);
    }
}
@WebFilter("/connect")
public class CustomWebFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        chain.doFilter(new CustomHttpServletRequest((HttpServletRequest) request), response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void destroy() { }
}

Configuring a Client Log-in Form

Create a form to ask the user for a username/password pair and send it to the server side. The following snippet shows how to code a log-in web component.

import { html, LitElement } from 'lit';
import { customElement, query } from 'lit/decorators.js';

@customElement("my-login")
export class MyLogin extends LitElement {
  @query('#username')
  private username: any;
  @query('#password')
  private password: any;

  render() {
    return html`
      <input id="username" name="username" />
      <input id="password" name="password" type="password" />
      <button @click="${this.login}">login</button>
    `;
  }

  private login() {
    fetch('/connect/login', {
      method: 'POST',
      body: `username=${this.username.value}&password=${this.password.value}`
    })
    .then(() => console.log("User Logged-in"));
  }
}

Next, change the above filter to handle the request and set the appropriate principal object in the session.

@WebFilter("/connect")
public class CustomWebFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        // Check username/password and set the `User` attribute in session
        if ("foo".equals(request.getParameter("username")) &&
            "abc123".equals(request.getParameter("password"))) {
            ((HttpServletRequest) request).getSession()
                .setAttribute("User", new CustomPrincipal("foo"));
        }

        // wrap original request with our custom implementation
        chain.doFilter(new CustomHttpServletRequest((HttpServletRequest) request), response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }
    @Override
    public void destroy() { }
}

Configuring Servlet Container Authentication

The following sections show how to configure authentication in Jetty and Tomcat servers using the Basic HTTP authentication schema.

Note
Basic HTTP authentication is considered insecure. For public and production deployments, it’s recommended to use form-based mechanisms or client-side certificates. Most servlet containers can be configured to use these.

Configuring Jetty

test: password1,user
admin: password2,user,admin
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <Set name="contextPath">/connect</Set>
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/my-app</Set>

  <Get name="securityHandler">
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">my-app</Set>
        <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/jetty-users.properties</Set>
      </New>
    </Set>
  </Get>
</Configure>
Note
A 'realm' is a repository of user information. HashLoginService is a log-in service that loads usernames from a Java properties file, whereas JDBCLoginService can read users from a JDBC data source.

Configuring Tomcat

<tomcat-users>
  <role rolename="admin" />
  <role rolename="user" />
  <user name="test" password="password1" roles="user" />
  <user name="admin" password="password2" roles="user,admin" />
</tomcat-users>
<Context path="/connect">
  <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
         resourceName="UserDatabase" />
</Context>
Note
Change the realm implementation if you prefer to have a different user data source. The provided UserDatabaseRealm can get users from a JDBC database.

A0A3832E-663B-47A6-B108-78F36B608B77