/** * ============================================================================= * * 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.service; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import javax.persistence.NoResultException; import org.orcid.core.constants.OrcidOauth2Constants; import org.orcid.core.manager.ClientDetailsEntityCacheManager; import org.orcid.core.manager.ProfileEntityCacheManager; import org.orcid.core.oauth.OrcidOauth2AuthInfo; import org.orcid.core.oauth.OrcidOauth2UserAuthentication; import org.orcid.core.oauth.OrcidProfileUserDetails; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices; import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.stereotype.Service; /** * @author Declan Newman (declan) Date: 23/04/2012 */ @Service("orcidAuthorizationCodeService") public class OrcidAuthorizationCodeServiceImpl extends RandomValueAuthorizationCodeServices { private static final String CLIENT_ID = "client_id"; private static final String STATE = "state"; private static final String SCOPE = "scope"; private static final String REDIRECT_URI = "redirect_uri"; private static final String RESPONSE_TYPE = "response_type"; @Resource(name = "orcidOauth2AuthoriziationCodeDetailDao") private OrcidOauth2AuthoriziationCodeDetailDao orcidOauth2AuthoriziationCodeDetailDao; @Resource(name = "profileEntityCacheManager") private ProfileEntityCacheManager profileEntityCacheManager; @Resource private ClientDetailsEntityCacheManager clientDetailsEntityCacheManager; private static final Logger LOGGER = LoggerFactory.getLogger(OrcidAuthorizationCodeServiceImpl.class); @Override protected void store(String code, OAuth2Authentication authentication) { OrcidOauth2AuthoriziationCodeDetail detail = getDetailFromAuthorization(code, authentication); if (detail == null) { throw new IllegalArgumentException("Cannot persist the authorisation code as the user and/or client " + "cannot be found"); } orcidOauth2AuthoriziationCodeDetailDao.persist(detail); OrcidOauth2AuthInfo authInfo = new OrcidOauth2AuthInfo(authentication); LOGGER.info("Storing authorization code: code={}, clientId={}, scopes={}, userOrcid={}", new Object[] { code, authInfo.getClientId(), authInfo.getScopes(), authInfo.getUserOrcid() }); } @Override protected OAuth2Authentication remove(String code) { OrcidOauth2AuthoriziationCodeDetail detail = orcidOauth2AuthoriziationCodeDetailDao.removeAndReturn(code); if (detail == null) { LOGGER.info("No such authorization code to remove: code={}", new Object[] { code }); return null; } OrcidOauth2AuthInfo authInfo = new OrcidOauth2AuthInfo(detail.getClientDetailsEntity().getId(), detail.getScopes(), detail.getProfileEntity().getId()); LOGGER.info("Removed authorization code: code={}, clientId={}, scopes={}, userOrcid={}", new Object[] { code, authInfo.getClientId(), authInfo.getScopes(), authInfo.getUserOrcid() }); OAuth2Request oAuth2Request = new OAuth2Request(Collections.<String, String> emptyMap(), authInfo.getClientId(), Collections.<GrantedAuthority> emptyList(), true, authInfo.getScopes(), detail.getResourceIds(), detail.getRedirectUri(), new HashSet<String>(Arrays.asList(detail.getResponseType())), Collections.<String, Serializable> emptyMap()); Authentication userAuth = getUserAuthentication(detail); OAuth2Authentication result = new OAuth2Authentication(oAuth2Request, userAuth); return result; } private OrcidOauth2UserAuthentication getUserAuthentication(OrcidOauth2AuthoriziationCodeDetail detail) { return new OrcidOauth2UserAuthentication(detail.getProfileEntity(), detail.getAuthenticated()); } private OrcidOauth2AuthoriziationCodeDetail getDetailFromAuthorization(String code, OAuth2Authentication authentication) { OAuth2Request oAuth2Request = authentication.getOAuth2Request(); OrcidOauth2AuthoriziationCodeDetail detail = new OrcidOauth2AuthoriziationCodeDetail(); Map<String, String> requestParameters = oAuth2Request.getRequestParameters(); if (requestParameters != null && !requestParameters.isEmpty()) { String clientId = (String) requestParameters.get(CLIENT_ID); ClientDetailsEntity clientDetails = getClientDetails(clientId); if (clientDetails == null) { return null; } detail.setScopes(OAuth2Utils.parseParameterList((String)requestParameters.get(SCOPE))); detail.setState((String)requestParameters.get(STATE)); detail.setRedirectUri((String)requestParameters.get(REDIRECT_URI)); detail.setResponseType((String)requestParameters.get(RESPONSE_TYPE)); detail.setClientDetailsEntity(clientDetails); } detail.setId(code); detail.setApproved(authentication.getOAuth2Request().isApproved()); Authentication userAuthentication = authentication.getUserAuthentication(); Object principal = userAuthentication.getPrincipal(); ProfileEntity entity = null; if (principal instanceof OrcidProfileUserDetails) { OrcidProfileUserDetails userDetails = (OrcidProfileUserDetails) principal; String effectiveOrcid = userDetails.getOrcid(); if (effectiveOrcid != null) { entity = profileEntityCacheManager.retrieve(effectiveOrcid); } } if (entity == null) { return null; } detail.setProfileEntity(entity); detail.setAuthenticated(userAuthentication.isAuthenticated()); Set<String> authorities = getStringSetFromGrantedAuthorities(authentication.getAuthorities()); detail.setAuthorities(authorities); Object authenticationDetails = userAuthentication.getDetails(); if (authenticationDetails instanceof WebAuthenticationDetails) { detail.setSessionId(((WebAuthenticationDetails) authenticationDetails).getSessionId()); } boolean isPersistentTokenEnabledByUser = false; //Set token version to persistent token //TODO: As of Jan 2015 all tokens will be new tokens, so, we will have to remove the token version code and //treat all tokens as new tokens detail.setVersion(Long.valueOf(OrcidOauth2Constants.PERSISTENT_TOKEN)); if(requestParameters.containsKey(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN)) { String grantPersitentToken = (String)requestParameters.get(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN); if(Boolean.parseBoolean(grantPersitentToken)) { isPersistentTokenEnabledByUser = true; } } detail.setPersistent(isPersistentTokenEnabledByUser); return detail; } private ClientDetailsEntity getClientDetails(String clientId) { try { return clientDetailsEntityCacheManager.retrieve(clientId); } catch (NoResultException e) { return null; } } private Set<String> getStringSetFromGrantedAuthorities(Collection<GrantedAuthority> authorities) { Set<String> stringSet = new HashSet<String>(); if (authorities != null && !authorities.isEmpty()) { for (GrantedAuthority authority : authorities) { stringSet.add(authority.getAuthority()); } } return stringSet; } }