2014-12-16 26 views
27

Ich versuche Spring Security mit Java-Konfiguration in einer grundlegenden Webanwendung zur Authentifizierung gegen einen externen Webdienst mit einem verschlüsselten Token in einem URL-Anfrageparameter zu konfigurieren.Spring Security benutzerdefinierten Authentifizierungsfilter mit Java Config

Ich möchte (glaube ich) einen Sicherheitsfilter haben, der Anfragen vom Login-Portal abfängt (sie alle gehen nach/authenticate), der Filter verwendet einen AuthenticationProvider, um die Geschäftslogik des Authentifizierungsprozesses zu verarbeiten.

Login Portal -> Redirect '\ authenticate' (+ Token) -> Token authentifizieren zurück zum Login Portal (WS) -> Wenn Erfolg Rollen und Setup-Benutzer erhalten.

ich einen Filter erstellt haben ..

@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); 
} 

Ein 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"); 
     } 
    } 

Und meine Spring Security 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()); 
    } 
} 

Mein Problem ist die Konfiguration des Filters in meiner SpringConfig-Klasse. Ich möchte, dass der Filter nur dann wirksam wird, wenn die Anfrage die URL/authenticate betrifft. Ich habe .antMatcher ("/ authenticate/**") zur Filterkonfiguration hinzugefügt.

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

Wenn ich diese Zeile in allen anderen URLs sind nicht mehr gesichert ist, kann ich manuell/home navigieren ohne Authentifizierung, entfernen Sie die Zeile und/home authentifiziert wird.

Sollte ich einen Filter deklarieren, der nur für eine bestimmte URL gilt?

Wie kann ich dies unter Beibehaltung der Sicherheit anderer URLs implementieren?

+0

Dank für die Question. :) Hilft! – raj

Antwort

12

ich mein Problem gelöst haben, indem eine Überprüfung der Authentifizierungsstatus in den Filter durchführen, bevor involking den Authentifizierungs-Provider ....

Config

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

Filter

@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

Können Sie den Code dieser Klassen veröffentlichen: 'OEWebToken',' AuthenticatedAccount' und 'extractToken (request)' Methodenimplementierung? Ich würde mir mit meinem Rastservice sehr helfen. Danke im Voraus. – masterdany88

Verwandte Themen