package com.monkeyk.os.service.impl;
import com.monkeyk.os.domain.oauth.*;
import com.monkeyk.os.service.OauthService;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.utils.OAuthUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* 15-6-10
*
* @author Shengzhao Li
*/
@Service("oauthService")
public class OauthServiceImpl implements OauthService {
private static final Logger LOG = LoggerFactory.getLogger(OauthServiceImpl.class);
@Autowired
private OauthRepository oauthRepository;
@Autowired
private AuthenticationIdGenerator authenticationIdGenerator;
@Autowired
private OAuthIssuer oAuthIssuer;
@Override
public ClientDetails loadClientDetails(String clientId) {
LOG.debug("Load ClientDetails by clientId: {}", clientId);
return oauthRepository.findClientDetails(clientId);
}
@Override
public OauthCode saveAuthorizationCode(String authCode, ClientDetails clientDetails) {
final String username = currentUsername();
OauthCode oauthCode = new OauthCode()
.code(authCode).username(username)
.clientId(clientDetails.getClientId());
oauthRepository.saveOauthCode(oauthCode);
LOG.debug("Save OauthCode: {}", oauthCode);
return oauthCode;
}
private String currentUsername() {
return (String) SecurityUtils.getSubject().getPrincipal();
}
@Override
public String retrieveAuthCode(ClientDetails clientDetails) throws OAuthSystemException {
final String clientId = clientDetails.getClientId();
final String username = currentUsername();
OauthCode oauthCode = oauthRepository.findOauthCodeByUsernameClientId(username, clientId);
if (oauthCode != null) {
//Always delete exist
LOG.debug("OauthCode ({}) is existed, remove it and create a new one", oauthCode);
oauthRepository.deleteOauthCode(oauthCode);
}
//create a new one
oauthCode = createOauthCode(clientDetails);
return oauthCode.code();
}
@Override
public AccessToken retrieveAccessToken(ClientDetails clientDetails, Set<String> scopes, boolean includeRefreshToken) throws OAuthSystemException {
String scope = OAuthUtils.encodeScopes(scopes);
final String username = currentUsername();
final String clientId = clientDetails.getClientId();
final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
if (accessToken == null) {
accessToken = createAndSaveAccessToken(clientDetails, includeRefreshToken, username, authenticationId);
LOG.debug("Create a new AccessToken: {}", accessToken);
}
return accessToken;
}
//Always return new AccessToken, exclude refreshToken
@Override
public AccessToken retrieveNewAccessToken(ClientDetails clientDetails, Set<String> scopes) throws OAuthSystemException {
String scope = OAuthUtils.encodeScopes(scopes);
final String username = currentUsername();
final String clientId = clientDetails.getClientId();
final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
if (accessToken != null) {
LOG.debug("Delete existed AccessToken: {}", accessToken);
oauthRepository.deleteAccessToken(accessToken);
}
accessToken = createAndSaveAccessToken(clientDetails, false, username, authenticationId);
LOG.debug("Create a new AccessToken: {}", accessToken);
return accessToken;
}
@Override
public OauthCode loadOauthCode(String code, ClientDetails clientDetails) {
final String clientId = clientDetails.getClientId();
return oauthRepository.findOauthCode(code, clientId);
}
@Override
public boolean removeOauthCode(String code, ClientDetails clientDetails) {
final OauthCode oauthCode = loadOauthCode(code, clientDetails);
final int rows = oauthRepository.deleteOauthCode(oauthCode);
return rows > 0;
}
//Always return new AccessToken
@Override
public AccessToken retrieveAuthorizationCodeAccessToken(ClientDetails clientDetails, String code) throws OAuthSystemException {
final OauthCode oauthCode = loadOauthCode(code, clientDetails);
final String username = oauthCode.username();
final String clientId = clientDetails.getClientId();
final String authenticationId = authenticationIdGenerator.generate(clientId, username, null);
AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
if (accessToken != null) {
LOG.debug("Delete existed AccessToken: {}", accessToken);
oauthRepository.deleteAccessToken(accessToken);
}
accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
LOG.debug("Create a new AccessToken: {}", accessToken);
return accessToken;
}
//grant_type=password AccessToken
@Override
public AccessToken retrievePasswordAccessToken(ClientDetails clientDetails, Set<String> scopes, String username) throws OAuthSystemException {
String scope = OAuthUtils.encodeScopes(scopes);
final String clientId = clientDetails.getClientId();
final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
boolean needCreate = false;
if (accessToken == null) {
needCreate = true;
LOG.debug("Not found AccessToken from repository, will create a new one, client_id: {}", clientId);
} else if (accessToken.tokenExpired()) {
LOG.debug("Delete expired AccessToken: {} and create a new one, client_id: {}", accessToken, clientId);
oauthRepository.deleteAccessToken(accessToken);
needCreate = true;
} else {
LOG.debug("Use existed AccessToken: {}, client_id: {}", accessToken, clientId);
}
if (needCreate) {
accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
LOG.debug("Create a new AccessToken: {}", accessToken);
}
return accessToken;
}
//grant_type=client_credentials
@Override
public AccessToken retrieveClientCredentialsAccessToken(ClientDetails clientDetails, Set<String> scopes) throws OAuthSystemException {
String scope = OAuthUtils.encodeScopes(scopes);
final String clientId = clientDetails.getClientId();
//username = clientId
final String authenticationId = authenticationIdGenerator.generate(clientId, clientId, scope);
AccessToken accessToken = oauthRepository.findAccessToken(clientId, clientId, authenticationId);
boolean needCreate = false;
if (accessToken == null) {
needCreate = true;
LOG.debug("Not found AccessToken from repository, will create a new one, client_id: {}", clientId);
} else if (accessToken.tokenExpired()) {
LOG.debug("Delete expired AccessToken: {} and create a new one, client_id: {}", accessToken, clientId);
oauthRepository.deleteAccessToken(accessToken);
needCreate = true;
} else {
LOG.debug("Use existed AccessToken: {}, client_id: {}", accessToken, clientId);
}
if (needCreate) {
//Ignore refresh_token
accessToken = createAndSaveAccessToken(clientDetails, false, clientId, authenticationId);
LOG.debug("Create a new AccessToken: {}", accessToken);
}
return accessToken;
}
@Override
public AccessToken loadAccessTokenByRefreshToken(String refreshToken, String clientId) {
LOG.debug("Load ClientDetails by refreshToken: {} and clientId: {}", refreshToken, clientId);
return oauthRepository.findAccessTokenByRefreshToken(refreshToken, clientId);
}
/*
* Get AccessToken
* Generate a new AccessToken from existed(exclude token,refresh_token)
* Update access_token,refresh_token, expired.
* Save and remove old
* */
@Override
public AccessToken changeAccessTokenByRefreshToken(String refreshToken, String clientId) throws OAuthSystemException {
final AccessToken oldToken = loadAccessTokenByRefreshToken(refreshToken, clientId);
AccessToken newAccessToken = oldToken.cloneMe();
LOG.debug("Create new AccessToken: {} from old AccessToken: {}", newAccessToken, oldToken);
ClientDetails details = oauthRepository.findClientDetails(clientId);
newAccessToken.updateByClientDetails(details);
final String authId = authenticationIdGenerator.generate(clientId, oldToken.username(), null);
newAccessToken.authenticationId(authId)
.tokenId(oAuthIssuer.accessToken())
.refreshToken(oAuthIssuer.refreshToken());
oauthRepository.deleteAccessToken(oldToken);
LOG.debug("Delete old AccessToken: {}", oldToken);
oauthRepository.saveAccessToken(newAccessToken);
LOG.debug("Save new AccessToken: {}", newAccessToken);
return newAccessToken;
}
@Override
public boolean isExistedClientId(String clientId) {
final ClientDetails clientDetails = loadClientDetails(clientId);
return clientDetails != null;
}
private AccessToken createAndSaveAccessToken(ClientDetails clientDetails, boolean includeRefreshToken, String username, String authenticationId) throws OAuthSystemException {
AccessToken accessToken = new AccessToken()
.clientId(clientDetails.getClientId())
.username(username)
.tokenId(oAuthIssuer.accessToken())
.authenticationId(authenticationId)
.updateByClientDetails(clientDetails);
if (includeRefreshToken) {
accessToken.refreshToken(oAuthIssuer.refreshToken());
}
this.oauthRepository.saveAccessToken(accessToken);
LOG.debug("Save AccessToken: {}", accessToken);
return accessToken;
}
private OauthCode createOauthCode(ClientDetails clientDetails) throws OAuthSystemException {
OauthCode oauthCode;
final String authCode = oAuthIssuer.authorizationCode();
LOG.debug("Save authorizationCode '{}' of ClientDetails '{}'", authCode, clientDetails);
oauthCode = this.saveAuthorizationCode(authCode, clientDetails);
return oauthCode;
}
}