|
15 | 15 | */
|
16 | 16 | package org.springframework.security.oauth2.server.authorization.web;
|
17 | 17 |
|
| 18 | +import org.springframework.http.MediaType; |
| 19 | +import org.springframework.http.server.ServletServerHttpResponse; |
18 | 20 | import org.springframework.security.authentication.AuthenticationManager;
|
| 21 | +import org.springframework.security.core.Authentication; |
| 22 | +import org.springframework.security.core.AuthenticationException; |
| 23 | +import org.springframework.security.core.context.SecurityContextHolder; |
| 24 | +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; |
| 25 | +import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter; |
| 26 | +import org.springframework.security.web.authentication.AuthenticationConverter; |
| 27 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
| 28 | +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
| 29 | +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; |
| 30 | +import org.springframework.security.web.util.matcher.RequestMatcher; |
| 31 | +import org.springframework.util.Assert; |
19 | 32 | import org.springframework.web.filter.OncePerRequestFilter;
|
20 |
| - |
21 | 33 | import javax.servlet.FilterChain;
|
22 | 34 | import javax.servlet.ServletException;
|
23 | 35 | import javax.servlet.http.HttpServletRequest;
|
|
26 | 38 |
|
27 | 39 | /**
|
28 | 40 | * @author Joe Grandja
|
| 41 | + * @author Patryk Kostrzewa |
29 | 42 | */
|
30 | 43 | public class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter {
|
31 |
| - private AuthenticationManager authenticationManager; |
| 44 | + |
| 45 | + public static final String DEFAULT_FILTER_PROCESSES_URL = "/oauth2/token"; |
| 46 | + private final AuthenticationManager authenticationManager; |
| 47 | + private final RequestMatcher requestMatcher; |
| 48 | + private final OAuth2ErrorHttpMessageConverter errorMessageConverter = new OAuth2ErrorHttpMessageConverter(); |
| 49 | + private AuthenticationSuccessHandler authenticationSuccessHandler; |
| 50 | + private AuthenticationFailureHandler authenticationFailureHandler; |
| 51 | + private AuthenticationConverter authenticationConverter = new DefaultOAuth2ClientAuthenticationConverter(); |
| 52 | + |
| 53 | + /** |
| 54 | + * Creates an instance which will authenticate against the supplied |
| 55 | + * {@code AuthenticationManager}. |
| 56 | + * |
| 57 | + * @param authenticationManager |
| 58 | + * the bean to submit authentication requests to |
| 59 | + */ |
| 60 | + public OAuth2ClientAuthenticationFilter(AuthenticationManager authenticationManager) { |
| 61 | + this(authenticationManager, DEFAULT_FILTER_PROCESSES_URL); |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * Creates an instance which will authenticate against the supplied |
| 66 | + * {@code AuthenticationManager}. |
| 67 | + * |
| 68 | + * <p> |
| 69 | + * Configures default {@link RequestMatcher} verifying the provided endpoint. |
| 70 | + * |
| 71 | + * @param authenticationManager |
| 72 | + * the bean to submit authentication requests to |
| 73 | + * @param filterProcessesUrl |
| 74 | + * the filterProcessesUrl to match request URI against |
| 75 | + */ |
| 76 | + public OAuth2ClientAuthenticationFilter(AuthenticationManager authenticationManager, String filterProcessesUrl) { |
| 77 | + this(authenticationManager, new AntPathRequestMatcher(filterProcessesUrl, "POST")); |
| 78 | + } |
| 79 | + |
| 80 | + /** |
| 81 | + * Creates an instance which will authenticate against the supplied |
| 82 | + * {@code AuthenticationManager} and custom {@code RequestMatcher}. |
| 83 | + * |
| 84 | + * @param authenticationManager |
| 85 | + * the bean to submit authentication requests to |
| 86 | + * @param requestMatcher |
| 87 | + * the {@code RequestMatcher} to match {@code HttpServletRequest} against |
| 88 | + */ |
| 89 | + public OAuth2ClientAuthenticationFilter(AuthenticationManager authenticationManager, |
| 90 | + RequestMatcher requestMatcher) { |
| 91 | + Assert.notNull(authenticationManager, "authenticationManager cannot be null"); |
| 92 | + Assert.notNull(requestMatcher, "requestMatcher cannot be null"); |
| 93 | + this.authenticationManager = authenticationManager; |
| 94 | + this.requestMatcher = requestMatcher; |
| 95 | + this.authenticationSuccessHandler = this::defaultAuthenticationSuccessHandler; |
| 96 | + this.authenticationFailureHandler = this::defaultAuthenticationFailureHandler; |
| 97 | + } |
32 | 98 |
|
33 | 99 | @Override
|
34 |
| - protected void doFilterInternal(HttpServletRequest request, |
35 |
| - HttpServletResponse response, FilterChain filterChain) |
| 100 | + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
36 | 101 | throws ServletException, IOException {
|
37 | 102 |
|
| 103 | + if (this.requestMatcher.matches(request)) { |
| 104 | + Authentication authentication = this.authenticationConverter.convert(request); |
| 105 | + if (authentication == null) { |
| 106 | + filterChain.doFilter(request, response); |
| 107 | + return; |
| 108 | + } |
| 109 | + try { |
| 110 | + final Authentication result = this.authenticationManager.authenticate(authentication); |
| 111 | + this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, result); |
| 112 | + } catch (OAuth2AuthenticationException failed) { |
| 113 | + this.authenticationFailureHandler.onAuthenticationFailure(request, response, failed); |
| 114 | + return; |
| 115 | + } |
| 116 | + } |
| 117 | + filterChain.doFilter(request, response); |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * Used to define custom behaviour on a successful authentication. |
| 122 | + * |
| 123 | + * @param authenticationSuccessHandler |
| 124 | + * the handler to be used |
| 125 | + */ |
| 126 | + public final void setAuthenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler) { |
| 127 | + Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null"); |
| 128 | + this.authenticationSuccessHandler = authenticationSuccessHandler; |
38 | 129 | }
|
39 | 130 |
|
| 131 | + /** |
| 132 | + * Used to define custom behaviour on a failed authentication. |
| 133 | + * |
| 134 | + * @param authenticationFailureHandler |
| 135 | + * the handler to be used |
| 136 | + */ |
| 137 | + public final void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) { |
| 138 | + Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null"); |
| 139 | + this.authenticationFailureHandler = authenticationFailureHandler; |
| 140 | + } |
| 141 | + |
| 142 | + /** |
| 143 | + * Used to define custom {@link AuthenticationConverter}. |
| 144 | + * |
| 145 | + * @param authenticationConverter |
| 146 | + * the converter to be used |
| 147 | + */ |
| 148 | + public final void setAuthenticationConverter(AuthenticationConverter authenticationConverter) { |
| 149 | + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); |
| 150 | + this.authenticationConverter = authenticationConverter; |
| 151 | + } |
| 152 | + |
| 153 | + private void defaultAuthenticationSuccessHandler(HttpServletRequest request, HttpServletResponse response, |
| 154 | + Authentication authentication) { |
| 155 | + |
| 156 | + SecurityContextHolder.getContext() |
| 157 | + .setAuthentication(authentication); |
| 158 | + } |
| 159 | + |
| 160 | + private void defaultAuthenticationFailureHandler(HttpServletRequest request, HttpServletResponse response, |
| 161 | + AuthenticationException failed) throws IOException { |
| 162 | + |
| 163 | + SecurityContextHolder.clearContext(); |
| 164 | + this.errorMessageConverter.write(((OAuth2AuthenticationException) failed).getError(), |
| 165 | + MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response)); |
| 166 | + } |
40 | 167 | }
|
0 commit comments