package org.springframework.security.oauth2.provider.token; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.Date; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.security.authentication.AccountExpiredException; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.RequestTokenFactory; import org.springframework.security.oauth2.provider.TokenRequest; import org.springframework.security.oauth2.provider.client.BaseClientDetails; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; import org.springframework.test.util.ReflectionTestUtils; /** * @author Ryan Heaton * @author Dave Syer * */ public class DefaultTokenServicesWithInMemoryTests extends AbstractPersistentDefaultTokenServicesTests { private InMemoryTokenStore tokenStore; @Rule public ExpectedException expected = ExpectedException.none(); @Test public void testExpiredToken() throws Exception { OAuth2Authentication expectedAuthentication = new OAuth2Authentication(RequestTokenFactory.createOAuth2Request( "id", false, Collections.singleton("read")), new TestAuthentication("test2", false)); DefaultOAuth2AccessToken firstAccessToken = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); // Make it expire (and rely on mutable state in volatile token store) firstAccessToken.setExpiration(new Date(System.currentTimeMillis() - 1000)); expected.expect(InvalidTokenException.class); expected.expectMessage("expired"); getTokenServices().loadAuthentication(firstAccessToken.getValue()); } @Test public void testExpiredRefreshToken() throws Exception { OAuth2Authentication expectedAuthentication = new OAuth2Authentication(RequestTokenFactory.createOAuth2Request( "id", false, Collections.singleton("read")), new TestAuthentication("test2", false)); DefaultOAuth2AccessToken firstAccessToken = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); assertNotNull(firstAccessToken.getRefreshToken()); // Make it expire (and rely on mutable state in volatile token store) ReflectionTestUtils.setField(firstAccessToken.getRefreshToken(), "expiration", new Date(System.currentTimeMillis() - 1000)); firstAccessToken.setExpiration(new Date(System.currentTimeMillis() - 1000)); expected.expect(InvalidTokenException.class); expected.expectMessage("refresh token (expired)"); TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id", null, null); getTokenServices().refreshAccessToken(firstAccessToken.getRefreshToken().getValue(), tokenRequest); } @Test public void testRefreshTokenWithUnauthenticatedUser() throws Exception { OAuth2Authentication expectedAuthentication = new OAuth2Authentication(RequestTokenFactory.createOAuth2Request( "id", false, Collections.singleton("read")), new TestAuthentication("test2", false)); getTokenServices().setAuthenticationManager(new AuthenticationManager() { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { throw new AccountExpiredException("Not valid"); } }); DefaultOAuth2AccessToken firstAccessToken = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); assertNotNull(firstAccessToken.getRefreshToken()); expected.expect(AccountExpiredException.class); TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id", null, null); getTokenServices().refreshAccessToken(firstAccessToken.getRefreshToken().getValue(), tokenRequest); } @Test public void testExpiredRefreshTokenIsRenewedWithNewAccessToken() throws Exception { OAuth2Authentication expectedAuthentication = new OAuth2Authentication(RequestTokenFactory.createOAuth2Request( "id", false, Collections.singleton("read")), new TestAuthentication("test2", false)); DefaultOAuth2AccessToken firstAccessToken = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); assertNotNull(firstAccessToken.getRefreshToken()); // Make it expire (and rely on mutable state in volatile token store) ReflectionTestUtils.setField(firstAccessToken.getRefreshToken(), "expiration", new Date(System.currentTimeMillis() - 1000)); firstAccessToken.setExpiration(new Date(System.currentTimeMillis() - 1000)); DefaultOAuth2AccessToken secondAccessToken = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); ExpiringOAuth2RefreshToken refreshToken = (ExpiringOAuth2RefreshToken) secondAccessToken.getRefreshToken(); assertNotNull(refreshToken); assertTrue(refreshToken.getExpiration().getTime() > System.currentTimeMillis()); } @Test public void testDifferentRefreshTokenMaintainsState() throws Exception { // create access token getTokenServices().setAccessTokenValiditySeconds(1); getTokenServices().setClientDetailsService(new ClientDetailsService() { public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception { BaseClientDetails client = new BaseClientDetails(); client.setAccessTokenValiditySeconds(1); client.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "refresh_token")); return client; } }); OAuth2Authentication expectedAuthentication = new OAuth2Authentication(RequestTokenFactory.createOAuth2Request( "id", false, Collections.singleton("read")), new TestAuthentication("test2", false)); DefaultOAuth2AccessToken firstAccessToken = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); OAuth2RefreshToken expectedExpiringRefreshToken = firstAccessToken.getRefreshToken(); // Make it expire (and rely on mutable state in volatile token store) firstAccessToken.setExpiration(new Date(System.currentTimeMillis() - 1000)); // create another access token OAuth2AccessToken secondAccessToken = getTokenServices().createAccessToken(expectedAuthentication); assertFalse("The new access token should be different", firstAccessToken.getValue().equals(secondAccessToken.getValue())); assertEquals("The new access token should have the same refresh token", expectedExpiringRefreshToken.getValue(), secondAccessToken.getRefreshToken().getValue()); // refresh access token with refresh token TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id", Collections.singleton("read"), null); getTokenServices().refreshAccessToken(expectedExpiringRefreshToken.getValue(), tokenRequest); assertEquals(1, getAccessTokenCount()); } @Test public void testNoRefreshTokenIfNotAuthorized() throws Exception { // create access token getTokenServices().setAccessTokenValiditySeconds(1); getTokenServices().setClientDetailsService(new ClientDetailsService() { public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception { BaseClientDetails client = new BaseClientDetails(); client.setAccessTokenValiditySeconds(1); client.setAuthorizedGrantTypes(Arrays.asList("authorization_code")); return client; } }); OAuth2Authentication expectedAuthentication = new OAuth2Authentication(RequestTokenFactory.createOAuth2Request( "id", false, Collections.singleton("read")), new TestAuthentication("test2", false)); DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) getTokenServices().createAccessToken( expectedAuthentication); assertNull(token.getRefreshToken()); } @Override protected TokenStore createTokenStore() { tokenStore = new InMemoryTokenStore(); return tokenStore; } @Override protected int getAccessTokenCount() { return tokenStore.getAccessTokenCount(); } @Override protected int getRefreshTokenCount() { return tokenStore.getRefreshTokenCount(); } }