How to implement my own FilterSecurityInterceptor filter using grails 1.3.2 and spring-security-core 1 plugin?

I am writing a grails 1.3.2 application and implement security using spring-security-core 1.0. For reasons that are beyond the scope of this question, I implement my own FilterSecurityInterceptor filter in addition to interceptors out of the box. I started by blogging on this topic and tried to set it up for Spring Security 3 without much success.

Right after the blog (as it is based on an older version of Spring Security), I created the following classes:

  • A org.springframework.security.authentication.AbstractAuthenticationToken subclass to store my credentials.
  • A subgroup of org.springframework.security.authentication.AuthenticationProvider for implementing authentication and supports methods for populating an authentication instance with data from my UserDetailsService.
  • Subgroup org.springframework.security.web.access.intercept.FilterSecurityInterceptor for implementing the doFilter and afterPropertiesSet methods.
  • Some configuration of beans and the spring-security-core plugin to recognize my AuthenticationProvider and insert my filter into the filter chain.

My AbstractAuthenticationToken is pretty simple:

class InterchangeAuthenticationToken extends AbstractAuthenticationToken {
 String credentials
 Integer name
 Integer principal

 String getCredentials() { //necessary or I get compilation error
  return credentials
 }

 Integer getPrincipal() { //necessary or I get compilation error
  return principal
 }
}

My AuthenticationProvider is pretty simple:

class InterchangeAuthenticationProvider implements org.springframework.security.authentication.AuthenticationProvider {

 Authentication authenticate(Authentication customAuth) {
  def authUser = AuthUser.get(customAuth.principal)
  if (authUser) {
   customAuth.setAuthorities(authUser.getAuthorities())
   customAuth.setAuthenticated(true)
   return customAuth
  } else {
   return null
  }
 }

 boolean supports(Class authentication) {
  return InterchangeAuthenticationToken.class.isAssignableFrom(authentication)
 }

}

I implemented the trivial FilterSecurityInterceptor filter. In the end, it will do something interesting:

class InterchangeFilterSecurityInterceptor extends FilterSecurityInterceptor implements InitializingBean {

 def authenticationManager
 def interchangeAuthenticationProvider
 def securityMetadataSource

 void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {

  if (SecurityContextHolder.getContext().getAuthentication() == null) {
    def myAuth = new InterchangeAuthenticationToken()
    myAuth.setName(1680892)
    myAuth.setCredentials('SDYLWUYa:nobody::27858cff')
    myAuth.setPrincipal(1680892)
    myAuth = authenticationManager.authenticate(myAuth);
    if (myAuth) {
     println "Successfully Authenticated ${userId} in object ${myAuth}"

     // Store to SecurityContextHolder
     SecurityContextHolder.getContext().setAuthentication(myAuth);
     }    
  }
  chain.doFilter(request, response)
 }

 void afterPropertiesSet() {
  def providers = authenticationManager.providers
  providers.add(interchangeAuthenticationProvider)
  authenticationManager.providers = providers
 }
}           

Finally, I'll configure some beans:

beans = {
  interchangeAuthenticationProvider(com.bc.commerce.core.InterchangeAuthenticationProvider) {
  }
  interchangeFilterSecurityInterceptor(com.bc.commerce.core.InterchangeFilterSecurityInterceptor) {
    authenticationManager = ref('authenticationManager')
    interchangeAuthenticationProvider = ref('interchangeAuthenticationProvider')
    securityMetadataSource = ref('objectDefinitionSource')
  }
}

And do some plugin configuration:

grails.plugins.springsecurity.dao.hideUserNotFoundExceptions = true //not setting this causes exception
grails.plugins.springsecurity.providerNames = [
'interchangeAuthenticationProvider',
'daoAuthenticationProvider',
'anonymousAuthenticationProvider',
'rememberMeAuthenticationProvider'
]

And set the filtering order in Bootstrap.groovy:

def init = {servletContext ->
  //insert our custom filter just after the filter security interceptor
  SpringSecurityUtils.clientRegisterFilter('interchangeFilterSecurityInterceptor', SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)
  <snip />
}

URL-, , :

2010-07-30 15:07:16,763 [http-8080-1] ERROR [/community-services].[default]  - Servlet.service() for servlet default threw exception
java.lang.NullPointerException
 at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:171)
 at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:106)
 at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
 at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:112)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
 at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
 at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
 at org.codehaus.groovy.grails.plugins.springsecurity.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:40)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
 at org.codehaus.groovy.grails.plugins.springsecurity.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:79)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
 at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
 at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
 at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
 at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:104)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:67)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:66)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
 at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
 at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
 at java.lang.Thread.run(Thread.java:637)

, , , - ?

+3
3

, , FilterSecurityInterceptor. OOTB rememberMe. , , , , cookie cookie cookie . , .

:

import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.ServletException
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import org.springframework.context.ApplicationEventPublisher
import org.springframework.context.ApplicationEventPublisherAware
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.filter.GenericFilterBean

class CustomRememberMeAuthenticationFilter extends GenericFilterBean implements ApplicationEventPublisherAware {

    def authenticationManager
    def eventPublisher
    def customService
    def rememberMeServices
    def springSecurityService

    //make certain that we've specified our beans
    void afterPropertiesSet() {
        assert authenticationManager != null, 'authenticationManager must be specified'
        assert customService != null, 'customService must be specified'
        assert rememberMeServices != null, 'rememberMeServices must be specified'
    }

    void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req
        HttpServletResponse response = (HttpServletResponse) res

        if (SecurityContextHolder.getContext().getAuthentication() == null) {           
            Authentication auth
            try {
                auth = customService.getUsernamePasswordAuthenticationToken(request)
                if (auth != null) {
                    springSecurityService.reauthenticate(auth.getPrincipal(), auth.getCredentials())
                    logger.debug("SecurityContextHolder populated with auth: '"
                        + SecurityContextHolder.getContext().getAuthentication() + "'")
                    onSuccessfulAuthentication(request, response, SecurityContextHolder.getContext().getAuthentication())
                } else {
                    logger.debug('customService did not return an authentication from the request')
                }
            } catch (AuthenticationException authenticationException) {
                logger.warn("SecurityContextHolder not populated with auth, as "
                    + "springSecurityService rejected Authentication returned by customService: '"
                    + auth + "'", authenticationException)
                onUnsuccessfulAuthentication(request, response, auth)
            } catch(e) {
                logger.warn("Unsuccessful authentication in customRememberMeAuthenticationFilter", e)
                onUnsuccessfulAuthentication(request, response, auth)
            }
        } else {
            logger.debug("SecurityContextHolder not populated with auth, as it already contained: '"
                + SecurityContextHolder.getContext().getAuthentication() + "'")
        }
        chain.doFilter(request, response)
    }

    protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
        //sets the rememberMe cookie, but cannot call "loginSuccess" because that filters out requests
        //that don't set the rememberMe cookie, like this one
        rememberMeServices.onLoginSuccess(request, response, authResult)
    }

    protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
        //clear the rememberMe cookie
        rememberMeServices.loginFail(request, response)
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher
    }
}

, . , .

+3

, ( ), , .

grails.plugins.springsecurity.dao.hideUserNotFoundExceptions = true
grails.plugins.springsecurity.providerNames = [
    'interchangeAuthenticationProvider',
    'daoAuthenticationProvider',
    'anonymousAuthenticationProvider',
    'rememberMeAuthenticationProvider'
]

, (quirk Grails/ConfigSlurper) . "active = true", , , reset.

btw - InterchangeAuthenticationToken, .

+1

This seems to be a bug in the spring-security-core plugin because it is securityMetadataSourcenot entered in> FilterSecurityInterceptorby default. Perhaps the plugin got confused and entered securityMetadataSourceinto your user FilterSecurityInterceptorand neglects the other (by default)? Burt may want to read deeper information.

Perhaps you could try replacing the standard FilterSecurityInterceptorwith your own using the property grails.plugins.springsecurity.filterNames...

+1
source

Source: https://habr.com/ru/post/1757749/


All Articles