/** * ============================================================================= * * 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.util.Date; import java.util.List; import java.util.Set; import javax.annotation.Resource; import javax.persistence.NoResultException; import org.orcid.core.oauth.OrcidOauth2TokenDetailService; import org.orcid.jaxb.model.message.ScopePathType; import org.orcid.persistence.dao.OrcidOauth2TokenDetailDao; import org.orcid.persistence.jpa.entities.OrcidOauth2TokenDetail; import org.orcid.pojo.ajaxForm.PojoUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * @author Declan Newman (declan) Date: 19/04/2012 */ @Service public class OrcidOauth2TokenDetailServiceImpl implements OrcidOauth2TokenDetailService { private static final Logger LOGGER = LoggerFactory.getLogger(OrcidOauth2TokenDetailServiceImpl.class); @Resource private OrcidOauth2TokenDetailDao orcidOauth2TokenDetailDao; @Override public void setOrcidOauth2TokenDetailDao(OrcidOauth2TokenDetailDao orcidOauth2TokenDetailDao) { this.orcidOauth2TokenDetailDao = orcidOauth2TokenDetailDao; } @Override public OrcidOauth2TokenDetail findNonDisabledByTokenValue(String token) { try { return orcidOauth2TokenDetailDao.findNonDisabledByTokenValue(token); } catch (NoResultException e) { LOGGER.debug("No token found for token value {}", e, token); return null; } } @Override public OrcidOauth2TokenDetail findIgnoringDisabledByTokenValue(String token) { try { return orcidOauth2TokenDetailDao.findByTokenValue(token); } catch (NoResultException e) { LOGGER.debug("No token found for token value {}", e, token); return null; } } @Override public List<OrcidOauth2TokenDetail> getAll() { return orcidOauth2TokenDetailDao.getAll(); } @Override @Transactional public void remove(OrcidOauth2TokenDetail detail) { orcidOauth2TokenDetailDao.remove(detail); } @Override @Transactional public void remove(String tokenValue) { orcidOauth2TokenDetailDao.removeByTokenValue(tokenValue); } @Override @Transactional public void saveOrUpdate(OrcidOauth2TokenDetail detail) { if (detail.getId() != null) detail = orcidOauth2TokenDetailDao.merge(detail); orcidOauth2TokenDetailDao.persist(detail); } @Override public Long getCount() { return orcidOauth2TokenDetailDao.countAll(); } @Override @Transactional public void removeByTokenValue(String tokenValue) { orcidOauth2TokenDetailDao.removeByTokenValue(tokenValue); } @Override public OrcidOauth2TokenDetail findByRefreshTokenValue(String refreshTokenValue) { try { return orcidOauth2TokenDetailDao.findByRefreshTokenValue(refreshTokenValue); } catch (NoResultException e) { LOGGER.debug("No token found for refresh token value {}", e, refreshTokenValue); return null; } } @Override @Transactional public void removeByRefreshTokenValue(String refreshToken) { orcidOauth2TokenDetailDao.removeByRefreshTokenValue(refreshToken); } @Override public List<OrcidOauth2TokenDetail> findByAuthenticationKey(String authKey) { try { return orcidOauth2TokenDetailDao.findByAuthenticationKey(authKey); } catch (NoResultException e) { LOGGER.debug("No token found for auth token {}", e, authKey); return null; } } @Override public List<OrcidOauth2TokenDetail> findByUserName(String userName) { try { return orcidOauth2TokenDetailDao.findByUserName(userName); } catch (NoResultException e) { LOGGER.debug("No token found for username {}", e, userName); return null; } } @Override @Cacheable(value = "count-tokens", key = "#userName.concat('-').concat(#lastModified)") public int findCountByUserName(String userName, long lastModified) { return orcidOauth2TokenDetailDao.findCountByUserName(userName); } @Override public List<OrcidOauth2TokenDetail> findByClientId(String clientId) { try { return orcidOauth2TokenDetailDao.findByClientId(clientId); } catch (NoResultException e) { LOGGER.debug("No token found for client id {}", e, clientId); return null; } } /** * This should NOT delete the row, but merely set it as disabled * * @param accessToken * the value to use to identify the row containing the access * token */ @Override public void disableAccessToken(String accessToken) { orcidOauth2TokenDetailDao.disableAccessToken(accessToken); } /** * This should NOT delete the row, but merely set it as disabled * * @param tokenId * the id of the token that should be disabled * @param userOrcid * the id of the user owner of the token */ @Override public void disableAccessToken(Long tokenId, String userOrcid) { if(PojoUtil.isEmpty(userOrcid) || tokenId == null) { throw new IllegalArgumentException("One of the provided params is empty: userOrcid='" + userOrcid + "' tokenId='" + String.valueOf(tokenId) + "'"); } //Iterate over all tokens that belongs to this user and client, to remove all the ones that have the same scopes OrcidOauth2TokenDetail tokenToDisable = orcidOauth2TokenDetailDao.find(tokenId); String scopesToDisableString = tokenToDisable.getScope(); Set<ScopePathType> scopesToDisable = ScopePathType.getScopesFromSpaceSeparatedString(scopesToDisableString); List<OrcidOauth2TokenDetail> allTokens = orcidOauth2TokenDetailDao.findByClientIdAndUserName(tokenToDisable.getClientDetailsId(), userOrcid); //Iterate over all tokens and verify we disable all the ones that have the same scopes for(OrcidOauth2TokenDetail token : allTokens) { if(token.getTokenDisabled() == null || !token.getTokenDisabled()) { if(!PojoUtil.isEmpty(token.getScope())) { Set<ScopePathType> tokenScopes = ScopePathType.getScopesFromSpaceSeparatedString(token.getScope()); if(scopesToDisable.equals(tokenScopes)) { orcidOauth2TokenDetailDao.disableAccessTokenById(token.getId(), userOrcid); } } } } } /** * This should NOT delete the row, but merely remove the value from it * * @param refreshTokenValue * the value to use to identify the row containing the access * token */ @Override public void disableAccessTokenByRefreshToken(String refreshTokenValue) { orcidOauth2TokenDetailDao.disableAccessTokenByRefreshToken(refreshTokenValue); } @Override public void removeConflictsAndCreateNew(OrcidOauth2TokenDetail detail) { // We should allow multiple tokens for the same combo user-scopes, thats why we will // not delete based on the authentication key orcidOauth2TokenDetailDao.removeByAuthenticationKeyOrTokenValueOrRefreshTokenValue(null, detail.getTokenValue(), detail.getRefreshTokenValue()); orcidOauth2TokenDetailDao.persist(detail); } @Override public List<OrcidOauth2TokenDetail> findByClientIdAndUserName(String clientId, String userName) { try { return orcidOauth2TokenDetailDao.findByClientIdAndUserName(clientId, userName); } catch (NoResultException e) { LOGGER.debug("No token found for client id {}", e, clientId); return null; } } @Override public boolean doesClientKnowUser(String clientId, String userOrcid) { List<OrcidOauth2TokenDetail> existingTokens = orcidOauth2TokenDetailDao.findByClientIdAndUserName(clientId, userOrcid); if (existingTokens == null || existingTokens.isEmpty()) { return false; } Date now = new Date(); for (OrcidOauth2TokenDetail token : existingTokens) { if (token.getTokenExpiration() != null && token.getTokenExpiration().after(now)) { return true; } } return false; } }