View Javadoc
1   /*
2    * Copyright 2006-2011 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5    * the License. You may obtain a copy of the License at
6    * 
7    * https://www.apache.org/licenses/LICENSE-2.0
8    * 
9    * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10   * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11   * specific language governing permissions and limitations under the License.
12   */
13  package org.springframework.security.oauth2.provider.request;
14  
15  import java.util.Collections;
16  import java.util.LinkedHashSet;
17  import java.util.Map;
18  import java.util.Set;
19  
20  import org.springframework.security.core.authority.AuthorityUtils;
21  import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
22  import org.springframework.security.oauth2.common.util.OAuth2Utils;
23  import org.springframework.security.oauth2.provider.AuthorizationRequest;
24  import org.springframework.security.oauth2.provider.ClientDetails;
25  import org.springframework.security.oauth2.provider.ClientDetailsService;
26  import org.springframework.security.oauth2.provider.DefaultSecurityContextAccessor;
27  import org.springframework.security.oauth2.provider.OAuth2Request;
28  import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
29  import org.springframework.security.oauth2.provider.SecurityContextAccessor;
30  import org.springframework.security.oauth2.provider.TokenRequest;
31  
32  /**
33   * Default implementation of {@link OAuth2RequestFactory} which initializes fields from the parameters map, validates
34   * grant types and scopes, and fills in scopes with the default values from the client if they are missing.
35   * 
36   * @author Dave Syer
37   * @author Amanda Anganes
38   * 
39   */
40  public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
41  
42  	private final ClientDetailsService clientDetailsService;
43  
44  	private SecurityContextAccessor securityContextAccessor = new DefaultSecurityContextAccessor();
45  
46  	private boolean checkUserScopes = false;
47  
48  	public DefaultOAuth2RequestFactory(ClientDetailsService clientDetailsService) {
49  		this.clientDetailsService = clientDetailsService;
50  	}
51  
52  	/**
53  	 * @param securityContextAccessor the security context accessor to set
54  	 */
55  	public void setSecurityContextAccessor(SecurityContextAccessor securityContextAccessor) {
56  		this.securityContextAccessor = securityContextAccessor;
57  	}
58  
59  	/**
60  	 * Flag to indicate that scopes should be interpreted as valid authorities. No scopes will be granted to a user
61  	 * unless they are permitted as a granted authority to that user.
62  	 * 
63  	 * @param checkUserScopes the checkUserScopes to set (default false)
64  	 */
65  	public void setCheckUserScopes(boolean checkUserScopes) {
66  		this.checkUserScopes = checkUserScopes;
67  	}
68  
69  	public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) {
70  
71  		String clientId = authorizationParameters.get(OAuth2Utils.CLIENT_ID);
72  		String state = authorizationParameters.get(OAuth2Utils.STATE);
73  		String redirectUri = authorizationParameters.get(OAuth2Utils.REDIRECT_URI);
74  		Set<String> responseTypes = OAuth2Utils.parseParameterList(authorizationParameters
75  				.get(OAuth2Utils.RESPONSE_TYPE));
76  
77  		Set<String> scopes = extractScopes(authorizationParameters, clientId);
78  		
79  		AuthorizationRequest request = new AuthorizationRequest(authorizationParameters,
80  				Collections.<String, String> emptyMap(), clientId, scopes, null, null, false, state, redirectUri,
81  				responseTypes);
82  
83  		ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);		
84  		request.setResourceIdsAndAuthoritiesFromClientDetails(clientDetails);
85  
86  		return request;
87  
88  	}
89  
90  	public OAuth2Request createOAuth2Request(AuthorizationRequest request) {
91  		return request.createOAuth2Request();
92  	}
93  
94  	public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
95  
96  		String clientId = requestParameters.get(OAuth2Utils.CLIENT_ID);
97  		if (clientId == null) {
98  			// if the clientId wasn't passed in in the map, we add pull it from the authenticated client object
99  			clientId = authenticatedClient.getClientId();
100 		}
101 		else {
102 			// otherwise, make sure that they match
103 			if (!clientId.equals(authenticatedClient.getClientId())) {
104 				throw new InvalidClientException("Given client ID does not match authenticated client");
105 			}
106 		}
107 		String grantType = requestParameters.get(OAuth2Utils.GRANT_TYPE);
108 
109 		Set<String> scopes = extractScopes(requestParameters, clientId);
110 		TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scopes, grantType);
111 
112 		return tokenRequest;
113 	}
114 
115 	public TokenRequest createTokenRequest(AuthorizationRequest authorizationRequest, String grantType) {
116 		TokenRequest tokenRequest = new TokenRequest(authorizationRequest.getRequestParameters(),
117 				authorizationRequest.getClientId(), authorizationRequest.getScope(), grantType);
118 		return tokenRequest;
119 	}
120 
121 	public OAuth2Request createOAuth2Request(ClientDetails client, TokenRequest tokenRequest) {
122 		return tokenRequest.createOAuth2Request(client);
123 	}
124 
125 	private Set<String> extractScopes(Map<String, String> requestParameters, String clientId) {
126 		Set<String> scopes = OAuth2Utils.parseParameterList(requestParameters.get(OAuth2Utils.SCOPE));
127 		ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
128 
129 		if ((scopes == null || scopes.isEmpty())) {
130 			// If no scopes are specified in the incoming data, use the default values registered with the client
131 			// (the spec allows us to choose between this option and rejecting the request completely, so we'll take the
132 			// least obnoxious choice as a default).
133 			scopes = clientDetails.getScope();
134 		}
135 
136 		if (checkUserScopes) {
137 			scopes = checkUserScopes(scopes, clientDetails);
138 		}
139 		return scopes;
140 	}
141 
142 	private Set<String> checkUserScopes(Set<String> scopes, ClientDetails clientDetails) {
143 		if (!securityContextAccessor.isUser()) {
144 			return scopes;
145 		}
146 		Set<String> result = new LinkedHashSet<String>();
147 		Set<String> authorities = AuthorityUtils.authorityListToSet(securityContextAccessor.getAuthorities());
148 		for (String scope : scopes) {
149 			if (authorities.contains(scope) || authorities.contains(scope.toUpperCase())
150 					|| authorities.contains("ROLE_" + scope.toUpperCase())) {
151 				result.add(scope);
152 			}
153 		}
154 		return result;
155 	}
156 
157 }