/* * Copyright (c) 2013, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.oauth2.token.handlers.grant; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.base.IdentityException; import org.wso2.carbon.identity.oauth.cache.CacheKey; import org.wso2.carbon.identity.oauth.cache.OAuthCacheKey; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; /** * Implements the AuthorizationGrantHandler for the Grant Type : authorization_code. */ public class AuthorizationCodeGrantHandler extends AbstractAuthorizationGrantHandler { // This is used to keep the pre processed authorization code in the OAuthTokenReqMessageContext. private static final String AUTHZ_CODE = "AuthorizationCode"; private static Log log = LogFactory.getLog(AuthorizationCodeGrantHandler.class); @Override public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception { if(!super.validateGrant(tokReqMsgCtx)){ return false; } OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO = tokReqMsgCtx.getOauth2AccessTokenReqDTO(); String authorizationCode = oAuth2AccessTokenReqDTO.getAuthorizationCode(); String clientId = oAuth2AccessTokenReqDTO.getClientId(); AuthzCodeDO authzCodeDO = null; // if cache is enabled, check in the cache first. if (cacheEnabled) { OAuthCacheKey cacheKey = new OAuthCacheKey(OAuth2Util.buildCacheKeyStringForAuthzCode( clientId, authorizationCode)); authzCodeDO = (AuthzCodeDO) oauthCache.getValueFromCache(cacheKey); } if (log.isDebugEnabled()) { if (authzCodeDO != null) { log.debug("Authorization Code Info was available in cache for client id : " + clientId); } else { log.debug("Authorization Code Info was not available in cache for client id : " + clientId); } } // authz Code is not available in cache. check the database if (authzCodeDO == null) { authzCodeDO = tokenMgtDAO.validateAuthorizationCode(clientId, authorizationCode); } //Check whether it is a valid grant if (authzCodeDO == null) { if (log.isDebugEnabled()) { log.debug("Invalid access token request with " + "Client Id : " + clientId); } return false; } // Validate redirect_uri if it was presented in authorization request if (authzCodeDO.getCallbackUrl() != null && !authzCodeDO.getCallbackUrl().equals("")) { if (oAuth2AccessTokenReqDTO.getCallbackURI() == null) { if (log.isDebugEnabled()) { log.debug("Invalid access token request with " + "Client Id : " + clientId + "redirect_uri not present in request"); } return false; } else if (!oAuth2AccessTokenReqDTO.getCallbackURI().equals(authzCodeDO.getCallbackUrl())) { if (log.isDebugEnabled()) { log.debug("Invalid access token request with " + "Client Id : " + clientId + "redirect_uri does not match previously presented redirect_uri to authorization endpoint"); } return false; } } // Check whether the grant is expired long issuedTimeInMillis = authzCodeDO.getIssuedTime().getTime(); long validityPeriodInMillis = authzCodeDO.getValidityPeriod(); long timestampSkew = OAuthServerConfiguration.getInstance() .getTimeStampSkewInSeconds() * 1000; long currentTimeInMillis = System.currentTimeMillis(); // if authorization code is expired. if ((currentTimeInMillis - timestampSkew) > (issuedTimeInMillis + validityPeriodInMillis)) { if (log.isDebugEnabled()) { log.debug("Authorization Code is expired." + " Issued Time(ms) : " + issuedTimeInMillis + ", Validity Period : " + validityPeriodInMillis + ", Timestamp Skew : " + timestampSkew + ", Current Time : " + currentTimeInMillis); } // remove the authorization code from the database. tokenMgtDAO.expireAuthzCode(authorizationCode); if (log.isDebugEnabled()) { log.debug("Expired Authorization code" + " issued for client " + clientId + " was removed from the database."); } // remove the authorization code from the cache oauthCache.clearCacheEntry(new OAuthCacheKey( OAuth2Util.buildCacheKeyStringForAuthzCode(clientId, authorizationCode))); if (log.isDebugEnabled()) { log.debug("Expired Authorization code" + " issued for client " + clientId + " was removed from the cache."); } return false; } if (log.isDebugEnabled()) { log.debug("Found an Authorization Code, " + "Client : " + clientId + ", authorized user : " + authzCodeDO.getAuthorizedUser() + ", scope : " + OAuth2Util.buildScopeString(authzCodeDO.getScope())); } tokReqMsgCtx.setAuthorizedUser(authzCodeDO.getAuthorizedUser()); tokReqMsgCtx.setScope(authzCodeDO.getScope()); // keep the pre processed authz code as a OAuthTokenReqMessageContext property to avoid // calculating it again when issuing the access token. tokReqMsgCtx.addProperty(AUTHZ_CODE, authorizationCode); return true; } @Override public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception { OAuth2AccessTokenRespDTO tokenRespDTO = super.issue(tokReqMsgCtx); // get the token from the OAuthTokenReqMessageContext which is stored while validating // the authorization code. String authzCode = (String) tokReqMsgCtx.getProperty(AUTHZ_CODE); // if it's not there (which is unlikely), recalculate it. if (authzCode == null) { authzCode = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAuthorizationCode(); } // Clear the cache entry if (cacheEnabled) { String clientId = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId(); OAuthCacheKey cacheKey = new OAuthCacheKey(OAuth2Util.buildCacheKeyStringForAuthzCode( clientId, authzCode)); oauthCache.clearCacheEntry(cacheKey); if (log.isDebugEnabled()) { log.debug("Cache was cleared for authorization code info for client id : " + clientId); } } return tokenRespDTO; } @Override public boolean authorizeAccessDelegation(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception { // authorization is handled when the authorization code was issued. return true; } @Override protected void storeAccessToken(OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO, String userStoreDomain, AccessTokenDO newAccessTokenDO, String newAccessToken, AccessTokenDO existingAccessTokenDO) throws IdentityOAuth2Exception { try { newAccessTokenDO.setAuthorizationCode(oAuth2AccessTokenReqDTO.getAuthorizationCode()); tokenMgtDAO.storeAccessToken(newAccessToken, oAuth2AccessTokenReqDTO.getClientId(), newAccessTokenDO, existingAccessTokenDO, userStoreDomain); } catch (IdentityException e) { throw new IdentityOAuth2Exception( "Error occurred while storing new access token", e); } } }