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.authentication;
14  
15  import java.util.Collection;
16  import java.util.Set;
17  
18  import org.springframework.beans.factory.InitializingBean;
19  import org.springframework.security.authentication.AuthenticationManager;
20  import org.springframework.security.core.Authentication;
21  import org.springframework.security.core.AuthenticationException;
22  import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
23  import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
24  import org.springframework.security.oauth2.provider.AuthorizationRequest;
25  import org.springframework.security.oauth2.provider.ClientDetails;
26  import org.springframework.security.oauth2.provider.ClientDetailsService;
27  import org.springframework.security.oauth2.provider.ClientRegistrationException;
28  import org.springframework.security.oauth2.provider.OAuth2Authentication;
29  import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
30  import org.springframework.util.Assert;
31  
32  /**
33   * An {@link AuthenticationManager} for OAuth2 protected resources.
34   * 
35   * @author Dave Syer
36   * 
37   */
38  public class OAuth2AuthenticationManager implements AuthenticationManager, InitializingBean {
39  
40  	private ResourceServerTokenServices tokenServices;
41  
42  	private ClientDetailsService clientDetailsService;
43  
44  	private String resourceId;
45  
46  	public void setResourceId(String resourceId) {
47  		this.resourceId = resourceId;
48  	}
49  
50  	public void setClientDetailsService(ClientDetailsService clientDetailsService) {
51  		this.clientDetailsService = clientDetailsService;
52  	}
53  
54  	/**
55  	 * @param tokenServices the tokenServices to set
56  	 */
57  	public void setTokenServices(ResourceServerTokenServices tokenServices) {
58  		this.tokenServices = tokenServices;
59  	}
60  
61  	public void afterPropertiesSet() {
62  		Assert.state(tokenServices != null, "TokenServices are required");
63  	}
64  
65  	/**
66  	 * Expects the incoming authentication request to have a principal value that is an access token value (e.g. from an
67  	 * authorization header). Loads an authentication from the {@link ResourceServerTokenServices} and checks that the
68  	 * resource id is contained in the {@link AuthorizationRequest} (if one is specified). Also copies authentication
69  	 * details over from the input to the output (e.g. typically so that the access token value and request details can
70  	 * be reported later).
71  	 * 
72  	 * @param authentication an authentication request containing an access token value as the principal
73  	 * @return an {@link OAuth2Authentication}
74  	 * 
75  	 * @see org.springframework.security.authentication.AuthenticationManager#authenticate(org.springframework.security.core.Authentication)
76  	 */
77  	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
78  
79  		if (authentication == null) {
80  			throw new InvalidTokenException("Invalid token (token not found)");
81  		}
82  		String token = (String) authentication.getPrincipal();
83  		OAuth2Authentication auth = tokenServices.loadAuthentication(token);
84  		if (auth == null) {
85  			throw new InvalidTokenException("Invalid token: " + token);
86  		}
87  
88  		Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds();
89  		if (resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {
90  			throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + resourceId + ")");
91  		}
92  
93  		checkClientDetails(auth);
94  
95  		if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
96  			OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
97  			// Guard against a cached copy of the same details
98  			if (!details.equals(auth.getDetails())) {
99  				// Preserve the authentication details from the one loaded by token services
100 				details.setDecodedDetails(auth.getDetails());
101 			}
102 		}
103 		auth.setDetails(authentication.getDetails());
104 		auth.setAuthenticated(true);
105 		return auth;
106 
107 	}
108 
109 	private void checkClientDetails(OAuth2Authentication auth) {
110 		if (clientDetailsService != null) {
111 			ClientDetails client;
112 			try {
113 				client = clientDetailsService.loadClientByClientId(auth.getOAuth2Request().getClientId());
114 			}
115 			catch (ClientRegistrationException e) {
116 				throw new OAuth2AccessDeniedException("Invalid token contains invalid client id");
117 			}
118 			Set<String> allowed = client.getScope();
119 			for (String scope : auth.getOAuth2Request().getScope()) {
120 				if (!allowed.contains(scope)) {
121 					throw new OAuth2AccessDeniedException(
122 							"Invalid token contains disallowed scope (" + scope + ") for this client");
123 				}
124 			}
125 		}
126 	}
127 
128 }