1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.security.oauth2.provider.endpoint;
18
19 import org.springframework.http.HttpHeaders;
20 import org.springframework.http.HttpMethod;
21 import org.springframework.http.HttpStatus;
22 import org.springframework.http.ResponseEntity;
23 import org.springframework.security.authentication.InsufficientAuthenticationException;
24 import org.springframework.security.core.Authentication;
25 import org.springframework.security.oauth2.common.OAuth2AccessToken;
26 import org.springframework.security.oauth2.common.exceptions.BadClientCredentialsException;
27 import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
28 import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
29 import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
30 import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
31 import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
32 import org.springframework.security.oauth2.common.util.OAuth2Utils;
33 import org.springframework.security.oauth2.provider.ClientDetails;
34 import org.springframework.security.oauth2.provider.ClientRegistrationException;
35 import org.springframework.security.oauth2.provider.OAuth2Authentication;
36 import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
37 import org.springframework.security.oauth2.provider.TokenRequest;
38 import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
39 import org.springframework.util.StringUtils;
40 import org.springframework.web.HttpRequestMethodNotSupportedException;
41 import org.springframework.web.bind.annotation.ExceptionHandler;
42 import org.springframework.web.bind.annotation.RequestMapping;
43 import org.springframework.web.bind.annotation.RequestMethod;
44 import org.springframework.web.bind.annotation.RequestParam;
45
46 import java.security.Principal;
47 import java.util.Arrays;
48 import java.util.Collections;
49 import java.util.HashSet;
50 import java.util.Map;
51 import java.util.Set;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 @FrameworkEndpoint
71 public class TokenEndpoint extends AbstractEndpoint {
72
73 private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();
74
75 private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST));
76
77 @RequestMapping(value = "/oauth/token", method=RequestMethod.GET)
78 public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam
79 Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
80 if (!allowedRequestMethods.contains(HttpMethod.GET)) {
81 throw new HttpRequestMethodNotSupportedException("GET");
82 }
83 return postAccessToken(principal, parameters);
84 }
85
86 @RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
87 public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
88 Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
89
90 if (!(principal instanceof Authentication)) {
91 throw new InsufficientAuthenticationException(
92 "There is no client authentication. Try adding an appropriate authentication filter.");
93 }
94
95 String clientId = getClientId(principal);
96 ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
97
98 TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
99
100 if (clientId != null && !clientId.equals("")) {
101
102
103 if (!clientId.equals(tokenRequest.getClientId())) {
104
105
106 throw new InvalidClientException("Given client ID does not match authenticated client");
107 }
108 }
109 if (authenticatedClient != null) {
110 oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
111 }
112 if (!StringUtils.hasText(tokenRequest.getGrantType())) {
113 throw new InvalidRequestException("Missing grant type");
114 }
115 if (tokenRequest.getGrantType().equals("implicit")) {
116 throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
117 }
118
119 if (isAuthCodeRequest(parameters)) {
120
121 if (!tokenRequest.getScope().isEmpty()) {
122 logger.debug("Clearing scope of incoming token request");
123 tokenRequest.setScope(Collections.<String> emptySet());
124 }
125 }
126
127 if (isRefreshTokenRequest(parameters)) {
128
129 tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
130 }
131
132 OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
133 if (token == null) {
134 throw new UnsupportedGrantTypeException("Unsupported grant type");
135 }
136
137 return getResponse(token);
138
139 }
140
141
142
143
144
145 protected String getClientId(Principal principal) {
146 Authentication client = (Authentication) principal;
147 if (!client.isAuthenticated()) {
148 throw new InsufficientAuthenticationException("The client is not authenticated.");
149 }
150 String clientId = client.getName();
151 if (client instanceof OAuth2Authentication) {
152
153 clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId();
154 }
155 return clientId;
156 }
157
158 @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
159 public ResponseEntity<OAuth2Exception> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) throws Exception {
160 if (logger.isInfoEnabled()) {
161 logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
162 }
163 return getExceptionTranslator().translate(e);
164 }
165
166 @ExceptionHandler(Exception.class)
167 public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
168 if (logger.isErrorEnabled()) {
169 logger.error("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage(), e);
170 }
171 return getExceptionTranslator().translate(e);
172 }
173
174 @ExceptionHandler(ClientRegistrationException.class)
175 public ResponseEntity<OAuth2Exception> handleClientRegistrationException(Exception e) throws Exception {
176 if (logger.isWarnEnabled()) {
177 logger.warn("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
178 }
179 return getExceptionTranslator().translate(new BadClientCredentialsException());
180 }
181
182 @ExceptionHandler(OAuth2Exception.class)
183 public ResponseEntity<OAuth2Exception> handleException(OAuth2Exception e) throws Exception {
184 if (logger.isWarnEnabled()) {
185 logger.warn("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
186 }
187 return getExceptionTranslator().translate(e);
188 }
189
190 private ResponseEntity<OAuth2AccessToken> getResponse(OAuth2AccessToken accessToken) {
191 HttpHeaders headers = new HttpHeaders();
192 headers.set("Cache-Control", "no-store");
193 headers.set("Pragma", "no-cache");
194 headers.set("Content-Type", "application/json;charset=UTF-8");
195 return new ResponseEntity<OAuth2AccessToken>(accessToken, headers, HttpStatus.OK);
196 }
197
198 private boolean isRefreshTokenRequest(Map<String, String> parameters) {
199 return "refresh_token".equals(parameters.get("grant_type")) && parameters.get("refresh_token") != null;
200 }
201
202 private boolean isAuthCodeRequest(Map<String, String> parameters) {
203 return "authorization_code".equals(parameters.get("grant_type")) && parameters.get("code") != null;
204 }
205
206 public void setOAuth2RequestValidator(OAuth2RequestValidator oAuth2RequestValidator) {
207 this.oAuth2RequestValidator = oAuth2RequestValidator;
208 }
209
210 public void setAllowedRequestMethods(Set<HttpMethod> allowedRequestMethods) {
211 this.allowedRequestMethods = allowedRequestMethods;
212 }
213 }