View Javadoc
1   /*
2    * Copyright 2013-2014 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  
14  package org.springframework.security.oauth2.provider.token;
15  
16  import static org.junit.Assert.assertEquals;
17  import static org.junit.Assert.assertFalse;
18  import static org.junit.Assert.assertNotNull;
19  import static org.junit.Assert.assertTrue;
20  
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Date;
25  import java.util.LinkedHashSet;
26  import java.util.concurrent.atomic.AtomicBoolean;
27  
28  import org.junit.Before;
29  import org.junit.Test;
30  import org.springframework.security.authentication.AbstractAuthenticationToken;
31  import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken;
32  import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
33  import org.springframework.security.oauth2.common.OAuth2AccessToken;
34  import org.springframework.security.oauth2.common.OAuth2RefreshToken;
35  import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
36  import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
37  import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
38  import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
39  import org.springframework.security.oauth2.provider.ClientDetails;
40  import org.springframework.security.oauth2.provider.ClientDetailsService;
41  import org.springframework.security.oauth2.provider.ClientRegistrationException;
42  import org.springframework.security.oauth2.provider.OAuth2Authentication;
43  import org.springframework.security.oauth2.provider.RequestTokenFactory;
44  import org.springframework.security.oauth2.provider.TokenRequest;
45  import org.springframework.security.oauth2.provider.client.BaseClientDetails;
46  
47  /**
48   * @author Dave Syer
49   *
50   */
51  public abstract class AbstractDefaultTokenServicesTests {
52  
53  	private DefaultTokenServices services;
54  
55  	private TokenStore tokenStore;
56  
57  	@Before
58  	public void setUp() throws Exception {
59  		tokenStore = createTokenStore();
60  		services = new DefaultTokenServices();
61  		configureTokenServices(services);
62  	}
63  
64  	@Test
65  	public void testClientSpecificRefreshTokenExpiry() throws Exception {
66  		getTokenServices().setRefreshTokenValiditySeconds(1000);
67  		getTokenServices().setClientDetailsService(new ClientDetailsService() {
68  			public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception {
69  				BaseClientDetails client = new BaseClientDetails();
70  				client.setRefreshTokenValiditySeconds(100);
71  				client.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "refresh_token"));
72  				return client;
73  			}
74  		});
75  		OAuth2AccessToken accessToken = getTokenServices().createAccessToken(createAuthentication());
76  		DefaultExpiringOAuth2RefreshToken refreshToken = (DefaultExpiringOAuth2RefreshToken) accessToken
77  				.getRefreshToken();
78  		Date expectedExpiryDate = new Date(System.currentTimeMillis() + 102 * 1000L);
79  		assertTrue(expectedExpiryDate.after(refreshToken.getExpiration()));
80  	}
81  
82  	@Test(expected = InvalidTokenException.class)
83  	public void testClientInvalidated() throws Exception {
84  		final AtomicBoolean deleted = new AtomicBoolean();
85  		getTokenServices().setClientDetailsService(new ClientDetailsService() {
86  			public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception {
87  				if (deleted.get()) {
88  					throw new ClientRegistrationException("No such client: " + clientId);
89  				}
90  				BaseClientDetails client = new BaseClientDetails();
91  				client.setRefreshTokenValiditySeconds(100);
92  				client.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "refresh_token"));
93  				return client;
94  			}
95  		});
96  		OAuth2AccessToken token = getTokenServices().createAccessToken(createAuthentication());
97  		deleted.set(true);
98  		OAuth2Authentication authentication = getTokenServices().loadAuthentication(token.getValue());
99  		assertNotNull(authentication.getOAuth2Request());
100 	}
101 
102 	@Test(expected = InvalidGrantException.class)
103 	public void testRefreshedTokenInvalidWithWrongClient() throws Exception {
104 		ExpiringOAuth2RefreshToken expectedExpiringRefreshToken = (ExpiringOAuth2RefreshToken) getTokenServices()
105 				.createAccessToken(createAuthentication()).getRefreshToken();
106 		TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "wrong"), "wrong", null,
107 				null);
108 		OAuth2AccessToken refreshedAccessToken = getTokenServices()
109 				.refreshAccessToken(expectedExpiringRefreshToken.getValue(), tokenRequest);
110 		assertEquals("[read]", refreshedAccessToken.getScope().toString());
111 	}
112 
113 	@Test
114 	public void testRefreshedTokenHasNarrowedScopes() throws Exception {
115 		ExpiringOAuth2RefreshToken expectedExpiringRefreshToken = (ExpiringOAuth2RefreshToken) getTokenServices()
116 				.createAccessToken(createAuthentication()).getRefreshToken();
117 		TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id",
118 				Collections.singleton("read"), null);
119 		OAuth2AccessToken refreshedAccessToken = getTokenServices()
120 				.refreshAccessToken(expectedExpiringRefreshToken.getValue(), tokenRequest);
121 		assertEquals("[read]", refreshedAccessToken.getScope().toString());
122 	}
123 
124 	@Test
125 	public void testRefreshTokenRequestHasRefreshFlag() throws Exception {
126 		ExpiringOAuth2RefreshToken expectedExpiringRefreshToken = (ExpiringOAuth2RefreshToken) getTokenServices()
127 				.createAccessToken(createAuthentication()).getRefreshToken();
128 		TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id",
129 				Collections.singleton("read"), null);
130 		final AtomicBoolean called = new AtomicBoolean(false);
131 		getTokenServices().setTokenEnhancer(new TokenEnhancer() {
132 			@Override
133 			public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
134 				assertTrue(authentication.getOAuth2Request().isRefresh());
135 				called.set(true);
136 				return accessToken;
137 			}
138 		});
139 		getTokenServices().refreshAccessToken(expectedExpiringRefreshToken.getValue(), tokenRequest);
140 		assertTrue(called.get());
141 	}
142 
143 	@Test
144 	public void testRefreshTokenNonExpiring() throws Exception {
145 		ClientDetailsService clientDetailsService = new InMemoryClientDetailsServiceBuilder().withClient("id")
146 				.refreshTokenValiditySeconds(0).authorizedGrantTypes("refresh_token").and().build();
147 		DefaultTokenServices tokenServices = getTokenServices();
148 		tokenServices.setClientDetailsService(clientDetailsService);
149 		OAuth2RefreshToken refreshToken = tokenServices.createAccessToken(createAuthentication())
150 				.getRefreshToken();
151 		assertNotNull(refreshToken);
152 		assertFalse(refreshToken instanceof ExpiringOAuth2RefreshToken);
153 	}
154 
155 	@Test
156 	public void testTokenRevoked() throws Exception {
157 		OAuth2Authentication authentication = createAuthentication();
158 		OAuth2AccessToken original = getTokenServices().createAccessToken(authentication);
159 		getTokenStore().removeAccessToken(original);
160 		assertEquals(0, getTokenStore().findTokensByClientId(authentication.getOAuth2Request().getClientId()).size());
161 	}
162 
163 	@Test
164 	public void testUnlimitedTokenExpiry() throws Exception {
165 		getTokenServices().setAccessTokenValiditySeconds(0);
166 		OAuth2AccessToken accessToken = getTokenServices().createAccessToken(createAuthentication());
167 		assertEquals(0, accessToken.getExpiresIn());
168 		assertEquals(null, accessToken.getExpiration());
169 	}
170 
171 	@Test
172 	public void testDefaultTokenExpiry() throws Exception {
173 		getTokenServices().setAccessTokenValiditySeconds(100);
174 		OAuth2AccessToken accessToken = getTokenServices().createAccessToken(createAuthentication());
175 		assertTrue(100 >= accessToken.getExpiresIn());
176 	}
177 
178 	@Test
179 	public void testClientSpecificTokenExpiry() throws Exception {
180 		getTokenServices().setAccessTokenValiditySeconds(1000);
181 		getTokenServices().setClientDetailsService(new ClientDetailsService() {
182 			public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception {
183 				BaseClientDetails client = new BaseClientDetails();
184 				client.setAccessTokenValiditySeconds(100);
185 				return client;
186 			}
187 		});
188 		OAuth2AccessToken accessToken = getTokenServices().createAccessToken(createAuthentication());
189 		assertTrue(100 >= accessToken.getExpiresIn());
190 	}
191 
192 	@Test
193 	public void testRefreshedTokenHasScopes() throws Exception {
194 		ExpiringOAuth2RefreshToken expectedExpiringRefreshToken = (ExpiringOAuth2RefreshToken) getTokenServices()
195 				.createAccessToken(createAuthentication()).getRefreshToken();
196 		TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id", null, null);
197 		OAuth2AccessToken refreshedAccessToken = getTokenServices()
198 				.refreshAccessToken(expectedExpiringRefreshToken.getValue(), tokenRequest);
199 		assertEquals("[read, write]", refreshedAccessToken.getScope().toString());
200 	}
201 
202 	@Test
203 	public void testRefreshedTokenNotExpiring() throws Exception {
204 		getTokenServices().setRefreshTokenValiditySeconds(0);
205 		OAuth2RefreshToken expectedExpiringRefreshToken = getTokenServices().createAccessToken(createAuthentication())
206 				.getRefreshToken();
207 		assertFalse(expectedExpiringRefreshToken instanceof DefaultExpiringOAuth2RefreshToken);
208 	}
209 
210 	@Test
211 	public void testRevokedTokenNotAvailable() throws Exception {
212 		OAuth2Authentication authentication = createAuthentication();
213 		OAuth2AccessToken token = getTokenServices().createAccessToken(authentication);
214 		getTokenServices().revokeToken(token.getValue());
215 		Collection<OAuth2AccessToken> tokens = getTokenStore().findTokensByClientIdAndUserName(
216 				authentication.getOAuth2Request().getClientId(), authentication.getUserAuthentication().getName());
217 		assertFalse(tokens.contains(token));
218 		assertTrue(tokens.isEmpty());
219 	}
220 
221 	protected void configureTokenServices(DefaultTokenServices services) throws Exception {
222 		services.setTokenStore(tokenStore);
223 		services.setSupportRefreshToken(true);
224 		services.afterPropertiesSet();
225 	}
226 
227 	protected abstract TokenStore createTokenStore();
228 
229 	protected OAuth2Authentication createAuthentication() {
230 		return new OAuth2Authentication(
231 				RequestTokenFactory.createOAuth2Request(null, "id", null, false,
232 						new LinkedHashSet<String>(Arrays.asList("read", "write")), null, null, null, null),
233 				new TestAuthentication("test2", false));
234 	}
235 
236 	protected TokenStore getTokenStore() {
237 		return tokenStore;
238 	}
239 
240 	protected DefaultTokenServices getTokenServices() {
241 		return services;
242 	}
243 
244 	protected static class TestAuthentication extends AbstractAuthenticationToken {
245 
246 		private static final long serialVersionUID = 1L;
247 
248 		private String principal;
249 
250 		public TestAuthentication(String name, boolean authenticated) {
251 			super(null);
252 			setAuthenticated(authenticated);
253 			this.principal = name;
254 		}
255 
256 		public Object getCredentials() {
257 			return null;
258 		}
259 
260 		public Object getPrincipal() {
261 			return this.principal;
262 		}
263 	}
264 
265 }