Dropping Domino’s HTTP task (3): WebSSO Integration (Part 1)

To integrate the new HTTP stack into the existing environment, we can use LTPA tokens. These tokens are cookies which store the authentication information and allow to share them betweeen different participating Domino servers. A users must log on only once, and existing applications and data/views can be accessed without a relogin.

Validating an existing LTPA token with Spring can be done with our own PreAuthentificationFilter which checks for an existing LTPA token and extracts the authentication details from the cookie and creates a new Principal instance.


import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

public class LtpaPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter {

   @Value("${ltpa.secret}")
   private String ltpaSecret;

   @Value("${ltpa.cookieName}")
   private String ltpaCookieName;

   @Override
   protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {

      Cookie[] cookies = request.getCookies();
      if( cookies == null ) {
         return null;
      }

      for( int i= 0; i<cookies.length ; i++ ){
         String name = cookies[i].getName();
         String value = cookies[i].getValue();

         if( ltpaCookieName.equalsIgnoreCase(name) ){
            DominoLtpaToken ltpaToken = new DominoLtpaToken( value, ltpaSecret );

            if( ltpaToken.isValid() ){
               return ltpaToken.getDistinguishedName();
            }
         }
      }

      return null;
   }

   @Override
   protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
      // is required to return an empty string
      return "";
   }

}

The filter implements two methods, one for extraction of the principal, and the other for the credentials (which we don’t have with LTPA tokens). In the getPreAuthenticatedPrincipal method, existinig LTPA tokens are searched, then the user extracted and the token validated.

The secret of the LTPA token and the name are stored in application.properties:

The second part is implementing a AuthenticationUserDetailsService. This service is for getting additional details for the authenticated user, for example the ACL roles or groups the user belongs to.

import java.util.Collection;
import java.util.HashSet;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

public class LtpaUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

   @Override
   public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
      throws UsernameNotFoundException {

      String userName=(String)token.getPrincipal();

      Collection<GrantedAuthority> authorities = new HashSet<GrantedAuthority>() ;
      authorities.add(new LtpaUserAuthority());

      User user = new User(userName,"",authorities);

      return user;
    }

}

In our case, we are just adding an LtpaUserAuthority to the user information. Don’t worry about the usage of the LtpaUserAuthority. We come back to this in another post.

import org.springframework.security.core.GrantedAuthority;

public class LtpaUserAuthority implements GrantedAuthority {

   private static final long serialVersionUID = 1L;

   @Override
   public String getAuthority() {
      return "ROLE_USER_LTPA";
   }

}

In the last step we have to update the SecurityConfig.java to activate the filter:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Configuration
   @Order(1)
   static class DominoLtpaSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

      @Bean
      public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService() {
         return new LtpaUserDetailsService();
      }

      @Bean
      public PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() {
         PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();

         provider.setPreAuthenticatedUserDetailsService(authenticationUserDetailsService());
         provider.setUserDetailsChecker(new AccountStatusUserDetailsChecker());

         return provider;
      }

      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
      }

      @Bean
      public AbstractPreAuthenticatedProcessingFilter preAuthenticatedProcessingFilter() throws Exception {
         LtpaPreAuthenticatedFilter filter = new LtpaPreAuthenticatedFilter();
         filter.setAuthenticationManager(authenticationManager());
         return filter;
      }

      @Override
      protected void configure(HttpSecurity http) throws Exception {
         http.addFilter(preAuthenticatedProcessingFilter())
         .authorizeRequests()
         .antMatchers("/**").permitAll() ;
      }
   }
  ...
}

This includes the filter in any request. Now, the Principal contains the user name stored in the LTPA token.

Dieser Beitrag wurde unter Java, Server, Web abgelegt und mit , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.