Skip to content

Commit

Permalink
Fixes: #322
Browse files Browse the repository at this point in the history
  • Loading branch information
alvarosanchez committed Feb 13, 2020
1 parent 0b28eb4 commit 671fc02
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class RestAuthenticationFilter extends GenericFilterBean {
AuthenticationSuccessHandler authenticationSuccessHandler
AuthenticationFailureHandler authenticationFailureHandler
RestAuthenticationEventPublisher authenticationEventPublisher
SpringSecurityRestFilterRequestMatcher requestMatcher

AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource

Expand All @@ -75,12 +76,8 @@ class RestAuthenticationFilter extends GenericFilterBean {
HttpServletRequest httpServletRequest = request as HttpServletRequest
HttpServletResponse httpServletResponse = response as HttpServletResponse

String actualUri = httpServletRequest.requestURI - httpServletRequest.contextPath

logger.debug "Actual URI is ${actualUri}; endpoint URL is ${endpointUrl}"

//Only apply filter to the configured URL
if (actualUri == endpointUrl) {
if (requestMatcher.matches(httpServletRequest)) {
log.debug "Applying authentication filter to this request"

//Only POST is supported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ class RestLogoutFilter extends GenericFilterBean {

TokenStorageService tokenStorageService

SpringSecurityRestFilterRequestMatcher requestMatcher

@Override
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletRequest = request as HttpServletRequest
HttpServletResponse servletResponse = response as HttpServletResponse

String actualUri = servletRequest.requestURI - servletRequest.contextPath

//Only apply filter to the configured URL
if (actualUri == endpointUrl) {
if (requestMatcher.matches(servletRequest)) {

//Only POST is supported
if (servletRequest.method != 'POST') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class RestTokenValidationFilter extends GenericFilterBean {
AuthenticationFailureHandler authenticationFailureHandler
RestAuthenticationEventPublisher authenticationEventPublisher

SpringSecurityRestFilterRequestMatcher requestMatcher

TokenReader tokenReader
String validationEndpointUrl
Boolean active
Expand Down Expand Up @@ -104,16 +106,14 @@ class RestTokenValidationFilter extends GenericFilterBean {
HttpServletRequest httpRequest = request as HttpServletRequest
HttpServletResponse httpResponse = response as HttpServletResponse

String actualUri = httpRequest.requestURI - httpRequest.contextPath

if (!active) {
log.debug "Token validation is disabled. Continuing the filter chain"
chain.doFilter(request, response)
return
}

if (authenticationResult?.accessToken) {
if (actualUri == validationEndpointUrl) {
if (requestMatcher.matches(httpRequest)) {
log.debug "Validation endpoint called. Generating response."
authenticationSuccessHandler.onAuthenticationSuccess(httpRequest, httpResponse, authenticationResult)
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package grails.plugin.springsecurity.rest

import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.springframework.security.web.util.matcher.RequestMatcher

import javax.servlet.http.HttpServletRequest

/**
* Determines whether a given request matches against a configured endpoint URL
*
* @author Álvaro Sánchez-Mariscal
*/
@Slf4j
@CompileStatic
class SpringSecurityRestFilterRequestMatcher implements RequestMatcher {

private String endpointUrl

SpringSecurityRestFilterRequestMatcher(String endpointUrl) {
this.endpointUrl = endpointUrl
}

@Override
boolean matches(HttpServletRequest request) {
String actualUri = request.requestURI - request.contextPath
log.debug "Actual URI is ${actualUri}; endpoint URL is ${endpointUrl}"
return actualUri == endpointUrl
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class SpringSecurityRestGrailsPlugin extends Plugin {
if(conf.rest.login.active) {
SpringSecurityUtils.registerFilter 'restAuthenticationFilter', SecurityFilterPosition.FORM_LOGIN_FILTER.order + 1

restAuthenticationFilterRequestMatcher(SpringSecurityRestFilterRequestMatcher, conf.rest.login.endpointUrl)

restAuthenticationFilter(RestAuthenticationFilter) {
authenticationManager = ref('authenticationManager')
authenticationSuccessHandler = ref('restAuthenticationSuccessHandler')
Expand All @@ -122,6 +124,7 @@ class SpringSecurityRestGrailsPlugin extends Plugin {
tokenGenerator = ref('tokenGenerator')
tokenStorageService = ref('tokenStorageService')
authenticationEventPublisher = ref('authenticationEventPublisher')
requestMatcher = ref('restAuthenticationFilterRequestMatcher')
}

def paramsClosure = {
Expand All @@ -136,11 +139,14 @@ class SpringSecurityRestGrailsPlugin extends Plugin {
}

/* restLogoutFilter */
restLogoutFilterRequestMatcher(SpringSecurityRestFilterRequestMatcher, conf.rest.logout.endpointUrl)

restLogoutFilter(RestLogoutFilter) {
endpointUrl = conf.rest.logout.endpointUrl
headerName = conf.rest.token.validation.headerName
tokenStorageService = ref('tokenStorageService')
tokenReader = ref('tokenReader')
requestMatcher = ref('restLogoutFilterRequestMatcher')
}
}

Expand Down Expand Up @@ -184,6 +190,8 @@ class SpringSecurityRestGrailsPlugin extends Plugin {
SpringSecurityUtils.registerFilter 'restTokenValidationFilter', SecurityFilterPosition.ANONYMOUS_FILTER.order + 1
SpringSecurityUtils.registerFilter 'restExceptionTranslationFilter', SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order - 5

restTokenValidationFilterRequestMatcher(SpringSecurityRestFilterRequestMatcher, conf.rest.token.validation.endpointUrl)

restTokenValidationFilter(RestTokenValidationFilter) {
headerName = conf.rest.token.validation.headerName
validationEndpointUrl = conf.rest.token.validation.endpointUrl
Expand All @@ -194,6 +202,7 @@ class SpringSecurityRestGrailsPlugin extends Plugin {
authenticationFailureHandler = ref('restAuthenticationFailureHandler')
restAuthenticationProvider = ref('restAuthenticationProvider')
authenticationEventPublisher = ref('authenticationEventPublisher')
requestMatcher = ref('restTokenValidationFilterRequestMatcher')
}

restExceptionTranslationFilter(ExceptionTranslationFilter, ref('restAuthenticationEntryPoint'), ref('restRequestCache')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class RestTokenValidationFilterUnitSpec extends Specification {
filter.authenticationFailureHandler = Mock(AuthenticationFailureHandler)
filter.tokenReader = Mock(TokenReader)
filter.authenticationEventPublisher = Mock(RestAuthenticationEventPublisher)
filter.requestMatcher = Stub(SpringSecurityRestFilterRequestMatcher) {
matches(_) >> true
}
}

void "authentication passes when a valid token is found"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package grails.plugin.springsecurity.rest

import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockServletContext
import spock.lang.Specification
import spock.lang.Unroll

class SpringSecurityRestFilterRequestMatcherSpec extends Specification {

@Unroll
void "if the context path is #contextPath, the URI #uri matches: #matches"(String contextPath, String uri, boolean matches) {
given:
SpringSecurityRestFilterRequestMatcher requestMatcher = new SpringSecurityRestFilterRequestMatcher("/api/login")
MockServletContext servletContext = new MockServletContext()
servletContext.setContextPath(contextPath)
MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "POST", uri)

when:
boolean matchesResult = requestMatcher.matches(request)

then:
matchesResult == matches

where:
contextPath | uri || matches
"/" | "/api/login" || true
"/" | "/api/loginxxx" || false
"/foo" | "/api/login/foo" || false
}

}

0 comments on commit 671fc02

Please sign in to comment.