/** * ============================================================================= * * 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 java.util.Date; import java.util.HashSet; import java.util.Set; import javax.annotation.Resource; import org.orcid.core.constants.OrcidOauth2Constants; import org.orcid.core.manager.ClientDetailsEntityCacheManager; import org.orcid.core.oauth.service.OrcidOAuth2RequestValidator; import org.orcid.jaxb.model.message.ScopePathType; import org.orcid.persistence.dao.OrcidOauth2TokenDetailDao; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.OrcidOauth2TokenDetail; import org.orcid.pojo.ajaxForm.PojoUtil; import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.TokenRequest; /** * @author Angel Montenegro */ public class OrcidRefreshTokenChecker { @Resource private ClientDetailsEntityCacheManager clientDetailsEntityCacheManager; @Resource private OrcidOAuth2RequestValidator orcidOAuth2RequestValidator; @Resource private OrcidOauth2TokenDetailDao orcidOauth2TokenDetailDao; public void validateRequest(String grantType, TokenRequest tokenRequest, Long requestTimeInMillis) { String authorization = tokenRequest.getRequestParameters().get(OrcidOauth2Constants.AUTHORIZATION); String clientId = tokenRequest.getClientId(); String scopes = tokenRequest.getRequestParameters().get(OAuth2Utils.SCOPE); Long expireIn = tokenRequest.getRequestParameters().containsKey(OrcidOauth2Constants.EXPIRES_IN) ? Long.valueOf(tokenRequest.getRequestParameters().get(OrcidOauth2Constants.EXPIRES_IN)) : 0L; String refreshToken = tokenRequest.getRequestParameters().get(OrcidOauth2Constants.REFRESH_TOKEN); OrcidOauth2TokenDetail token = orcidOauth2TokenDetailDao.findByTokenValue(authorization); // Verify the token belongs to this client if (!clientId.equals(token.getClientDetailsId())) { throw new IllegalArgumentException("This token doesnt belong to the given client"); } // Verify client is enabled ClientDetailsEntity clientDetails = clientDetailsEntityCacheManager.retrieve(clientId); orcidOAuth2RequestValidator.validateClientIsEnabled(clientDetails); // Verify the token is not expired if (token.getTokenExpiration() != null) { if (token.getTokenExpiration().before(new Date())) { throw new InvalidTokenException("Access token expired: " + authorization); } } // Verify access token and refresh token are linked if (!refreshToken.equals(token.getRefreshTokenValue())) { throw new InvalidTokenException("Token and refresh token does not match"); } // Verify the token is not disabled if (token.getTokenDisabled() != null && token.getTokenDisabled()) { throw new InvalidTokenException("Parent token is disabled"); } // Verify scopes are not wider than the token scopes if (PojoUtil.isEmpty(scopes)) { scopes = token.getScope(); } else { Set<ScopePathType> requiredScopes = ScopePathType.getScopesFromSpaceSeparatedString(scopes); Set<ScopePathType> simpleTokenScopes = ScopePathType.getScopesFromSpaceSeparatedString(token.getScope()); // This collection contains all tokens that should be allowed given // the scopes that the parent token contains Set<ScopePathType> combinedTokenScopes = new HashSet<ScopePathType>(); for (ScopePathType scope : simpleTokenScopes) { combinedTokenScopes.addAll(scope.combined()); } // Check that all requiredScopes are included in the list of // combinedTokenScopes for (ScopePathType scope : requiredScopes) { if (!combinedTokenScopes.contains(scope)) { throw new InvalidScopeException("The given scope '" + scope.value() + "' is not allowed for the parent token"); } } } // Validate the expiration for the new token is no later than the parent // token expiration. long parentTokenExpiration = token.getTokenExpiration() == null ? System.currentTimeMillis() : token.getTokenExpiration().getTime(); if (expireIn > parentTokenExpiration) { throw new IllegalArgumentException("Token expiration can't be after " + token.getTokenExpiration()); } } }