/** * ============================================================================= * * ORCID (R) Open Source * http://orcid.org * * Copyright (c) 2012-2014 ORCID, Inc. * Licensed under an MIT-Style License (MIT) * http://orcid.org/open-source-license * * This copyright and license information (including a link to the full license) * shall be included in its entirety in all copies or substantial portion of * the software. * * ============================================================================= */ package org.orcid.core.oauth; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Arrays; import java.util.HashSet; import javax.annotation.Resource; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.orcid.core.utils.SecurityContextTestUtils; import org.orcid.jaxb.model.message.ScopePathType; import org.orcid.persistence.dao.OrcidOauth2AuthoriziationCodeDetailDao; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.OrcidOauth2AuthoriziationCodeDetail; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.pojo.ajaxForm.PojoUtil; import org.orcid.test.DBUnitTest; import org.orcid.test.OrcidJUnit4ClassRunner; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.test.context.ContextConfiguration; import com.sun.jersey.core.util.MultivaluedMapImpl; @RunWith(OrcidJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:orcid-core-context.xml", "classpath:orcid-oauth2-common-config.xml" }) public class OrcidClientCredentialEndPointDelegatorTest extends DBUnitTest { private static final String CLIENT_ID_1 = "APP-5555555555555555"; private static final String USER_ORCID = "0000-0000-0000-0001"; @Resource private OrcidOauth2AuthoriziationCodeDetailDao orcidOauth2AuthoriziationCodeDetailDao; @Resource private OrcidClientCredentialEndPointDelegator orcidClientCredentialEndPointDelegator; @BeforeClass public static void initDBUnitData() throws Exception { initDBUnitData(Arrays.asList("/data/SecurityQuestionEntityData.xml", "/data/SubjectEntityData.xml", "/data/SourceClientDetailsEntityData.xml", "/data/ProfileEntityData.xml")); } @AfterClass public static void removeDBUnitData() throws Exception { removeDBUnitData(Arrays.asList("/data/ProfileEntityData.xml", "/data/SourceClientDetailsEntityData.xml", "/data/SubjectEntityData.xml", "/data/SecurityQuestionEntityData.xml")); } @After public void after() { SecurityContextHolder.clearContext(); } private OrcidOauth2AuthoriziationCodeDetail createAuthorizationCode(String value, String clientId, String redirectUri, boolean persistent, String ... scopes) { OrcidOauth2AuthoriziationCodeDetail authorizationCode = new OrcidOauth2AuthoriziationCodeDetail(); authorizationCode.setId(value); authorizationCode.setApproved(true); authorizationCode.setScopes(new HashSet<String>(Arrays.asList(scopes))); authorizationCode.setClientDetailsEntity(new ClientDetailsEntity(clientId)); authorizationCode.setPersistent(persistent); authorizationCode.setProfileEntity(new ProfileEntity(USER_ORCID)); authorizationCode.setRedirectUri(redirectUri); authorizationCode.setResourceIds(new HashSet<String>(Arrays.asList("orcid"))); authorizationCode.setAuthenticated(true); orcidOauth2AuthoriziationCodeDetailDao.persist(authorizationCode); return authorizationCode; } @Test public void generateAccessTokenTest() { SecurityContextTestUtils.setUpSecurityContextForClientOnly(CLIENT_ID_1, ScopePathType.ACTIVITIES_UPDATE, ScopePathType.READ_LIMITED); OrcidOauth2AuthoriziationCodeDetail authCode = createAuthorizationCode("code-1", CLIENT_ID_1, "http://www.APP-5555555555555555.com/redirect/oauth", true, "/activities/update"); MultivaluedMap<String, String> formParams = new MultivaluedMapImpl(); formParams.add("client_id", CLIENT_ID_1); formParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); formParams.add("grant_type", "authorization_code"); formParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); formParams.add("code", authCode.getId()); Response response = orcidClientCredentialEndPointDelegator.obtainOauth2Token(null, formParams); assertNotNull(response); assertNotNull(response.getEntity()); DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) response.getEntity(); assertNotNull(token); assertTrue(!PojoUtil.isEmpty(token.getValue())); assertNotNull(token.getRefreshToken()); assertTrue(!PojoUtil.isEmpty(token.getRefreshToken().getValue())); } @Test public void generateClientCredentialsAccessTokenTest() { SecurityContextTestUtils.setUpSecurityContextForClientOnly(CLIENT_ID_1, ScopePathType.ACTIVITIES_UPDATE, ScopePathType.READ_LIMITED); MultivaluedMap<String, String> formParams = new MultivaluedMapImpl(); formParams.add("client_id", CLIENT_ID_1); formParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); formParams.add("grant_type", "client_credentials"); formParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); formParams.add("scope", "/orcid-profile/create"); Response response = orcidClientCredentialEndPointDelegator.obtainOauth2Token(null, formParams); assertNotNull(response); assertNotNull(response.getEntity()); DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) response.getEntity(); assertNotNull(token); assertTrue(!PojoUtil.isEmpty(token.getValue())); assertNotNull(token.getRefreshToken()); assertTrue(!PojoUtil.isEmpty(token.getRefreshToken().getValue())); } @Test(expected = InvalidScopeException.class) public void generateClientCredentialsAccessTokenWithInvalidTokenTest() { SecurityContextTestUtils.setUpSecurityContextForClientOnly(CLIENT_ID_1, ScopePathType.ACTIVITIES_UPDATE); MultivaluedMap<String, String> formParams = new MultivaluedMapImpl(); formParams.add("client_id", CLIENT_ID_1); formParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); formParams.add("grant_type", "client_credentials"); formParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); formParams.add("scope", "/activities/update"); orcidClientCredentialEndPointDelegator.obtainOauth2Token(null, formParams); fail(); } @Test public void generateRefreshTokenTest() { //Generate the access token SecurityContextTestUtils.setUpSecurityContextForClientOnly(CLIENT_ID_1, ScopePathType.ACTIVITIES_UPDATE, ScopePathType.READ_LIMITED); OrcidOauth2AuthoriziationCodeDetail authCode = createAuthorizationCode("code-1", CLIENT_ID_1, "http://www.APP-5555555555555555.com/redirect/oauth", true, "/activities/update"); MultivaluedMap<String, String> formParams = new MultivaluedMapImpl(); formParams.add("client_id", CLIENT_ID_1); formParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); formParams.add("grant_type", "authorization_code"); formParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); formParams.add("code", authCode.getId()); Response response = orcidClientCredentialEndPointDelegator.obtainOauth2Token(null, formParams); assertNotNull(response); assertNotNull(response.getEntity()); DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) response.getEntity(); assertNotNull(token); assertTrue(!PojoUtil.isEmpty(token.getValue())); assertNotNull(token.getRefreshToken()); assertTrue(!PojoUtil.isEmpty(token.getRefreshToken().getValue())); //Generate the refresh token MultivaluedMap<String, String> refreshTokenformParams = new MultivaluedMapImpl(); refreshTokenformParams.add("client_id", CLIENT_ID_1); refreshTokenformParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); refreshTokenformParams.add("grant_type", "refresh_token"); refreshTokenformParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); refreshTokenformParams.add("refresh_token", token.getRefreshToken().getValue()); String authorization = "bearer " + token.getValue(); Response refreshTokenResponse = orcidClientCredentialEndPointDelegator.obtainOauth2Token(authorization, refreshTokenformParams); assertNotNull(refreshTokenResponse); assertNotNull(refreshTokenResponse.getEntity()); DefaultOAuth2AccessToken refreshToken = (DefaultOAuth2AccessToken) refreshTokenResponse.getEntity(); assertNotNull(refreshToken); assertTrue(!PojoUtil.isEmpty(refreshToken.getValue())); assertNotNull(refreshToken.getRefreshToken()); assertTrue(!PojoUtil.isEmpty(refreshToken.getRefreshToken().getValue())); //Assert that both tokens expires at the same time assertEquals(token.getExpiration(), refreshToken.getExpiration()); //Try to generate another one, and fail, because parent token was disabled try{ orcidClientCredentialEndPointDelegator.obtainOauth2Token(authorization, refreshTokenformParams); } catch (InvalidTokenException e) { assertTrue(e.getMessage().contains("Parent token is disabled")); } } @Test public void generateRefreshTokenThatExpireAfterParentTokenTest() { //Generate the access token SecurityContextTestUtils.setUpSecurityContextForClientOnly(CLIENT_ID_1, ScopePathType.ACTIVITIES_UPDATE, ScopePathType.READ_LIMITED); OrcidOauth2AuthoriziationCodeDetail authCode = createAuthorizationCode("code-1", CLIENT_ID_1, "http://www.APP-5555555555555555.com/redirect/oauth", false, "/activities/update"); MultivaluedMap<String, String> formParams = new MultivaluedMapImpl(); formParams.add("client_id", CLIENT_ID_1); formParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); formParams.add("grant_type", "authorization_code"); formParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); formParams.add("code", authCode.getId()); Response response = orcidClientCredentialEndPointDelegator.obtainOauth2Token(null, formParams); assertNotNull(response); assertNotNull(response.getEntity()); DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) response.getEntity(); assertNotNull(token); assertTrue(!PojoUtil.isEmpty(token.getValue())); assertNotNull(token.getRefreshToken()); assertTrue(!PojoUtil.isEmpty(token.getRefreshToken().getValue())); //Generate the refresh token that expires after parent token MultivaluedMap<String, String> refreshTokenformParams = new MultivaluedMapImpl(); refreshTokenformParams.add("client_id", CLIENT_ID_1); refreshTokenformParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); refreshTokenformParams.add("grant_type", "refresh_token"); refreshTokenformParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); refreshTokenformParams.add("refresh_token", token.getRefreshToken().getValue()); refreshTokenformParams.add("expires_in", String.valueOf(2*60*60)); String authorization = "bearer " + token.getValue(); try { orcidClientCredentialEndPointDelegator.obtainOauth2Token(authorization, refreshTokenformParams); } catch(IllegalArgumentException e) { assertTrue(e.getMessage().contains("Token expiration can't be after")); } //Try again with a valid expiration value refreshTokenformParams = new MultivaluedMapImpl(); refreshTokenformParams.add("client_id", CLIENT_ID_1); refreshTokenformParams.add("client_secret", "DhkFj5EI0qp6GsUKi55Vja+h+bsaKpBx"); refreshTokenformParams.add("grant_type", "refresh_token"); refreshTokenformParams.add("redirect_uri", "http://www.APP-5555555555555555.com/redirect/oauth"); refreshTokenformParams.add("refresh_token", token.getRefreshToken().getValue()); refreshTokenformParams.add("expires_in", String.valueOf(60*30)); response = orcidClientCredentialEndPointDelegator.obtainOauth2Token(authorization, refreshTokenformParams); assertNotNull(response); assertNotNull(response.getEntity()); DefaultOAuth2AccessToken refreshToken = (DefaultOAuth2AccessToken) response.getEntity(); assertNotNull(refreshToken); assertTrue(!PojoUtil.isEmpty(refreshToken.getValue())); assertNotNull(refreshToken.getRefreshToken()); assertTrue(!PojoUtil.isEmpty(refreshToken.getRefreshToken().getValue())); assertTrue(token.getExpiration().getTime() > refreshToken.getExpiration().getTime()); } }