1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.security.oauth2.client.token;
17
18 import java.util.Collections;
19 import java.util.List;
20
21 import org.springframework.security.access.AccessDeniedException;
22 import org.springframework.security.authentication.AnonymousAuthenticationToken;
23 import org.springframework.security.authentication.InsufficientAuthenticationException;
24 import org.springframework.security.core.Authentication;
25 import org.springframework.security.core.context.SecurityContextHolder;
26 import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
27 import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
28 import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
29 import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
30 import org.springframework.security.oauth2.common.OAuth2AccessToken;
31 import org.springframework.security.oauth2.common.OAuth2RefreshToken;
32 import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
33
34
35
36
37
38
39
40
41
42 public class AccessTokenProviderChain extends OAuth2AccessTokenSupport
43 implements AccessTokenProvider {
44
45 private final List<AccessTokenProvider> chain;
46
47 private ClientTokenServices clientTokenServices;
48
49 public AccessTokenProviderChain(List<? extends AccessTokenProvider> chain) {
50 this.chain = chain == null ? Collections.<AccessTokenProvider> emptyList()
51 : Collections.unmodifiableList(chain);
52 }
53
54
55
56
57
58
59 public void setClientTokenServices(ClientTokenServices clientTokenServices) {
60 this.clientTokenServices = clientTokenServices;
61 }
62
63 public boolean supportsResource(OAuth2ProtectedResourceDetails resource) {
64 for (AccessTokenProvider tokenProvider : chain) {
65 if (tokenProvider.supportsResource(resource)) {
66 return true;
67 }
68 }
69 return false;
70 }
71
72 public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource) {
73 for (AccessTokenProvider tokenProvider : chain) {
74 if (tokenProvider.supportsRefresh(resource)) {
75 return true;
76 }
77 }
78 return false;
79 }
80
81 public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails resource,
82 AccessTokenRequest request)
83 throws UserRedirectRequiredException, AccessDeniedException {
84
85 OAuth2AccessToken accessToken = null;
86 OAuth2AccessToken existingToken = null;
87 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
88
89 if (auth instanceof AnonymousAuthenticationToken) {
90 if (!resource.isClientOnly()) {
91 throw new InsufficientAuthenticationException(
92 "Authentication is required to obtain an access token (anonymous not allowed)");
93 }
94 }
95
96 if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) {
97 existingToken = request.getExistingToken();
98 if (existingToken == null && clientTokenServices != null) {
99 existingToken = clientTokenServices.getAccessToken(resource, auth);
100 }
101
102 if (existingToken != null) {
103 if (existingToken.isExpired()) {
104 if (clientTokenServices != null) {
105 clientTokenServices.removeAccessToken(resource, auth);
106 }
107 OAuth2RefreshToken refreshToken = existingToken.getRefreshToken();
108 if (refreshToken != null && !resource.isClientOnly()) {
109 accessToken = refreshAccessToken(resource, refreshToken, request);
110 }
111 }
112 else {
113 accessToken = existingToken;
114 }
115 }
116 }
117
118
119 if (accessToken == null) {
120
121 accessToken = obtainNewAccessTokenInternal(resource, request);
122
123 if (accessToken == null) {
124 throw new IllegalStateException(
125 "An OAuth 2 access token must be obtained or an exception thrown.");
126 }
127 }
128
129 if (clientTokenServices != null
130 && (resource.isClientOnly() || auth != null && auth.isAuthenticated())) {
131 clientTokenServices.saveAccessToken(resource, auth, accessToken);
132 }
133
134 return accessToken;
135 }
136
137 protected OAuth2AccessToken obtainNewAccessTokenInternal(
138 OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
139 throws UserRedirectRequiredException, AccessDeniedException {
140
141 if (request.isError()) {
142
143 throw OAuth2Exception.valueOf(request.toSingleValueMap());
144 }
145
146 for (AccessTokenProvider tokenProvider : chain) {
147 if (tokenProvider.supportsResource(details)) {
148 return tokenProvider.obtainAccessToken(details, request);
149 }
150 }
151
152 throw new OAuth2AccessDeniedException(
153 "Unable to obtain a new access token for resource '" + details.getId()
154 + "'. The provider manager is not configured to support it.",
155 details);
156 }
157
158
159
160
161
162
163
164
165
166 public OAuth2AccessToken refreshAccessToken(OAuth2ProtectedResourceDetails resource,
167 OAuth2RefreshToken refreshToken, AccessTokenRequest request)
168 throws UserRedirectRequiredException {
169 for (AccessTokenProvider tokenProvider : chain) {
170 if (tokenProvider.supportsRefresh(resource)) {
171 DefaultOAuth2AccessToken refreshedAccessToken = new DefaultOAuth2AccessToken(
172 tokenProvider.refreshAccessToken(resource, refreshToken,
173 request));
174 if (refreshedAccessToken.getRefreshToken() == null) {
175
176 refreshedAccessToken.setRefreshToken(refreshToken);
177 }
178 return refreshedAccessToken;
179 }
180 }
181 throw new OAuth2AccessDeniedException(
182 "Unable to obtain a new access token for resource '" + resource.getId()
183 + "'. The provider manager is not configured to support it.",
184 resource);
185 }
186
187 }