/* * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. * * Copyright (c) 2014, Gluu */ package org.gluu.oxauth.service; import com.google.common.collect.Sets; import org.gluu.oxauth.model.common.AuthenticationMethod; import org.gluu.oxauth.model.config.StaticConfiguration; import org.gluu.oxauth.model.configuration.AppConfiguration; import org.gluu.oxauth.model.exception.InvalidClaimException; import org.gluu.oxauth.model.registration.Client; import org.gluu.oxauth.service.common.EncryptionService; import org.gluu.persist.PersistenceEntryManager; import org.gluu.persist.exception.EntryPersistenceException; import org.gluu.persist.model.base.CustomAttribute; import org.gluu.persist.model.base.CustomEntry; import org.gluu.service.BaseCacheService; import org.gluu.service.CacheService; import org.gluu.service.LocalCacheService; import org.gluu.util.StringHelper; import org.gluu.util.security.StringEncrypter; import org.gluu.util.security.StringEncrypter.EncryptionException; import org.json.JSONArray; import org.oxauth.persistence.model.Scope; import org.python.jline.internal.Preconditions; import org.slf4j.Logger; import javax.ejb.Stateless; import javax.inject.Inject; import javax.inject.Named; import java.util.*; /** * Provides operations with clients. * * @author Javier Rojas Blum * @author Yuriy Movchan Date: 04/15/2014 * @version October 22, 2016 */ @Stateless @Named public class ClientService { public static final String[] CLIENT_OBJECT_CLASSES = new String[] { "oxAuthClient" }; @Inject private Logger log; @Inject private PersistenceEntryManager ldapEntryManager; @Inject private CacheService cacheService; @Inject private LocalCacheService localCacheService; @Inject private ScopeService scopeService; @Inject private EncryptionService encryptionService; @Inject private AppConfiguration appConfiguration; @Inject private StaticConfiguration staticConfiguration; public void persist(Client client) { ldapEntryManager.persist(client); } public void merge(Client client) { ldapEntryManager.merge(client); removeFromCache(client); } /** * Authenticate client. * * @param clientId * Client inum. * @param password * Client password. * @return <code>true</code> if success, otherwise <code>false</code>. */ public boolean authenticate(String clientId, String password) { log.debug("Authenticating Client with LDAP: clientId = {}", clientId); boolean authenticated = false; try { Client client = getClient(clientId); if (client == null) { log.debug("Failed to find client = {}", clientId); return authenticated; } String decryptedClientSecret = decryptSecret(client.getClientSecret()); authenticated = client != null && decryptedClientSecret != null && decryptedClientSecret.equals(password); } catch (StringEncrypter.EncryptionException e) { log.error(e.getMessage(), e); } return authenticated; } public Set<Client> getClient(Collection<String> clientIds, boolean silent) { Set<Client> set = Sets.newHashSet(); if (clientIds == null) { return set; } for (String clientId : clientIds) { try { Client client = getClient(clientId); if (client != null) { set.add(client); } } catch (RuntimeException e) { if (!silent) { throw e; } } } return set; } public Client getClient(String clientId) { if (clientId != null && !clientId.isEmpty()) { Client result = getClientByDn(buildClientDn(clientId)); log.debug("Found {} entries for client id = {}", result != null ? 1 : 0, clientId); return result; } return null; } public boolean isPublic(String clientId) { return isPublic(getClient(clientId)); } public boolean isPublic(Client client) { return client != null && client.getAuthenticationMethod() == AuthenticationMethod.NONE; } public Client getClient(String clientId, String registrationAccessToken) { final Client client = getClient(clientId); if (client != null && registrationAccessToken != null && registrationAccessToken.equals(client.getRegistrationAccessToken())) { return client; } return null; } public Set<Client> getClientsByDns(Collection<String> dnList) { return getClientsByDns(dnList, true); } public Set<Client> getClientsByDns(Collection<String> dnList, boolean silently) { Preconditions.checkNotNull(dnList); final Set<Client> result = Sets.newHashSet(); for (String clientDn : dnList) { try { result.add(getClientByDn(clientDn)); } catch (RuntimeException e) { if (!silently) { throw e; } } } return result; } /** * Returns client by DN. * * @param dn * dn of client * @return Client */ public Client getClientByDn(String dn) { BaseCacheService usedCacheService = getCacheService(); try { return usedCacheService.getWithPut(dn, () -> ldapEntryManager.find(Client.class, dn), 60); } catch (Exception e) { log.trace(e.getMessage(), e); return null; } } public org.gluu.persist.model.base.CustomAttribute getCustomAttribute(Client client, String attributeName) { for (org.gluu.persist.model.base.CustomAttribute customAttribute : client.getCustomAttributes()) { if (StringHelper.equalsIgnoreCase(attributeName, customAttribute.getName())) { return customAttribute; } } return null; } public void setCustomAttribute(Client client, String attributeName, String attributeValue) { org.gluu.persist.model.base.CustomAttribute customAttribute = getCustomAttribute(client, attributeName); if (customAttribute == null) { customAttribute = new org.gluu.persist.model.base.CustomAttribute(attributeName); client.getCustomAttributes().add(customAttribute); } customAttribute.setValue(attributeValue); } public List<Client> getAllClients(String[] returnAttributes) { String baseDn = staticConfiguration.getBaseDn().getClients(); List<Client> result = ldapEntryManager.findEntries(baseDn, Client.class, null, returnAttributes); return result; } public List<Client> getAllClients(String[] returnAttributes, int size) { String baseDn = staticConfiguration.getBaseDn().getClients(); List<Client> result = ldapEntryManager.findEntries(baseDn, Client.class, null, returnAttributes, size); return result; } public String buildClientDn(String p_clientId) { final StringBuilder dn = new StringBuilder(); dn.append(String.format("inum=%s,", p_clientId)); dn.append(staticConfiguration.getBaseDn().getClients()); // ou=clients,o=gluu return dn.toString(); } public void remove(Client client) { if (client != null) { removeFromCache(client); String clientDn = client.getDn(); ldapEntryManager.removeRecursively(clientDn); } } private void removeFromCache(Client client) { BaseCacheService usedCacheService = getCacheService(); try { usedCacheService.remove(client.getDn()); } catch (Exception e) { log.error("Failed to remove client from cache." + client.getDn(), e); } } public void updateAccessTime(Client client, boolean isUpdateLogonTime) { if (!appConfiguration.getUpdateClientAccessTime()) { return; } String clientDn = client.getDn(); CustomEntry customEntry = new CustomEntry(); customEntry.setDn(clientDn); customEntry.setCustomObjectClasses(CLIENT_OBJECT_CLASSES); Date now = new GregorianCalendar(TimeZone.getTimeZone("UTC")).getTime(); String nowDateString = ldapEntryManager.encodeTime(customEntry.getDn(), now); CustomAttribute customAttributeLastAccessTime = new CustomAttribute("oxLastAccessTime", nowDateString); customEntry.getCustomAttributes().add(customAttributeLastAccessTime); if (isUpdateLogonTime) { CustomAttribute customAttributeLastLogonTime = new CustomAttribute("oxLastLogonTime", nowDateString); customEntry.getCustomAttributes().add(customAttributeLastLogonTime); } try { ldapEntryManager.merge(customEntry); } catch (EntryPersistenceException epe) { log.error("Failed to update oxLastAccessTime and oxLastLogonTime of client '{}'", clientDn); } removeFromCache(client); } public Object getAttribute(Client client, String clientAttribute) throws InvalidClaimException { Object attribute = null; if (clientAttribute != null) { if (clientAttribute.equals("displayName")) { attribute = client.getClientName(); } else if (clientAttribute.equals("inum")) { attribute = client.getClientId(); } else if (clientAttribute.equals("oxAuthAppType")) { attribute = client.getApplicationType(); } else if (clientAttribute.equals("oxAuthIdTokenSignedResponseAlg")) { attribute = client.getIdTokenSignedResponseAlg(); } else if (clientAttribute.equals("oxAuthRedirectURI") && client.getRedirectUris() != null) { JSONArray array = new JSONArray(); for (String redirectUri : client.getRedirectUris()) { array.put(redirectUri); } attribute = array; } else if (clientAttribute.equals("oxAuthScope") && client.getScopes() != null) { JSONArray array = new JSONArray(); for (String scopeDN : client.getScopes()) { Scope s = scopeService.getScopeByDn(scopeDN); if (s != null) { String scopeName = s.getId(); array.put(scopeName); } } attribute = array; } else { for (CustomAttribute customAttribute : client.getCustomAttributes()) { if (customAttribute.getName().equals(clientAttribute)) { List<String> values = customAttribute.getValues(); if (values != null) { if (values.size() == 1) { attribute = values.get(0); } else { JSONArray array = new JSONArray(); for (String v : values) { array.put(v); } attribute = array; } } break; } } } } return attribute; } public String decryptSecret(String encryptedClientSecret) throws EncryptionException { return encryptionService.decrypt(encryptedClientSecret); } public String encryptSecret(String clientSecret) throws EncryptionException { return encryptionService.encrypt(clientSecret); } private BaseCacheService getCacheService() { if (appConfiguration.getUseLocalCache()) { return localCacheService; } return cacheService; } }