Skip to content

joanluk/ldapauthenticationcache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status

API Rest con seguridad básica contra LDAP y caché

Spring Security ofrece varios proveedores de seguridad (LDAP, Base de datos, etc). En alguno de ellos ofrece un mecanismo de caché que permite guardar en una caché interna y durante un período de tiempo pequeño, usuarios y roles con el objetivo de mejorar el rendimiento en las ejecuciones.

Esta mejora es útil para servicios REST, los cuales deben ser por normal stateless. En aplicaciones web con mecanismos de sesión, el usuario logado se guarda en dicha sesión por lo que las ejecuciones suscesivas no es necesario volver a consultar.

Sin embargo, en ejecuciones de API´s sin estado, puede llegar a ser un problema si el acceso al repositorio con la información del usuario y roles penaliza.

Como indicaba, Spring Security para algunos provider ofrece mecanismo de caché. Por ejemplo para el DAOAuthenticationProvider se ofrece la posibilidad de definir un elemento cacheUser

	public abstract class AbstractUserDetailsAuthenticationProvider implements
			AuthenticationProvider, InitializingBean, MessageSourceAware {

		protected final Log logger = LogFactory.getLog(getClass());

		// ~ Instance fields
		// ================================================================================================
		protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
		private UserCache userCache = new NullUserCache();
		private boolean forcePrincipalAsString = false;
		protected boolean hideUserNotFoundExceptions = true;
		private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
		private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();
		private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();

Sin embargo, para el acceso a LDAP no se ofrece esta posibilidad. Es por ello que este ejemplo trata de incluir un posible implementación de un provider basado en LDAPAuthenticationProvider que permite cachear usuarios y roles.

La clase que se ha creado es CachingLdapAuthenticationProvider

//tag::code[]
@Slf4j
@Setter
public class CachingLdapAuthenticationProvider extends LdapAuthenticationProvider {

    private UserCache userCache = new NullUserCache();

    /**
     * Create an instance with the supplied authenticator and authorities populator
     * implementations.
     *
     * @param authenticator        the authentication strategy (bind, password comparison, etc)
     *                             to be used by this provider for authenticating users.
     * @param authoritiesPopulator the strategy for obtaining the authorities for a given
     */
    public CachingLdapAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) {
        super(authenticator, authoritiesPopulator);
    }

    public CachingLdapAuthenticationProvider(LdapAuthenticator authenticator) {
        super(authenticator);
    }


    @Override
    public Authentication authenticate(Authentication authentication)  {
        String userName = authentication.getName();
        UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication;
        UserDetails userDetailsFromCache = userCache.getUserFromCache(userName);
        if (userDetailsFromCache != null) {
            additionalAuthenticationChecks(userDetailsFromCache, userToken);
            return createSuccessfulAuthentication(userToken, userDetailsFromCache);
        } else {
            Authentication authenticationFromProvider = super.authenticate(authentication);
            userCache.putUserInCache((UserDetails)authenticationFromProvider.getPrincipal());
            return authenticationFromProvider;
        }

    }

    protected void additionalAuthenticationChecks(UserDetails userDetails,
                                                  UsernamePasswordAuthenticationToken authentication) {
        if (StringUtils.isEmpty(authentication.getCredentials())) {
            logger.debug("Authentication failed: no credentials provided");

            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
        String presentedPassword = authentication.getCredentials().toString();
        if (!StringUtils.isEmpty(userDetails.getPassword()) && (!presentedPassword.equals(userDetails.getPassword()))) {
            log.debug("Authentication failed: password does not match stored value");
            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
    }


}

Releases

No releases published

Packages

No packages published

Languages