|
17 | 17 | package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource;
|
18 | 18 |
|
19 | 19 | import java.util.Collections;
|
| 20 | +import java.util.LinkedHashMap; |
20 | 21 | import java.util.List;
|
| 22 | +import java.util.Map; |
21 | 23 | import java.util.regex.Matcher;
|
22 | 24 | import java.util.regex.Pattern;
|
23 | 25 |
|
24 | 26 | import jakarta.servlet.http.HttpServletRequest;
|
| 27 | +import jakarta.servlet.http.HttpServletResponse; |
25 | 28 |
|
26 | 29 | import org.springframework.http.HttpHeaders;
|
27 | 30 | import org.springframework.http.HttpStatus;
|
28 | 31 | import org.springframework.security.authentication.AuthenticationManager;
|
29 | 32 | import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
30 | 33 | import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
31 | 34 | import org.springframework.security.core.Authentication;
|
| 35 | +import org.springframework.security.core.AuthenticationException; |
32 | 36 | import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
33 | 37 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
34 | 38 | import org.springframework.security.oauth2.core.OAuth2Error;
|
35 | 39 | import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
| 40 | +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; |
| 41 | +import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; |
36 | 42 | import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationProvider;
|
37 | 43 | import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken;
|
| 44 | +import org.springframework.security.web.AuthenticationEntryPoint; |
38 | 45 | import org.springframework.security.web.authentication.AuthenticationConverter;
|
39 | 46 | import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler;
|
40 | 47 | import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
41 | 48 | import org.springframework.security.web.authentication.AuthenticationFilter;
|
42 | 49 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
43 |
| -import org.springframework.security.web.authentication.HttpStatusEntryPoint; |
44 | 50 | import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
45 | 51 | import org.springframework.security.web.util.matcher.RequestMatcher;
|
46 | 52 | import org.springframework.util.CollectionUtils;
|
@@ -102,7 +108,7 @@ private AuthenticationSuccessHandler getAuthenticationSuccessHandler() {
|
102 | 108 | private AuthenticationFailureHandler getAuthenticationFailureHandler() {
|
103 | 109 | if (this.authenticationFailureHandler == null) {
|
104 | 110 | this.authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(
|
105 |
| - new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)); |
| 111 | + new DPoPAuthenticationEntryPoint()); |
106 | 112 | }
|
107 | 113 | return this.authenticationFailureHandler;
|
108 | 114 | }
|
@@ -161,4 +167,47 @@ public Authentication convert(HttpServletRequest request) {
|
161 | 167 |
|
162 | 168 | }
|
163 | 169 |
|
| 170 | + private static final class DPoPAuthenticationEntryPoint implements AuthenticationEntryPoint { |
| 171 | + |
| 172 | + @Override |
| 173 | + public void commence(HttpServletRequest request, HttpServletResponse response, |
| 174 | + AuthenticationException authenticationException) { |
| 175 | + Map<String, String> parameters = new LinkedHashMap<>(); |
| 176 | + if (authenticationException instanceof OAuth2AuthenticationException oauth2AuthenticationException) { |
| 177 | + OAuth2Error error = oauth2AuthenticationException.getError(); |
| 178 | + parameters.put(OAuth2ParameterNames.ERROR, error.getErrorCode()); |
| 179 | + if (StringUtils.hasText(error.getDescription())) { |
| 180 | + parameters.put(OAuth2ParameterNames.ERROR_DESCRIPTION, error.getDescription()); |
| 181 | + } |
| 182 | + if (StringUtils.hasText(error.getUri())) { |
| 183 | + parameters.put(OAuth2ParameterNames.ERROR_URI, error.getUri()); |
| 184 | + } |
| 185 | + } |
| 186 | + parameters.put("algs", |
| 187 | + JwsAlgorithms.RS256 + " " + JwsAlgorithms.RS384 + " " + JwsAlgorithms.RS512 + " " |
| 188 | + + JwsAlgorithms.PS256 + " " + JwsAlgorithms.PS384 + " " + JwsAlgorithms.PS512 + " " |
| 189 | + + JwsAlgorithms.ES256 + " " + JwsAlgorithms.ES384 + " " + JwsAlgorithms.ES512); |
| 190 | + String wwwAuthenticate = toWWWAuthenticateHeader(parameters); |
| 191 | + response.addHeader(HttpHeaders.WWW_AUTHENTICATE, wwwAuthenticate); |
| 192 | + response.setStatus(HttpStatus.UNAUTHORIZED.value()); |
| 193 | + } |
| 194 | + |
| 195 | + private static String toWWWAuthenticateHeader(Map<String, String> parameters) { |
| 196 | + StringBuilder wwwAuthenticate = new StringBuilder(); |
| 197 | + wwwAuthenticate.append(OAuth2AccessToken.TokenType.DPOP.getValue()); |
| 198 | + if (!parameters.isEmpty()) { |
| 199 | + wwwAuthenticate.append(" "); |
| 200 | + int i = 0; |
| 201 | + for (Map.Entry<String, String> entry : parameters.entrySet()) { |
| 202 | + wwwAuthenticate.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\""); |
| 203 | + if (i++ != parameters.size() - 1) { |
| 204 | + wwwAuthenticate.append(", "); |
| 205 | + } |
| 206 | + } |
| 207 | + } |
| 208 | + return wwwAuthenticate.toString(); |
| 209 | + } |
| 210 | + |
| 211 | + } |
| 212 | + |
164 | 213 | }
|
0 commit comments