1
2
3
4
5
6
7
8
9
10
11
12
13 package org.springframework.security.oauth2.provider.endpoint;
14
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertFalse;
17 import static org.junit.Assert.assertNull;
18 import static org.junit.Assert.assertTrue;
19 import static org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.AUTHORIZATION_REQUEST_ATTR_NAME;
20 import static org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME;
21
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.LinkedHashSet;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
33 import org.springframework.security.core.Authentication;
34 import org.springframework.security.core.authority.AuthorityUtils;
35 import org.springframework.security.core.authority.SimpleGrantedAuthority;
36 import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
37 import org.springframework.security.oauth2.common.OAuth2AccessToken;
38 import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
39 import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
40 import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
41 import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
42 import org.springframework.security.oauth2.common.util.OAuth2Utils;
43 import org.springframework.security.oauth2.provider.AuthorizationRequest;
44 import org.springframework.security.oauth2.provider.ClientDetails;
45 import org.springframework.security.oauth2.provider.ClientDetailsService;
46 import org.springframework.security.oauth2.provider.OAuth2Authentication;
47 import org.springframework.security.oauth2.provider.TokenGranter;
48 import org.springframework.security.oauth2.provider.TokenRequest;
49 import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
50 import org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler;
51 import org.springframework.security.oauth2.provider.approval.InMemoryApprovalStore;
52 import org.springframework.security.oauth2.provider.client.BaseClientDetails;
53 import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
54 import org.springframework.util.MultiValueMap;
55 import org.springframework.web.bind.support.SimpleSessionStatus;
56 import org.springframework.web.servlet.ModelAndView;
57 import org.springframework.web.servlet.View;
58 import org.springframework.web.servlet.view.RedirectView;
59 import org.springframework.web.util.UriComponentsBuilder;
60
61
62
63
64
65 public class AuthorizationEndpointTests {
66
67 private AuthorizationEndpoint endpoint = new AuthorizationEndpoint();
68
69 private HashMap<String, Object> model = new HashMap<String, Object>();
70
71 private SimpleSessionStatus sessionStatus = new SimpleSessionStatus();
72
73 private UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken("foo", "bar",
74 Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")));
75
76 private BaseClientDetails client;
77
78 private AuthorizationRequest getAuthorizationRequest(String clientId, String redirectUri, String state,
79 String scope, Set<String> responseTypes) {
80 HashMap<String, String> parameters = new HashMap<String, String>();
81 parameters.put(OAuth2Utils.CLIENT_ID, clientId);
82 if (redirectUri != null) {
83 parameters.put(OAuth2Utils.REDIRECT_URI, redirectUri);
84 }
85 if (state != null) {
86 parameters.put(OAuth2Utils.STATE, state);
87 }
88 if (scope != null) {
89 parameters.put(OAuth2Utils.SCOPE, scope);
90 }
91 if (responseTypes != null) {
92 parameters.put(OAuth2Utils.RESPONSE_TYPE, OAuth2Utils.formatParameterList(responseTypes));
93 }
94 return new AuthorizationRequest(parameters, Collections.<String, String> emptyMap(),
95 parameters.get(OAuth2Utils.CLIENT_ID),
96 OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)), null, null, false,
97 parameters.get(OAuth2Utils.STATE), parameters.get(OAuth2Utils.REDIRECT_URI),
98 OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.RESPONSE_TYPE)));
99 }
100
101 @Before
102 public void init() throws Exception {
103 client = new BaseClientDetails();
104 client.setRegisteredRedirectUri(Collections.singleton("https://anywhere.com"));
105 client.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "implicit"));
106 endpoint.setClientDetailsService(new ClientDetailsService() {
107 public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception {
108 return client;
109 }
110 });
111 endpoint.setTokenGranter(new TokenGranter() {
112 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
113 return null;
114 }
115 });
116 endpoint.setRedirectResolver(new DefaultRedirectResolver());
117 endpoint.afterPropertiesSet();
118 }
119
120 @Test(expected = IllegalStateException.class)
121 public void testMandatoryProperties() throws Exception {
122 endpoint = new AuthorizationEndpoint();
123 endpoint.afterPropertiesSet();
124 }
125
126 @Test
127 public void testStartAuthorizationCodeFlow() throws Exception {
128 ModelAndView result = endpoint.authorize(model,
129 getAuthorizationRequest("foo", null, null, "read", Collections.singleton("code"))
130 .getRequestParameters(), sessionStatus, principal);
131 assertEquals("forward:/oauth/confirm_access", result.getViewName());
132 }
133
134 @Test
135 public void testApprovalStoreAddsScopes() throws Exception {
136 ApprovalStoreUserApprovalHandler userApprovalHandler = new ApprovalStoreUserApprovalHandler();
137 userApprovalHandler.setApprovalStore(new InMemoryApprovalStore());
138 endpoint.setUserApprovalHandler(userApprovalHandler);
139 ModelAndView result = endpoint.authorize(model,
140 getAuthorizationRequest("foo", null, null, "read", Collections.singleton("code"))
141 .getRequestParameters(), sessionStatus, principal);
142 assertEquals("forward:/oauth/confirm_access", result.getViewName());
143 assertTrue(result.getModel().containsKey("scopes"));
144 }
145
146 @Test(expected = OAuth2Exception.class)
147 public void testStartAuthorizationCodeFlowForClientCredentialsFails() throws Exception {
148 client.setAuthorizedGrantTypes(Collections.singleton("client_credentials"));
149 ModelAndView result = endpoint.authorize(model,
150 getAuthorizationRequest("foo", null, null, null, Collections.singleton("code")).getRequestParameters(),
151 sessionStatus, principal);
152 assertEquals("forward:/oauth/confirm_access", result.getViewName());
153 }
154
155 @Test
156 public void testAuthorizationCodeWithFragment() throws Exception {
157 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
158 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com#bar", null, null, Collections.singleton("code"));
159 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
160 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
161 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
162 sessionStatus, principal);
163 assertEquals("https://anywhere.com?code=thecode#bar", ((RedirectView) result).getUrl());
164 }
165
166 @Test
167 public void testAuthorizationCodeWithQueryParams() throws Exception {
168 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
169 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com?foo=bar", null, null, Collections.singleton("code"));
170 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
171 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
172 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
173 sessionStatus, principal);
174 assertEquals("https://anywhere.com?foo=bar&code=thecode", ((RedirectView) result).getUrl());
175 }
176
177 @Test
178 public void testAuthorizationCodeWithTrickyState() throws Exception {
179 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
180 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com", " =?s", null, Collections.singleton("code"));
181 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
182 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
183 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
184 sessionStatus, principal);
185 assertEquals("https://anywhere.com?code=thecode&state=%20%3D?s", ((RedirectView) result).getUrl());
186 }
187
188 @Test
189 public void testAuthorizationCodeWithMultipleQueryParams() throws Exception {
190 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
191 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com?foo=bar&bar=foo", null, null,
192 Collections.singleton("code"));
193 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
194 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
195 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
196 sessionStatus, principal);
197 assertEquals("https://anywhere.com?foo=bar&bar=foo&code=thecode", ((RedirectView) result).getUrl());
198 }
199
200 @Test
201 public void testAuthorizationCodeWithTrickyQueryParams() throws Exception {
202 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
203 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com?foo=b =&bar=f $", null, null,
204 Collections.singleton("code"));
205 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
206 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
207 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
208 sessionStatus, principal);
209 String url = ((RedirectView) result).getUrl();
210 assertEquals("https://anywhere.com?foo=b%20=&bar=f%20$&code=thecode", url);
211 MultiValueMap<String, String> params = UriComponentsBuilder.fromHttpUrl(url).build().getQueryParams();
212 assertEquals("[b%20=]", params.get("foo").toString());
213 assertEquals("[f%20$]", params.get("bar").toString());
214 }
215
216 @Test
217 public void testAuthorizationCodeWithTrickyEncodedQueryParams() throws Exception {
218 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
219 AuthorizationRequest request = getAuthorizationRequest(
220 "foo", "https://anywhere.com/path?foo=b%20%3D&bar=f%20$", null, null, Collections.singleton("code"));
221 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
222 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
223 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
224 sessionStatus, principal);
225 assertEquals("https://anywhere.com/path?foo=b%20%3D&bar=f%20$&code=thecode", ((RedirectView) result).getUrl());
226 }
227
228 @Test
229 public void testAuthorizationCodeWithMoreTrickyEncodedQueryParams() throws Exception {
230 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices());
231 AuthorizationRequest request = getAuthorizationRequest(
232 "foo", "https://anywhere?t=a%3Db%26ep%3Dtest%2540test.me", null, null, Collections.singleton("code"));
233 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
234 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
235 View result = endpoint.approveOrDeny(Collections.singletonMap(OAuth2Utils.USER_OAUTH_APPROVAL, "true"), model,
236 sessionStatus, principal);
237 assertEquals("https://anywhere?t=a%3Db%26ep%3Dtest%2540test.me&code=thecode", ((RedirectView) result).getUrl());
238 }
239
240 @Test
241 public void testAuthorizationCodeError() throws Exception {
242 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
243 public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
244 Authentication userAuthentication) {
245 return authorizationRequest;
246 }
247
248 public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest,
249 Authentication userAuthentication) {
250 return authorizationRequest;
251 }
252
253 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
254 return true;
255 }
256 });
257 endpoint.setAuthorizationCodeServices(new StubAuthorizationCodeServices() {
258 @Override
259 public String createAuthorizationCode(OAuth2Authentication authentication) {
260 throw new InvalidScopeException("FOO");
261 }
262 });
263 ModelAndView result = endpoint.authorize(
264 model,
265 getAuthorizationRequest("foo", "https://anywhere.com", "mystate", "myscope",
266 Collections.singleton("code")).getRequestParameters(), sessionStatus, principal);
267 String url = ((RedirectView) result.getView()).getUrl();
268 assertTrue("Wrong view: " + result, url.startsWith("https://anywhere.com"));
269 assertTrue("No error: " + result, url.contains("?error="));
270 assertTrue("Wrong state: " + result, url.contains("&state=mystate"));
271
272 }
273
274 @Test
275 public void testAuthorizationCodeWithMultipleResponseTypes() throws Exception {
276 Set<String> responseTypes = new HashSet<String>();
277 responseTypes.add("code");
278 responseTypes.add("other");
279 ModelAndView result = endpoint.authorize(model,
280 getAuthorizationRequest("foo", null, null, "read", responseTypes).getRequestParameters(),
281 sessionStatus, principal);
282 assertEquals("forward:/oauth/confirm_access", result.getViewName());
283 }
284
285 @Test
286 public void testImplicitPreApproved() throws Exception {
287 endpoint.setTokenGranter(new TokenGranter() {
288
289 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
290 DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
291 token.setAdditionalInformation(Collections.singletonMap("foo", (Object) "bar"));
292 return token;
293
294 }
295 });
296 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
297 public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
298 Authentication userAuthentication) {
299 return authorizationRequest;
300 }
301
302 public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest,
303 Authentication userAuthentication) {
304 return authorizationRequest;
305 }
306
307 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
308 return true;
309 }
310 });
311 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
312 "myscope", Collections.singleton("token"));
313 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
314 principal);
315 String url = ((RedirectView) result.getView()).getUrl();
316 assertTrue("Wrong view: " + result, url.startsWith("https://anywhere.com"));
317 assertTrue("Wrong state: " + result, url.contains("&state=mystate"));
318 assertTrue("Wrong token: " + result, url.contains("access_token="));
319 assertTrue("Wrong token: " + result, url.contains("foo=bar"));
320 }
321
322 @Test
323 public void testImplicitAppendsScope() throws Exception {
324 endpoint.setTokenGranter(new TokenGranter() {
325 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
326 DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
327 token.setScope(Collections.singleton("read"));
328 return token;
329 }
330 });
331 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
332 public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
333 Authentication userAuthentication) {
334 return authorizationRequest;
335 }
336
337 public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest,
338 Authentication userAuthentication) {
339 return authorizationRequest;
340 }
341
342 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
343 return true;
344 }
345 });
346 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
347 "myscope", Collections.singleton("token"));
348 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
349 principal);
350 String url = ((RedirectView) result.getView()).getUrl();
351 assertTrue("Wrong scope: " + result, url.contains("&scope=read"));
352 }
353
354 @Test
355 public void testImplicitWithQueryParam() throws Exception {
356 endpoint.setTokenGranter(new TokenGranter() {
357 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
358 DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
359 return token;
360 }
361 });
362 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
363 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
364 return true;
365 }
366 });
367 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com?foo=bar",
368 "mystate", "myscope", Collections.singleton("token"));
369 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
370 principal);
371 String url = ((RedirectView) result.getView()).getUrl();
372 assertTrue("Wrong url: " + result, url.contains("foo=bar"));
373 }
374
375 @Test
376 public void testImplicitWithAdditionalInfo() throws Exception {
377 endpoint.setTokenGranter(new TokenGranter() {
378 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
379 DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
380 token.setAdditionalInformation(Collections.<String, Object> singletonMap("foo", "bar"));
381 return token;
382 }
383 });
384 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
385 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
386 return true;
387 }
388 });
389 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
390 "myscope", Collections.singleton("token"));
391 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
392 principal);
393 String url = ((RedirectView) result.getView()).getUrl();
394 assertTrue("Wrong url: " + result, url.contains("foo=bar"));
395 }
396
397 @Test
398 public void testImplicitAppendsScopeWhenDefaulting() throws Exception {
399 endpoint.setTokenGranter(new TokenGranter() {
400 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
401 DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
402 token.setScope(new LinkedHashSet<String>(Arrays.asList("read", "write")));
403 return token;
404 }
405 });
406 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
407 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
408 return true;
409 }
410
411 public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
412 Authentication userAuthentication) {
413 return authorizationRequest;
414 }
415
416 public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest,
417 Authentication userAuthentication) {
418 return authorizationRequest;
419 }
420 });
421 client.setScope(Collections.singleton("read"));
422 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
423 null, Collections.singleton("token"));
424 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
425 principal);
426 String url = ((RedirectView) result.getView()).getUrl();
427 assertTrue("Wrong scope: " + result, url.contains("&scope=read%20write"));
428 }
429
430 @Test(expected = InvalidScopeException.class)
431 public void testImplicitPreApprovedButInvalid() throws Exception {
432 endpoint.setTokenGranter(new TokenGranter() {
433 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
434 throw new IllegalStateException("Shouldn't be called");
435 }
436 });
437 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
438 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
439 return true;
440 }
441
442 public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
443 Authentication userAuthentication) {
444 return authorizationRequest;
445 }
446
447 public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest,
448 Authentication userAuthentication) {
449 return authorizationRequest;
450 }
451 });
452 client.setScope(Collections.singleton("smallscope"));
453 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
454 "bigscope", Collections.singleton("token"));
455 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
456 principal);
457 String url = ((RedirectView) result.getView()).getUrl();
458 assertTrue("Wrong view: " + result, url.startsWith("https://anywhere.com"));
459 }
460
461 @Test
462 public void testImplicitUnapproved() throws Exception {
463 endpoint.setTokenGranter(new TokenGranter() {
464 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
465 return null;
466 }
467 });
468 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
469 "myscope", Collections.singleton("token"));
470 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
471 principal);
472 assertEquals("forward:/oauth/confirm_access", result.getViewName());
473 }
474
475 @Test
476 public void testImplicitError() throws Exception {
477 endpoint.setUserApprovalHandler(new DefaultUserApprovalHandler() {
478 public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
479 Authentication userAuthentication) {
480 return authorizationRequest;
481 }
482
483 public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest,
484 Authentication userAuthentication) {
485 return authorizationRequest;
486 }
487
488 public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
489 return true;
490 }
491 });
492 endpoint.setTokenGranter(new TokenGranter() {
493 public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
494 return null;
495 }
496 });
497 AuthorizationRequest authorizationRequest = getAuthorizationRequest("foo", "https://anywhere.com", "mystate",
498 "myscope", Collections.singleton("token"));
499 ModelAndView result = endpoint.authorize(model, authorizationRequest.getRequestParameters(), sessionStatus,
500 principal);
501
502 String url = ((RedirectView) result.getView()).getUrl();
503 assertTrue("Wrong view: " + result, url.startsWith("https://anywhere.com"));
504 assertTrue("No error: " + result, url.contains("#error="));
505 assertTrue("Wrong state: " + result, url.contains("&state=mystate"));
506
507 }
508
509 @Test
510 public void testApproveOrDeny() throws Exception {
511 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com", null, null,
512 Collections.singleton("code"));
513 request.setApproved(true);
514 Map<String, String> approvalParameters = new HashMap<String, String>();
515 approvalParameters.put("user_oauth_approval", "true");
516 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
517 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
518 View result = endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
519 assertTrue("Wrong view: " + result, ((RedirectView) result).getUrl().startsWith("https://anywhere.com"));
520 }
521
522 @Test
523 public void testApprovalDenied() throws Exception {
524 AuthorizationRequest request = getAuthorizationRequest("foo", "https://anywhere.com", null, null, Collections.singleton("code"));
525 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
526 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
527 Map<String, String> approvalParameters = new HashMap<String, String>();
528 approvalParameters.put("user_oauth_approval", "false");
529 View result = endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
530 String url = ((RedirectView) result).getUrl();
531 assertTrue("Wrong view: " + result, url.startsWith("https://anywhere.com"));
532 assertTrue("Wrong view: " + result, url.contains("error=access_denied"));
533 }
534
535 @Test
536 public void testDirectApproval() throws Exception {
537 ModelAndView result = endpoint.authorize(model,
538 getAuthorizationRequest("foo", "https://anywhere.com", null, "read", Collections.singleton("code"))
539 .getRequestParameters(), sessionStatus, principal);
540
541 assertFalse(result.getView() instanceof RedirectView);
542 }
543
544 @Test
545 public void testRedirectUriOptionalForAuthorization() throws Exception {
546 ModelAndView result = endpoint.authorize(model,
547 getAuthorizationRequest("foo", null, null, "read", Collections.singleton("code"))
548 .getRequestParameters(), sessionStatus, principal);
549
550 AuthorizationRequest authorizationRequest = (AuthorizationRequest) result.getModelMap().get(
551 AUTHORIZATION_REQUEST_ATTR_NAME);
552 assertNull(authorizationRequest.getRequestParameters().get(OAuth2Utils.REDIRECT_URI));
553 assertEquals("https://anywhere.com", authorizationRequest.getRedirectUri());
554 }
555
556
557
558
559
560 @Test(expected = InvalidRequestException.class)
561 public void testApproveOrDenyWithOAuth2RequestWithoutRedirectUri() throws Exception {
562 AuthorizationRequest request = getAuthorizationRequest("foo", null, null, null, Collections.singleton("code"));
563 request.setApproved(true);
564 Map<String, String> approvalParameters = new HashMap<String, String>();
565 approvalParameters.put("user_oauth_approval", "true");
566 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, request);
567 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(request));
568 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
569
570 }
571
572 @Test(expected = InvalidRequestException.class)
573 public void testApproveWithModifiedClientId() throws Exception {
574 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
575 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
576 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
577 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
578 authorizationRequest.setClientId("bar");
579 Map<String, String> approvalParameters = new HashMap<String, String>();
580 approvalParameters.put("user_oauth_approval", "true");
581 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
582 }
583
584 @Test(expected = InvalidRequestException.class)
585 public void testApproveWithModifiedState() throws Exception {
586 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
587 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
588 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
589 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
590 authorizationRequest.setState("state-5678");
591 Map<String, String> approvalParameters = new HashMap<String, String>();
592 approvalParameters.put("user_oauth_approval", "true");
593 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
594 }
595
596 @Test(expected = InvalidRequestException.class)
597 public void testApproveWithModifiedRedirectUri() throws Exception {
598 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
599 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
600 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
601 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
602 authorizationRequest.setRedirectUri("https://somewhere.com"); // Modify authorization request
603 Map<String, String> approvalParameters = new HashMap<String, String>();
604 approvalParameters.put("user_oauth_approval", "true");
605 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
606 }
607
608 @Test(expected = InvalidRequestException.class)
609 public void testApproveWithModifiedResponseTypes() throws Exception {
610 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
611 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
612 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
613 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
614 authorizationRequest.setResponseTypes(Collections.singleton("implicit"));
615 Map<String, String> approvalParameters = new HashMap<String, String>();
616 approvalParameters.put("user_oauth_approval", "true");
617 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
618 }
619
620 @Test(expected = InvalidRequestException.class)
621 public void testApproveWithModifiedScope() throws Exception {
622 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
623 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
624 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
625 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
626 authorizationRequest.setScope(Arrays.asList("read", "write"));
627 Map<String, String> approvalParameters = new HashMap<String, String>();
628 approvalParameters.put("user_oauth_approval", "true");
629 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
630 }
631
632 @Test(expected = InvalidRequestException.class)
633 public void testApproveWithModifiedApproved() throws Exception {
634 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
635 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
636 authorizationRequest.setApproved(false);
637 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
638 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
639 authorizationRequest.setApproved(true);
640 Map<String, String> approvalParameters = new HashMap<String, String>();
641 approvalParameters.put("user_oauth_approval", "true");
642 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
643 }
644
645 @Test(expected = InvalidRequestException.class)
646 public void testApproveWithModifiedResourceIds() throws Exception {
647 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
648 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
649 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
650 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
651 authorizationRequest.setResourceIds(Collections.singleton("resource-other"));
652 Map<String, String> approvalParameters = new HashMap<String, String>();
653 approvalParameters.put("user_oauth_approval", "true");
654 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
655 }
656
657 @Test(expected = InvalidRequestException.class)
658 public void testApproveWithModifiedAuthorities() throws Exception {
659 AuthorizationRequest authorizationRequest = getAuthorizationRequest(
660 "foo", "https://anywhere.com", "state-1234", "read", Collections.singleton("code"));
661 model.put(AUTHORIZATION_REQUEST_ATTR_NAME, authorizationRequest);
662 model.put(ORIGINAL_AUTHORIZATION_REQUEST_ATTR_NAME, endpoint.unmodifiableMap(authorizationRequest));
663 authorizationRequest.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList("authority-other"));
664 Map<String, String> approvalParameters = new HashMap<String, String>();
665 approvalParameters.put("user_oauth_approval", "true");
666 endpoint.approveOrDeny(approvalParameters, model, sessionStatus, principal);
667 }
668
669 private class StubAuthorizationCodeServices implements AuthorizationCodeServices {
670 private OAuth2Authentication authentication;
671
672 public String createAuthorizationCode(OAuth2Authentication authentication) {
673 this.authentication = authentication;
674 return "thecode";
675 }
676
677 public OAuth2Authentication consumeAuthorizationCode(String code) throws InvalidGrantException {
678 return authentication;
679 }
680 }
681
682 }