2014-12-16 17 views
27

Sto provando a configurare Spring Security utilizzando la configurazione Java in un'applicazione Web di base per l'autenticazione con un servizio Web esterno utilizzando un token crittografato fornito in un parametro di richiesta URL.Filtro di autenticazione personalizzata Spring Security mediante Java Config

Mi piacerebbe (credo) di avere un filtro di sicurezza che intercetta le richieste dal portale di accesso (tutte vanno a/autenticarsi), il filtro utilizzerà un AuthenticationProvider per elaborare la logica di bussiness del processo di autenticazione.

Portale di accesso -> Reindirizza "\ authenticate" (+ token) -> Autentica token di accesso al portale di accesso (WS) -> Se il successo ottiene ruoli e imposta utente.

ho creato un filtro ..

@Component 
public final class OEWebTokenFilter extends GenericFilterBean { 
    @Override 
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { 
     if (request instanceof HttpServletRequest) { 
      OEToken token = extractToken(request); 
      // dump token into security context (for authentication-provider to pick up) 
      SecurityContextHolder.getContext().setAuthentication(token); 
     } 
    } 
    chain.doFilter(request, response); 
} 

Un AuthenticationProvider ...

@Component 
public final class OEWebTokenAuthenticationProvider implements AuthenticationProvider { 
    @Autowired 
    private WebTokenService webTokenService; 

    @Override 
    public boolean supports(final Class<?> authentication) { 
     return OEWebToken.class.isAssignableFrom(authentication); 
    } 

    @Override 
    public Authentication authenticate(final Authentication authentication) { 
     if (!(authentication instanceof OEWebToken)) { 
      throw new AuthenticationServiceException("expecting a OEWebToken, got " + authentication); 
     } 

     try { 
      // validate token locally 
      OEWebToken token = (OEWebToken) authentication; 
      checkAccessToken(token); 

      // validate token remotely 
      webTokenService.validateToken(token); 

      // obtain user info from the token 
      User userFromToken = webTokenService.obtainUserInfo(token); 

      // obtain the user from the db 
      User userFromDB = userDao.findByUserName(userFromToken.getUsername()); 

      // validate the user status 
      checkUserStatus(userFromDB); 

      // update ncss db with values from OE 
      updateUserInDb(userFromToken, userFromDB); 

      // determine access rights 
      List<GrantedAuthority> roles = determineRoles(userFromDB); 

      // put account into security context (for controllers to use) 
      return new AuthenticatedAccount(userFromDB, roles); 
     } catch (AuthenticationException e) { 
      throw e; 
     } catch (Exception e) { 
      // stop non-AuthenticationExceptions. otherwise full stacktraces returned to the requester 
      throw new AuthenticationServiceException("Internal error occurred"); 
     } 
    } 

E la mia sicurezza Primavera Config

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    OESettings oeSettings; 

    @Bean(name="oeAuthenticationService") 
    public AuthenticationService oeAuthenticationService() throws AuthenticationServiceException { 
     return new AuthenticationServiceImpl(new OEAuthenticationServiceImpl(), oeSettings.getAuthenticateUrl(), oeSettings.getApplicationKey()); 
    } 

    @Autowired 
    private OEWebTokenFilter tokenFilter; 

    @Autowired 
    private OEWebTokenAuthenticationProvider tokenAuthenticationProvider; 

    @Autowired 
    private OEWebTokenEntryPoint tokenEntryPoint; 

    @Bean(name="authenticationManager") 
    @Override 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 

    @Override 
    public void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(tokenAuthenticationProvider); 
    } 

    @Bean 
    public FilterRegistrationBean filterRegistrationBean() { 
     FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
     registrationBean.setFilter(tokenFilter);  
     registrationBean.setEnabled(false); 
     return registrationBean; 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.csrf().disable() 
      .authorizeRequests() 
      .antMatchers("/authenticate**").permitAll() 
      .antMatchers("/resources/**").hasAuthority("ROLE_USER") 
      .antMatchers("/home**").hasAuthority("ROLE_USER") 
      .antMatchers("/personSearch**").hasAuthority("ROLE_ADMIN") 
      // Spring Boot actuator endpoints 
      .antMatchers("/autoconfig**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/beans**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/configprops**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/dump**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/env**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/health**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/info**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/mappings**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/metrics**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/trace**").hasAuthority("ROLE_ADMIN") 
      .and() 
       .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) 
       .authenticationProvider(tokenAuthenticationProvider) 
       .antMatcher("/authenticate/**") 
       .exceptionHandling().authenticationEntryPoint(tokenEntryPoint) 
      .and() 
       .logout().logoutSuccessUrl(oeSettings.getUrl()); 
    } 
} 

Il mio problema è la configurazione del filtro nella mia classe SpringConfig. Voglio che il filtro entri in vigore solo quando la richiesta è per l'URL/authenticate, ho aggiunto .antMatcher ("/ authenticate/**") alla configurazione del filtro.

.and() 
       .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) 
       .authenticationProvider(tokenAuthenticationProvider) 
       .antMatcher("/authenticate/**") 
       .exceptionHandling().authenticationEntryPoint(tokenEntryPoint) 

Quando ho questa linea in tutti gli altri URL non sono fissati, posso passare manualmente/casa senza autenticazione, rimuovere la riga e/home è autenticato.

Devo dichiarare un filtro applicabile solo a un URL specifico?

Come posso implementarlo mantenendo la sicurezza di altri URL?

+0

Grazie per la domanda. :) Aiuta! – raj

risposta

12

ho risolto il mio problema grazie all'esecuzione di una verifica sullo stato di autenticazione nel filtro prima involking il provider di autenticazione ....

Config

.and() 
    .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) 
    .authenticationProvider(tokenAuthenticationProvider) 
    .exceptionHandling().authenticationEntryPoint(tokenEntryPoint) 

Filtro

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

    logger.debug(this + "received authentication request from " + request.getRemoteHost() + " to " + request.getLocalName()); 

    if (request instanceof HttpServletRequest) { 
     if (isAuthenticationRequired()) { 
      // extract token from header 
      OEWebToken token = extractToken(request); 

      // dump token into security context (for authentication-provider to pick up) 
      SecurityContextHolder.getContext().setAuthentication(token); 
     } else { 
      logger.debug("session already contained valid Authentication - not checking again"); 
     } 
    } 

    chain.doFilter(request, response); 
} 

    private boolean isAuthenticationRequired() { 
    // apparently filters have to check this themselves. So make sure they have a proper AuthenticatedAccount in their session. 
    Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); 
    if ((existingAuth == null) || !existingAuth.isAuthenticated()) { 
     return true; 
    } 

    if (!(existingAuth instanceof AuthenticatedAccount)) { 
     return true; 
    } 

    // current session already authenticated 
    return false; 
} 
+4

Puoi pubblicare il codice di quelle classi: implementazione 'OEWebToken',' AuthenticatedAccount' e 'extractToken (request)'? Mi aiuterebbe molto con il mio servizio di riposo. Grazie in anticipo. – masterdany88

Problemi correlati