/* * ***************************************************************************** * Cloud Foundry * Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved. * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. * ***************************************************************************** */ package org.cloudfoundry.identity.uaa.oauth.token; import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication; import org.cloudfoundry.identity.uaa.oauth.UaaOauth2Authentication; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; import org.springframework.security.oauth2.common.exceptions.InvalidClientException; import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.OAuth2RequestFactory; import org.springframework.security.oauth2.provider.TokenRequest; import org.springframework.security.oauth2.provider.client.BaseClientDetails; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; import static org.cloudfoundry.identity.uaa.oauth.token.ClaimConstants.JTI; import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.GRANT_TYPE_REFRESH_TOKEN; import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.GRANT_TYPE_USER_TOKEN; import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.USER_TOKEN_REQUESTING_CLIENT_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.security.oauth2.common.util.OAuth2Utils.CLIENT_ID; import static org.springframework.security.oauth2.common.util.OAuth2Utils.GRANT_TYPE; public class UserTokenGranterTest { private UserTokenGranter granter; private AuthorizationServerTokenServices tokenServices; private ClientDetailsService clientDetailsService; private OAuth2RequestFactory requestFactory; private UaaOauth2Authentication authentication; private TokenRequest tokenRequest; private UaaAuthentication userAuthentication; private Map<String,String> requestParameters; private BaseClientDetails requestingClient; private BaseClientDetails receivingClient; private RevocableTokenProvisioning tokenStore; @Before public void setup() { tokenServices = mock(AuthorizationServerTokenServices.class); clientDetailsService = mock(ClientDetailsService.class); requestFactory = mock(OAuth2RequestFactory.class); authentication = mock(UaaOauth2Authentication.class); tokenStore = mock(RevocableTokenProvisioning.class); userAuthentication = mock(UaaAuthentication.class); granter = new UserTokenGranter( tokenServices, clientDetailsService, requestFactory, tokenStore ); SecurityContextHolder.getContext().setAuthentication(authentication); requestingClient = new BaseClientDetails("requestingId",null,"uaa.user",GRANT_TYPE_USER_TOKEN, null); receivingClient = new BaseClientDetails("receivingId",null,"test.scope",GRANT_TYPE_REFRESH_TOKEN, null); when(clientDetailsService.loadClientByClientId(eq(requestingClient.getClientId()))).thenReturn(requestingClient); when(clientDetailsService.loadClientByClientId(eq(receivingClient.getClientId()))).thenReturn(receivingClient); requestParameters = new HashMap<>(); requestParameters.put(USER_TOKEN_REQUESTING_CLIENT_ID, requestingClient.getClientId()); requestParameters.put(GRANT_TYPE, TokenConstants.GRANT_TYPE_USER_TOKEN); requestParameters.put(CLIENT_ID, receivingClient.getClientId()); tokenRequest = new PublicTokenRequest(); tokenRequest.setRequestParameters(requestParameters); } @After public void teardown() { SecurityContextHolder.clearContext(); } @Test(expected = InsufficientAuthenticationException.class) public void test_no_authentication() throws Exception { SecurityContextHolder.clearContext(); granter.validateRequest(tokenRequest); } @Test(expected = InsufficientAuthenticationException.class) public void test_not_authenticated() throws Exception { when(authentication.isAuthenticated()).thenReturn(false); granter.validateRequest(tokenRequest); } @Test(expected = InsufficientAuthenticationException.class) public void test_not_a_user_authentication() throws Exception { when(authentication.isAuthenticated()).thenReturn(true); when(authentication.getUserAuthentication()).thenReturn(null); granter.validateRequest(tokenRequest); } @Test(expected = InvalidGrantException.class) public void test_invalid_grant_type() throws Exception { missing_parameter(GRANT_TYPE); } @Test(expected = InvalidGrantException.class) public void test_requesting_client_id_missing() throws Exception { missing_parameter(USER_TOKEN_REQUESTING_CLIENT_ID); } @Test(expected = InvalidClientException.class) public void test_wrong_requesting_grant_type() { requestingClient.setAuthorizedGrantTypes(Arrays.asList("password")); missing_parameter("non existent"); } @Test(expected = InvalidClientException.class) public void test_wrong_receiving_grant_type() { receivingClient.setAuthorizedGrantTypes(Arrays.asList("password")); missing_parameter("non existent"); } @Test public void ensure_that_access_token_is_deleted_and_modified() { String tokenId = "access_token"; DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(tokenId); DefaultOAuth2RefreshToken refreshToken = new DefaultOAuth2RefreshToken("refresh_token"); Map<String,Object> info = new HashMap(token.getAdditionalInformation()); info.put(JTI, token.getValue()); token.setAdditionalInformation(info); token.setRefreshToken(refreshToken); token.setExpiration(new Date()); DefaultOAuth2AccessToken result = granter.prepareForSerialization(token); assertSame(token, result); assertEquals(refreshToken.getValue(), result.getAdditionalInformation().get(JTI)); assertNull(result.getValue()); verify(tokenStore).delete(eq(tokenId), anyInt()); } @Test public void ensure_client_gets_swapped() { granter = new UserTokenGranter( tokenServices, clientDetailsService, requestFactory, tokenStore ) { @Override protected DefaultOAuth2AccessToken prepareForSerialization(DefaultOAuth2AccessToken token) { return null; //override for testing } @Override protected Authentication validateRequest(TokenRequest request) { return userAuthentication; } }; granter.getAccessToken(requestingClient, tokenRequest); verify(clientDetailsService, times(1)).loadClientByClientId(eq(receivingClient.getClientId())); } @Test public void happy_day() { missing_parameter("non existent"); } protected void missing_parameter(String parameter) { tokenRequest.setClientId(receivingClient.getClientId()); when(authentication.isAuthenticated()).thenReturn(true); when(authentication.getUserAuthentication()).thenReturn(null); when(authentication.getUserAuthentication()).thenReturn(userAuthentication); when(userAuthentication.isAuthenticated()).thenReturn(true); requestParameters.remove(parameter); tokenRequest.setGrantType(requestParameters.get(GRANT_TYPE)); granter.validateRequest(tokenRequest); } public static class PublicTokenRequest extends TokenRequest { public PublicTokenRequest() { } } }