Pertanyaan Filter otentikasi khusus Keamanan Musim Semi menggunakan Java Config


Saya mencoba mengkonfigurasi Spring Security menggunakan konfigurasi Java dalam aplikasi web dasar untuk mengotentikasi layanan web eksternal menggunakan token terenkripsi yang disediakan dalam parameter permintaan URL.

Saya ingin (saya pikir) untuk memiliki filter keamanan yang memotong permintaan dari Portal Login (semuanya masuk ke / mengotentikasi), filter akan menggunakan AuthenticationProvider untuk memproses logika bisnis dari proses otentikasi.

Login Portal -> Redirect '\ authenticate' (+ Token) -> Authenticate Token kembali ke Login Portal (WS) -> Jika sukses mendapatkan peran dan setup pengguna.

Saya telah membuat filter ..

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

Penyedia Autentikasi ...

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

Dan Spring Security Config saya

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

Masalah saya adalah konfigurasi filter di kelas SpringConfig saya. Saya ingin filter hanya berlaku ketika permintaan adalah untuk / mengotentikasi URL, saya telah menambahkan .antMatcher ("/ authenticate / **") ke konfigurasi filter.

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

Ketika saya memiliki baris ini di semua URL lainnya tidak lagi aman, saya dapat menavigasi ke / rumah secara manual tanpa mengautentikasi, menghapus baris dan / home diotentikasi.

Haruskah saya mendeklarasikan filter yang hanya berlaku untuk URL tertentu?

Bagaimana saya bisa menerapkan ini sambil menjaga keamanan URL lainnya?


32
2017-12-16 15:18


asal


Jawaban:


Saya telah menyelesaikan masalah saya dengan melakukan pemeriksaan pada status otentikasi di filter sebelum melibatkan penyedia otentikasi ....

Config

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

Menyaring

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

14
2017-12-19 10:44