View Javadoc
1   /*
2    * Copyright 2002-2011 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.security.oauth2.provider.code;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  
22  import org.springframework.security.core.Authentication;
23  import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
24  import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
25  import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
26  import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;
27  import org.springframework.security.oauth2.common.util.OAuth2Utils;
28  import org.springframework.security.oauth2.provider.ClientDetails;
29  import org.springframework.security.oauth2.provider.ClientDetailsService;
30  import org.springframework.security.oauth2.provider.OAuth2Authentication;
31  import org.springframework.security.oauth2.provider.OAuth2Request;
32  import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
33  import org.springframework.security.oauth2.provider.TokenRequest;
34  import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
35  import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
36  
37  /**
38   * Token granter for the authorization code grant type.
39   * 
40   * @author Dave Syer
41   * 
42   */
43  public class AuthorizationCodeTokenGranter extends AbstractTokenGranter {
44  
45  	private static final String GRANT_TYPE = "authorization_code";
46  
47  	private final AuthorizationCodeServices authorizationCodeServices;
48  
49  	public AuthorizationCodeTokenGranter(AuthorizationServerTokenServices tokenServices,
50  			AuthorizationCodeServices authorizationCodeServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
51  		this(tokenServices, authorizationCodeServices, clientDetailsService, requestFactory, GRANT_TYPE);
52  	}
53  
54  	protected AuthorizationCodeTokenGranter(AuthorizationServerTokenServices tokenServices, AuthorizationCodeServices authorizationCodeServices,
55  			ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
56  		super(tokenServices, clientDetailsService, requestFactory, grantType);
57  		this.authorizationCodeServices = authorizationCodeServices;
58  	}
59  
60  	@Override
61  	protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
62  
63  		Map<String, String> parameters = tokenRequest.getRequestParameters();
64  		String authorizationCode = parameters.get("code");
65  		String redirectUri = parameters.get(OAuth2Utils.REDIRECT_URI);
66  
67  		if (authorizationCode == null) {
68  			throw new InvalidRequestException("An authorization code must be supplied.");
69  		}
70  
71  		OAuth2Authentication storedAuth = authorizationCodeServices.consumeAuthorizationCode(authorizationCode);
72  		if (storedAuth == null) {
73  			throw new InvalidGrantException("Invalid authorization code: " + authorizationCode);
74  		}
75  
76  		OAuth2Request pendingOAuth2Request = storedAuth.getOAuth2Request();
77  		// https://jira.springsource.org/browse/SECOAUTH-333
78  		// This might be null, if the authorization was done without the redirect_uri parameter
79  		String redirectUriApprovalParameter = pendingOAuth2Request.getRequestParameters().get(
80  				OAuth2Utils.REDIRECT_URI);
81  
82  		if ((redirectUri != null || redirectUriApprovalParameter != null)
83  				&& !pendingOAuth2Request.getRedirectUri().equals(redirectUri)) {
84  			throw new RedirectMismatchException("Redirect URI mismatch.");
85  		}
86  
87  		String pendingClientId = pendingOAuth2Request.getClientId();
88  		String clientId = tokenRequest.getClientId();
89  		if (clientId != null && !clientId.equals(pendingClientId)) {
90  			// just a sanity check.
91  			throw new InvalidClientException("Client ID mismatch");
92  		}
93  
94  		// Secret is not required in the authorization request, so it won't be available
95  		// in the pendingAuthorizationRequest. We do want to check that a secret is provided
96  		// in the token request, but that happens elsewhere.
97  
98  		Map<String, String> combinedParameters = new HashMap<String, String>(pendingOAuth2Request
99  				.getRequestParameters());
100 		// Combine the parameters adding the new ones last so they override if there are any clashes
101 		combinedParameters.putAll(parameters);
102 		
103 		// Make a new stored request with the combined parameters
104 		OAuth2Request finalStoredOAuth2Request = pendingOAuth2Request.createOAuth2Request(combinedParameters);
105 		
106 		Authentication userAuth = storedAuth.getUserAuthentication();
107 		
108 		return new OAuth2Authentication(finalStoredOAuth2Request, userAuth);
109 
110 	}
111 
112 }