/* * 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.service; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.UUID; import javax.ejb.Stateless; import javax.inject.Inject; import javax.inject.Named; import org.apache.commons.lang.StringUtils; import org.gluu.site.ldap.persistence.BatchOperation; import org.gluu.site.ldap.persistence.LdapEntryManager; import org.slf4j.Logger; import org.xdi.ldap.model.SearchScope; import org.xdi.oxauth.audit.ApplicationAuditLogger; import org.xdi.oxauth.model.audit.Action; import org.xdi.oxauth.model.audit.OAuth2AuditLog; import org.xdi.oxauth.model.common.AuthorizationGrant; import org.xdi.oxauth.model.common.MemcachedGrant; import org.xdi.oxauth.model.config.StaticConfiguration; import org.xdi.oxauth.model.ldap.Grant; import org.xdi.oxauth.model.ldap.TokenLdap; import org.xdi.oxauth.util.TokenHashUtil; import org.xdi.service.CacheService; import com.unboundid.ldap.sdk.Filter; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.util.StaticUtils; /** * @author Yuriy Zabrovarnyy * @author Javier Rojas Blum * @version November 11, 2016 */ @Stateless @Named public class GrantService { @Inject private Logger log; @Inject private LdapEntryManager ldapEntryManager; @Inject private ApplicationAuditLogger applicationAuditLogger; @Inject private ClientService clientService; @Inject private CacheService cacheService; @Inject private StaticConfiguration staticConfiguration; public static String generateGrantId() { return UUID.randomUUID().toString(); } public String buildDn(String p_uniqueIdentifier, String p_grantId, String p_clientId) { final StringBuilder dn = new StringBuilder(); dn.append(String.format("uniqueIdentifier=%s,oxAuthGrantId=%s,", p_uniqueIdentifier, p_grantId)); dn.append(clientService.buildClientDn(p_clientId)); return dn.toString(); } public String baseDn() { return staticConfiguration.getBaseDn().getClients(); // ou=clients,o=@!1111,o=gluu } public void merge(TokenLdap p_token) { ldapEntryManager.merge(p_token); } public void mergeSilently(TokenLdap p_token) { try { ldapEntryManager.merge(p_token); } catch (Exception e) { log.trace(e.getMessage(), e); } } public void persist(TokenLdap p_token) { prepareGrantBranch(p_token.getGrantId(), p_token.getClientId()); p_token.setTokenCode(TokenHashUtil.getHashedToken(p_token.getTokenCode())); ldapEntryManager.persist(p_token); } public void remove(Grant grant) { ldapEntryManager.remove(grant); log.trace("Removed grant, id: " + grant.getId()); } public void remove(TokenLdap p_token) { ldapEntryManager.remove(p_token); log.trace("Removed token, code: " + p_token.getTokenCode()); } public void removeSilently(TokenLdap token) { try { remove(token); if (StringUtils.isNotBlank(token.getAuthorizationCode())) { cacheService.remove(null, MemcachedGrant.cacheKey(token.getClientId(), token.getAuthorizationCode())); } } catch (Exception e) { log.trace(e.getMessage(), e); } } public void removeGrants(List<Grant> entries) { if (entries != null && !entries.isEmpty()) { for (Grant g : entries) { try { remove(g); } catch (Exception e) { log.error("Failed to remove entry", e); } } } } public void remove(List<TokenLdap> p_entries) { if (p_entries != null && !p_entries.isEmpty()) { for (TokenLdap t : p_entries) { try { remove(t); } catch (Exception e){ log.error("Failed to remove entry", e); } } } } public void removeSilently(List<TokenLdap> p_entries) { if (p_entries != null && !p_entries.isEmpty()) { for (TokenLdap t : p_entries) { removeSilently(t); } } } public void remove(AuthorizationGrant p_grant) { if (p_grant != null && p_grant.getTokenLdap() != null) { try { remove(p_grant.getTokenLdap()); } catch (Exception e) { log.trace(e.getMessage(), e); } } } public List<TokenLdap> getGrantsOfClient(String p_clientId) { try { final String baseDn = clientService.buildClientDn(p_clientId); return ldapEntryManager.findEntries(baseDn, TokenLdap.class, Filter.create("oxAuthTokenCode=*")); } catch (Exception e) { log.trace(e.getMessage(), e); } return Collections.emptyList(); } public TokenLdap getGrantsByCodeAndClient(String p_code, String p_clientId) { return load(clientService.buildClientDn(p_clientId), p_code); } public TokenLdap getGrantsByCode(String p_code) { return load(baseDn(), p_code); } private TokenLdap load(String p_baseDn, String p_code) { try { final List<TokenLdap> entries = ldapEntryManager.findEntries(p_baseDn, TokenLdap.class, Filter.create(String.format("oxAuthTokenCode=%s", TokenHashUtil.getHashedToken(p_code)))); if (entries != null && !entries.isEmpty()) { return entries.get(0); } } catch (LDAPException e) { log.trace(e.getMessage(), e); } catch (Exception e) { log.trace(e.getMessage(), e); } return null; } public List<TokenLdap> getGrantsByGrantId(String p_grantId) { try { return ldapEntryManager.findEntries(baseDn(), TokenLdap.class, Filter.create(String.format("oxAuthGrantId=%s", p_grantId))); } catch (LDAPException e) { log.trace(e.getMessage(), e); } catch (Exception e) { log.trace(e.getMessage(), e); } return Collections.emptyList(); } public List<TokenLdap> getGrantsByAuthorizationCode(String p_authorizationCode) { try { return ldapEntryManager.findEntries(baseDn(), TokenLdap.class, Filter.create(String.format("oxAuthAuthorizationCode=%s", TokenHashUtil.getHashedToken(p_authorizationCode)))); } catch (LDAPException e) { log.trace(e.getMessage(), e); } catch (Exception e) { log.trace(e.getMessage(), e); } return Collections.emptyList(); } public List<TokenLdap> getGrantsBySessionDn(String sessionDn) { try { return ldapEntryManager.findEntries(baseDn(), TokenLdap.class, Filter.create(String.format("oxAuthSessionDn=%s", sessionDn))); } catch (Exception e) { log.error(e.getMessage(), e); } return Collections.emptyList(); } public void removeAllTokensBySession(String sessionDn) { removeSilently(getGrantsBySessionDn(sessionDn)); } /** * Removes grant with particular code. * * @param p_code code */ public void removeByCode(String p_code, String p_clientId) { final TokenLdap t = getGrantsByCodeAndClient(p_code, p_clientId); if (t != null) { removeSilently(t); } cacheService.remove(null, MemcachedGrant.cacheKey(p_clientId, p_code)); } public void removeAllByAuthorizationCode(String p_authorizationCode) { removeSilently(getGrantsByAuthorizationCode(p_authorizationCode)); } public void removeAllByGrantId(String p_grantId) { removeSilently(getGrantsByGrantId(p_grantId)); } public void cleanUp() { // Cleaning oxAuthToken BatchOperation<TokenLdap> tokenBatchService = new BatchOperation<TokenLdap>(ldapEntryManager) { @Override protected List<TokenLdap> getChunkOrNull(int chunkSize) { return ldapEntryManager.findEntries(baseDn(), TokenLdap.class, getFilter(), SearchScope.SUB, null, this, 0, chunkSize, chunkSize); } @Override protected void performAction(List<TokenLdap> entries) { auditLogging(entries); remove(entries); } private Filter getFilter() { try { return Filter.create(String.format("(oxAuthExpiration<=%s)", StaticUtils.encodeGeneralizedTime(new Date()))); }catch (LDAPException e) { log.trace(e.getMessage(), e); return Filter.createPresenceFilter("oxAuthExpiration"); } } }; tokenBatchService.iterateAllByChunks(CleanerTimer.BATCH_SIZE); // Cleaning oxAuthGrant BatchOperation<Grant> grantBatchService = new BatchOperation<Grant>(ldapEntryManager) { @Override protected List<Grant> getChunkOrNull(int chunkSize) { return ldapEntryManager.findEntries(baseDn(), Grant.class, getFilter(), SearchScope.SUB, null, this, 0, chunkSize, chunkSize); } @Override protected void performAction(List<Grant> entries) { removeGrants(entries); } private Filter getFilter() { try { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.SECOND, 60); return Filter.create(String.format("(&(oxAuthCreation<=%s)(|(numsubordinates=0)(hasSubordinates=FALSE)))", StaticUtils.encodeGeneralizedTime(calendar.getTime()))); }catch (LDAPException e) { log.trace(e.getMessage(), e); return Filter.createPresenceFilter("oxAuthCreation"); } } }; grantBatchService.iterateAllByChunks(CleanerTimer.BATCH_SIZE); // Cleaning old oxAuthGrant // Note: This block should be removed, it is used only to delete old legacy data. BatchOperation<Grant> oldGrantBatchService = new BatchOperation<Grant>(ldapEntryManager) { @Override protected List<Grant> getChunkOrNull(int chunkSize) { return ldapEntryManager.findEntries(baseDn(), Grant.class, getFilter(), SearchScope.SUB, null, this, 0, chunkSize, chunkSize); } @Override protected void performAction(List<Grant> entries) { removeGrants(entries); } private Filter getFilter() { try { return Filter.create("(&(!(oxAuthCreation=*))(|(numsubordinates=0)(hasSubordinates=FALSE)))"); }catch (LDAPException e) { log.trace(e.getMessage(), e); return Filter.createPresenceFilter("oxAuthCreation"); } } }; oldGrantBatchService.iterateAllByChunks(CleanerTimer.BATCH_SIZE); } private void addGrantBranch(final String p_grantId, final String p_clientId) { Grant grant = new Grant(); grant.setDn(getBaseDnForGrant(p_grantId, p_clientId)); grant.setId(p_grantId); grant.setCreationDate(new Date()); ldapEntryManager.persist(grant); } private void prepareGrantBranch(final String p_grantId, final String p_clientId) { // Create ocAuthGrant branch if needed if (!containsGrantBranch(p_grantId, p_clientId)) { addGrantBranch(p_grantId, p_clientId); } } private boolean containsGrantBranch(final String p_grantId, final String p_clientId) { return ldapEntryManager.contains(Grant.class, getBaseDnForGrant(p_grantId, p_clientId)); } private String getBaseDnForGrant(final String p_grantId, final String p_clientId) { final StringBuilder dn = new StringBuilder(); dn.append(String.format("oxAuthGrantId=%s,", p_grantId)); dn.append(clientService.buildClientDn(p_clientId)); return dn.toString(); } private void auditLogging(Collection<TokenLdap> entries) { for (TokenLdap tokenLdap : entries) { OAuth2AuditLog oAuth2AuditLog = new OAuth2AuditLog(null, Action.SESSION_DESTROYED); oAuth2AuditLog.setSuccess(true); oAuth2AuditLog.setClientId(tokenLdap.getClientId()); oAuth2AuditLog.setScope(tokenLdap.getScope()); oAuth2AuditLog.setUsername(tokenLdap.getUserId()); applicationAuditLogger.sendMessage(oAuth2AuditLog); } } }