/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.model.common;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xdi.oxauth.model.authorize.JwtAuthorizationRequest;
import org.xdi.oxauth.model.exception.InvalidJweException;
import org.xdi.oxauth.model.exception.InvalidJwtException;
import org.xdi.oxauth.model.jwt.JwtClaimName;
import org.xdi.oxauth.model.ldap.TokenLdap;
import org.xdi.oxauth.model.registration.Client;
import org.xdi.oxauth.model.token.IdTokenFactory;
import org.xdi.oxauth.model.token.JsonWebResponse;
import org.xdi.oxauth.service.GrantService;
import org.xdi.oxauth.util.TokenHashUtil;
import org.xdi.service.CacheService;
import org.xdi.util.security.StringEncrypter;
import javax.inject.Inject;
import java.security.SignatureException;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Base class for all the types of authorization grant.
*
* @author Javier Rojas Blum
* @author Yuriy Movchan
* @version November 11, 2016
*/
public class AuthorizationGrant extends AbstractAuthorizationGrant {
private static final Logger log = LoggerFactory.getLogger(AuthorizationGrant.class);
@Inject
private CacheService cacheService;
@Inject
private GrantService grantService;
@Inject
private IdTokenFactory idTokenFactory;
private boolean isCachedWithNoPersistence = false;
public AuthorizationGrant() {}
public AuthorizationGrant(User user, AuthorizationGrantType authorizationGrantType, Client client,
Date authenticationTime) {
super(user, authorizationGrantType, client, authenticationTime);
}
public void init(User user, AuthorizationGrantType authorizationGrantType, Client client, Date authenticationTime) {
super.init(user, authorizationGrantType, client, authenticationTime);
}
public IdToken createIdToken(IAuthorizationGrant grant, String nonce, AuthorizationCode authorizationCode,
AccessToken accessToken, Set<String> scopes, boolean includeIdTokenClaims) throws Exception {
JsonWebResponse jwr = idTokenFactory.createJwr(grant, nonce, authorizationCode, accessToken, scopes,
includeIdTokenClaims);
return new IdToken(jwr.toString(), jwr.getClaims().getClaimAsDate(JwtClaimName.ISSUED_AT),
jwr.getClaims().getClaimAsDate(JwtClaimName.EXPIRATION_TIME));
}
@Override
public String checkScopesPolicy(String scope) {
final String result = super.checkScopesPolicy(scope);
save();
return result;
}
@Override
public void save() {
if (isCachedWithNoPersistence) {
if (getAuthorizationGrantType() == AuthorizationGrantType.AUTHORIZATION_CODE) {
MemcachedGrant memcachedGrant = new MemcachedGrant(this);
cacheService.put(Integer.toString(getAuthorizationCode().getExpiresIn()), memcachedGrant.cacheKey(),
memcachedGrant);
} else {
throw new UnsupportedOperationException(
"Grant caching is not supported for : " + getAuthorizationGrantType());
}
} else {
saveImpl();
}
}
private void saveImpl() {
String grantId = getGrantId();
if (grantId != null && StringUtils.isNotBlank(grantId)) {
final List<TokenLdap> grants = grantService.getGrantsByGrantId(grantId);
if (grants != null && !grants.isEmpty()) {
final String nonce = getNonce();
final String scopes = getScopesAsString();
for (TokenLdap t : grants) {
t.setNonce(nonce);
t.setScope(scopes);
t.setAuthMode(getAcrValues());
t.setSessionDn(getSessionDn());
t.setAuthenticationTime(getAuthenticationTime());
t.setCodeChallenge(getCodeChallenge());
t.setCodeChallengeMethod(getCodeChallengeMethod());
final JwtAuthorizationRequest jwtRequest = getJwtAuthorizationRequest();
if (jwtRequest != null && StringUtils.isNotBlank(jwtRequest.getEncodedJwt())) {
t.setJwtRequest(jwtRequest.getEncodedJwt());
}
log.debug("Saving grant: " + grantId + ", code_challenge: " + getCodeChallenge());
grantService.mergeSilently(t);
}
}
}
}
@Override
public AccessToken createAccessToken() {
try {
final AccessToken accessToken = super.createAccessToken();
if (accessToken.getExpiresIn() > 0) {
persist(asToken(accessToken));
}
return accessToken;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
@Override
public AccessToken createLongLivedAccessToken() {
try {
final AccessToken accessToken = super.createLongLivedAccessToken();
if (accessToken.getExpiresIn() > 0) {
persist(asToken(accessToken));
}
return accessToken;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
@Override
public RefreshToken createRefreshToken() {
try {
final RefreshToken refreshToken = super.createRefreshToken();
if (refreshToken.getExpiresIn() > 0) {
persist(asToken(refreshToken));
}
return refreshToken;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
@Override
public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, AccessToken accessToken,
AuthorizationGrant authorizationGrant, boolean includeIdTokenClaims)
throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException {
try {
final IdToken idToken = createIdToken(this, nonce, authorizationCode, accessToken, getScopes(),
includeIdTokenClaims);
final String acrValues = authorizationGrant.getAcrValues();
final String sessionDn = authorizationGrant.getSessionDn();
if (idToken.getExpiresIn() > 0) {
final TokenLdap tokenLdap = asToken(idToken);
tokenLdap.setAuthMode(acrValues);
tokenLdap.setSessionDn(sessionDn);
persist(tokenLdap);
}
// is it really neccessary to propagate to all tokens?
setAcrValues(acrValues);
setSessionDn(sessionDn);
save(); // asynchronous save
return idToken;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
public void persist(TokenLdap p_token) {
grantService.persist(p_token);
}
public void persist(AuthorizationCode p_code) {
persist(asToken(p_code));
}
public TokenLdap asToken(IdToken p_token) {
final TokenLdap result = asTokenLdap(p_token);
result.setTokenTypeEnum(org.xdi.oxauth.model.ldap.TokenType.ID_TOKEN);
return result;
}
public TokenLdap asToken(RefreshToken p_token) {
final TokenLdap result = asTokenLdap(p_token);
result.setTokenTypeEnum(org.xdi.oxauth.model.ldap.TokenType.REFRESH_TOKEN);
return result;
}
public TokenLdap asToken(AuthorizationCode p_authorizationCode) {
final TokenLdap result = asTokenLdap(p_authorizationCode);
result.setTokenTypeEnum(org.xdi.oxauth.model.ldap.TokenType.AUTHORIZATION_CODE);
return result;
}
public TokenLdap asToken(AccessToken p_accessToken) {
final TokenLdap result = asTokenLdap(p_accessToken);
result.setTokenTypeEnum(org.xdi.oxauth.model.ldap.TokenType.ACCESS_TOKEN);
return result;
}
public String getScopesAsString() {
final StringBuilder scopes = new StringBuilder();
for (String s : getScopes()) {
scopes.append(s).append(" ");
}
return scopes.toString().trim();
}
public TokenLdap asTokenLdap(AbstractToken p_token) {
final String id = GrantService.generateGrantId();
final TokenLdap result = new TokenLdap();
result.setDn(grantService.buildDn(id, getGrantId(), getClientId()));
result.setId(id);
result.setGrantId(getGrantId());
result.setCreationDate(p_token.getCreationDate());
result.setExpirationDate(p_token.getExpirationDate());
result.setTokenCode(TokenHashUtil.getHashedToken(p_token.getCode()));
result.setUserId(getUserId());
result.setClientId(getClientId());
result.setScope(getScopesAsString());
result.setAuthMode(p_token.getAuthMode());
result.setSessionDn(p_token.getSessionDn());
result.setAuthenticationTime(getAuthenticationTime());
final AuthorizationGrantType grantType = getAuthorizationGrantType();
if (grantType != null) {
result.setGrantType(grantType.getParamName());
}
final AuthorizationCode authorizationCode = getAuthorizationCode();
if (authorizationCode != null) {
result.setAuthorizationCode(TokenHashUtil.getHashedToken(authorizationCode.getCode()));
}
final String nonce = getNonce();
if (nonce != null) {
result.setNonce(nonce);
}
final JwtAuthorizationRequest jwtRequest = getJwtAuthorizationRequest();
if (jwtRequest != null && StringUtils.isNotBlank(jwtRequest.getEncodedJwt())) {
result.setJwtRequest(jwtRequest.getEncodedJwt());
}
return result;
}
@Override
public boolean isValid() {
// final TokenLdap t = getTokenLdap();
// if (t != null) {
// if (new Date().after(t.getExpirationDate())) {
// return true;
// }
// }
return true;
}
@Override
public void revokeAllTokens() {
final TokenLdap tokenLdap = getTokenLdap();
if (tokenLdap != null && StringUtils.isNotBlank(tokenLdap.getGrantId())) {
grantService.removeAllByGrantId(tokenLdap.getGrantId());
}
}
@Override
public void checkExpiredTokens() {
// do nothing, clean up is made via grant service:
// org.xdi.oxauth.service.GrantService.cleanUp()
}
public boolean isCachedWithNoPersistence() {
return isCachedWithNoPersistence;
}
public void setIsCachedWithNoPersistence(boolean isCachedWithNoPersistence) {
this.isCachedWithNoPersistence = isCachedWithNoPersistence;
}
}