/* * 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.external; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.xdi.model.AuthenticationScriptUsageType; import org.xdi.model.SimpleCustomProperty; import org.xdi.model.custom.script.CustomScriptType; import org.xdi.model.custom.script.conf.CustomScriptConfiguration; import org.xdi.model.custom.script.model.CustomScript; import org.xdi.model.custom.script.model.auth.AuthenticationCustomScript; import org.xdi.model.custom.script.type.auth.PersonAuthenticationType; import org.xdi.model.ldap.GluuLdapConfiguration; import org.xdi.oxauth.service.AppInitializer; import org.xdi.oxauth.service.cdi.event.ReloadAuthScript; import org.xdi.oxauth.service.external.internal.InternalDefaultPersonAuthenticationType; import org.xdi.service.custom.script.ExternalScriptService; import org.xdi.util.OxConstants; import org.xdi.util.StringHelper; import javax.ejb.DependsOn; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.inject.Named; import java.util.*; import java.util.Map.Entry; /** * Provides factory methods needed to create external authenticator * * @author Yuriy Movchan Date: 21/08/2012 */ @ApplicationScoped @DependsOn("appInitializer") @Named public class ExternalAuthenticationService extends ExternalScriptService { public final static String MODIFIED_INTERNAL_TYPES_EVENT_TYPE = "CustomScriptModifiedInternlTypesEvent"; @Inject @Named(AppInitializer.LDAP_AUTH_CONFIG_NAME) private List<GluuLdapConfiguration> ldapAuthConfigs; @Inject private InternalDefaultPersonAuthenticationType internalDefaultPersonAuthenticationType; private static final long serialVersionUID = 7339887464253044927L; private Map<AuthenticationScriptUsageType, List<CustomScriptConfiguration>> customScriptConfigurationsMapByUsageType; private Map<AuthenticationScriptUsageType, CustomScriptConfiguration> defaultExternalAuthenticators; public ExternalAuthenticationService() { super(CustomScriptType.PERSON_AUTHENTICATION); } public void reloadAuthScript(@Observes @ReloadAuthScript String event) { reload(event); } @Override protected void reloadExternal() { // Group external authenticator configurations by usage type this.customScriptConfigurationsMapByUsageType = groupCustomScriptConfigurationsMapByUsageType(this.customScriptConfigurationsNameMap); // Determine default authenticator for every usage type this.defaultExternalAuthenticators = determineDefaultCustomScriptConfigurationsMap(this.customScriptConfigurationsNameMap); } @Override protected void addExternalConfigurations(List<CustomScriptConfiguration> newCustomScriptConfigurations) { if ((ldapAuthConfigs == null) || (ldapAuthConfigs.size() == 0)) { newCustomScriptConfigurations.add(getInternalCustomScriptConfiguration()); } else { for (GluuLdapConfiguration ldapAuthConfig : ldapAuthConfigs) { newCustomScriptConfigurations.add(getInternalCustomScriptConfiguration(ldapAuthConfig)); } } } private Map<AuthenticationScriptUsageType, List<CustomScriptConfiguration>> groupCustomScriptConfigurationsMapByUsageType(Map<String, CustomScriptConfiguration> customScriptConfigurationsMap) { Map<AuthenticationScriptUsageType, List<CustomScriptConfiguration>> newCustomScriptConfigurationsMapByUsageType = new HashMap<AuthenticationScriptUsageType, List<CustomScriptConfiguration>>(); for (AuthenticationScriptUsageType usageType : AuthenticationScriptUsageType.values()) { List<CustomScriptConfiguration> currCustomScriptConfigurationsMapByUsageType = new ArrayList<CustomScriptConfiguration>(); for (CustomScriptConfiguration customScriptConfiguration : customScriptConfigurationsMap.values()) { if (!isValidateUsageType(usageType, customScriptConfiguration)) { continue; } currCustomScriptConfigurationsMapByUsageType.add(customScriptConfiguration); } newCustomScriptConfigurationsMapByUsageType.put(usageType, currCustomScriptConfigurationsMapByUsageType); } return newCustomScriptConfigurationsMapByUsageType; } private Map<AuthenticationScriptUsageType, CustomScriptConfiguration> determineDefaultCustomScriptConfigurationsMap(Map<String, CustomScriptConfiguration> customScriptConfigurationsMap) { Map<AuthenticationScriptUsageType, CustomScriptConfiguration> newDefaultCustomScriptConfigurationsMap = new HashMap<AuthenticationScriptUsageType, CustomScriptConfiguration>(); for (AuthenticationScriptUsageType usageType : AuthenticationScriptUsageType.values()) { CustomScriptConfiguration defaultExternalAuthenticator = null; for (CustomScriptConfiguration customScriptConfiguration : customScriptConfigurationsMapByUsageType.get(usageType)) { // Determine default authenticator if ((defaultExternalAuthenticator == null) || (defaultExternalAuthenticator.getLevel() < customScriptConfiguration.getLevel())) { defaultExternalAuthenticator = customScriptConfiguration; } } newDefaultCustomScriptConfigurationsMap.put(usageType, defaultExternalAuthenticator); } return newDefaultCustomScriptConfigurationsMap; } private boolean executeExternalIsValidAuthenticationMethod(AuthenticationScriptUsageType usageType, CustomScriptConfiguration customScriptConfiguration) { try { log.debug("Executing python 'isValidAuthenticationMethod' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.isValidAuthenticationMethod(usageType, configurationAttributes); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return false; } private String executeExternalGetAlternativeAuthenticationMethod(AuthenticationScriptUsageType usageType, CustomScriptConfiguration customScriptConfiguration) { try { log.debug("Executing python 'getAlternativeAuthenticationMethod' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.getAlternativeAuthenticationMethod(usageType, configurationAttributes); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return null; } public int executeExternalGetCountAuthenticationSteps(CustomScriptConfiguration customScriptConfiguration) { try { log.debug("Executing python 'getCountAuthenticationSteps' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.getCountAuthenticationSteps(configurationAttributes); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return -1; } public boolean executeExternalAuthenticate(CustomScriptConfiguration customScriptConfiguration, Map<String, String[]> requestParameters, int step) { try { log.debug("Executing python 'authenticate' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.authenticate(configurationAttributes, requestParameters, step); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return false; } public int getNextStep(CustomScriptConfiguration customScriptConfiguration, Map<String, String[]> requestParameters, int step) { try { log.debug("Executing python 'getNextStep' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.getNextStep(configurationAttributes, requestParameters, step); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return -1; } public boolean executeExternalLogout(CustomScriptConfiguration customScriptConfiguration, Map<String, String[]> requestParameters) { try { log.debug("Executing python 'logout' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.logout(configurationAttributes, requestParameters); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return false; } public String getLogoutExternalUrl(CustomScriptConfiguration customScriptConfiguration, Map<String, String[]> requestParameters) { try { log.debug("Executing python 'getLogouExternalUrl' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.getLogoutExternalUrl(configurationAttributes, requestParameters); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return null; } public boolean executeExternalPrepareForStep(CustomScriptConfiguration customScriptConfiguration, Map<String, String[]> requestParameters, int step) { try { log.debug("Executing python 'prepareForStep' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.prepareForStep(configurationAttributes, requestParameters, step); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return false; } public List<String> executeExternalGetExtraParametersForStep(CustomScriptConfiguration customScriptConfiguration, int step) { try { log.debug("Executing python 'getExtraParametersForStep' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.getExtraParametersForStep(configurationAttributes, step); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return null; } public String executeExternalGetPageForStep(CustomScriptConfiguration customScriptConfiguration, int step) { try { log.debug("Executing python 'getPageForStep' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); Map<String, SimpleCustomProperty> configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); return externalAuthenticator.getPageForStep(configurationAttributes, step); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return null; } public int executeExternalGetApiVersion(CustomScriptConfiguration customScriptConfiguration) { try { log.debug("Executing python 'getApiVersion' authenticator method"); PersonAuthenticationType externalAuthenticator = (PersonAuthenticationType) customScriptConfiguration.getExternalType(); return externalAuthenticator.getApiVersion(); } catch (Exception ex) { log.error(ex.getMessage(), ex); } return -1; } public boolean isEnabled(AuthenticationScriptUsageType usageType) { return this.customScriptConfigurationsMapByUsageType != null && this.customScriptConfigurationsMapByUsageType.get(usageType).size() > 0; } public CustomScriptConfiguration getExternalAuthenticatorByAuthLevel(AuthenticationScriptUsageType usageType, int authLevel) { CustomScriptConfiguration resultDefaultExternalAuthenticator = null; for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurationsMapByUsageType.get(usageType)) { // Determine authenticator if (customScriptConfiguration.getLevel() != authLevel) { continue; } if (resultDefaultExternalAuthenticator == null) { resultDefaultExternalAuthenticator = customScriptConfiguration; } } return resultDefaultExternalAuthenticator; } public CustomScriptConfiguration determineCustomScriptConfiguration(AuthenticationScriptUsageType usageType, int authStep, String acr) { CustomScriptConfiguration customScriptConfiguration; if (authStep == 1) { if (StringHelper.isNotEmpty(acr)) { customScriptConfiguration = getCustomScriptConfiguration(usageType, acr); } else { customScriptConfiguration = getDefaultExternalAuthenticator(usageType); } } else { customScriptConfiguration = getCustomScriptConfiguration(usageType, acr); } return customScriptConfiguration; } public CustomScriptConfiguration determineCustomScriptConfiguration(AuthenticationScriptUsageType usageType, List<String> acrValues) { List<String> authModes = getAuthModesByAcrValues(acrValues); if (authModes.size() > 0) { for (String authMode : authModes) { for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurationsMapByUsageType.get(usageType)) { if (StringHelper.equalsIgnoreCase(authMode, customScriptConfiguration.getName())) { return customScriptConfiguration; } } } } return null; } public List<String> getAuthModesByAcrValues(List<String> acrValues) { List<String> authModes = new ArrayList<String>(); for (String acrValue : acrValues) { if (StringHelper.isNotEmpty(acrValue)) { if (customScriptConfigurationsNameMap.containsKey(StringHelper.toLowerCase(acrValue))) { authModes.add(acrValue); } } } return authModes; } public CustomScriptConfiguration determineExternalAuthenticatorForWorkflow(AuthenticationScriptUsageType usageType, CustomScriptConfiguration customScriptConfiguration) { String authMode = customScriptConfiguration.getName(); log.debug("Validating acr_values: '{}'", authMode); boolean isValidAuthenticationMethod = executeExternalIsValidAuthenticationMethod(usageType, customScriptConfiguration); if (!isValidAuthenticationMethod) { log.warn("Current acr_values: '{}' isn't valid", authMode); String alternativeAuthenticationMethod = executeExternalGetAlternativeAuthenticationMethod(usageType, customScriptConfiguration); if (StringHelper.isEmpty(alternativeAuthenticationMethod)) { log.error("Failed to determine alternative authentication mode for acr_values: '{}'", authMode); return null; } else { CustomScriptConfiguration alternativeCustomScriptConfiguration = getCustomScriptConfiguration(AuthenticationScriptUsageType.INTERACTIVE, alternativeAuthenticationMethod); if (alternativeCustomScriptConfiguration == null) { log.error("Failed to get alternative CustomScriptConfiguration '{}' for acr_values: '{}'", alternativeAuthenticationMethod, authMode); return null; } else { return alternativeCustomScriptConfiguration; } } } return customScriptConfiguration; } public CustomScriptConfiguration getDefaultExternalAuthenticator(AuthenticationScriptUsageType usageType) { return this.defaultExternalAuthenticators.get(usageType); } public CustomScriptConfiguration getCustomScriptConfiguration(AuthenticationScriptUsageType usageType, String name) { for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurationsMapByUsageType.get(usageType)) { if (StringHelper.equalsIgnoreCase(name, customScriptConfiguration.getName())) { return customScriptConfiguration; } } return null; } public CustomScriptConfiguration getCustomScriptConfigurationByName(String name) { for (Entry<String, CustomScriptConfiguration> customScriptConfigurationEntry : this.customScriptConfigurationsNameMap.entrySet()) { if (StringHelper.equalsIgnoreCase(name, customScriptConfigurationEntry.getKey())) { return customScriptConfigurationEntry.getValue(); } } return null; } public List<CustomScriptConfiguration> getCustomScriptConfigurationsMap() { List<CustomScriptConfiguration> configurations = new ArrayList<CustomScriptConfiguration>(this.customScriptConfigurationsNameMap.values()); return configurations; } public List<String> getAcrValuesList() { List<String> acrValues = new ArrayList<String>(); for (CustomScriptConfiguration configuration : getCustomScriptConfigurationsMap()) { acrValues.add(configuration.getName()); } return acrValues; } private boolean isValidateUsageType(AuthenticationScriptUsageType usageType, CustomScriptConfiguration customScriptConfiguration) { if (customScriptConfiguration == null) { return false; } AuthenticationScriptUsageType externalAuthenticatorUsageType = ((AuthenticationCustomScript) customScriptConfiguration.getCustomScript()).getUsageType(); // Set default usage type if (externalAuthenticatorUsageType == null) { externalAuthenticatorUsageType = AuthenticationScriptUsageType.INTERACTIVE; } if (AuthenticationScriptUsageType.BOTH.equals(externalAuthenticatorUsageType)) { return true; } if (AuthenticationScriptUsageType.INTERACTIVE.equals(usageType) && AuthenticationScriptUsageType.INTERACTIVE.equals(externalAuthenticatorUsageType)) { return true; } if (AuthenticationScriptUsageType.SERVICE.equals(usageType) && AuthenticationScriptUsageType.SERVICE.equals(externalAuthenticatorUsageType)) { return true; } return false; } public Map<Integer, Set<String>> levelToAcrMapping() { Map<Integer, Set<String>> map = Maps.newHashMap(); for (CustomScriptConfiguration script : getCustomScriptConfigurationsMap()) { int level = script.getLevel(); String acr = script.getName(); Set<String> acrs = map.get(level); if (acrs == null) { acrs = Sets.newHashSet(); map.put(level, acrs); } acrs.add(acr); } return map; } public Map<String, Integer> acrToLevelMapping() { Map<String, Integer> map = Maps.newHashMap(); for (CustomScriptConfiguration script : getCustomScriptConfigurationsMap()) { map.put(script.getName(), script.getLevel()); } return map; } private CustomScriptConfiguration getInternalCustomScriptConfiguration(GluuLdapConfiguration ldapAuthConfig) { CustomScriptConfiguration customScriptConfiguration = getInternalCustomScriptConfiguration(); customScriptConfiguration.getCustomScript().setName(ldapAuthConfig.getConfigId()); return customScriptConfiguration; } private CustomScriptConfiguration getInternalCustomScriptConfiguration() { CustomScript customScript = new AuthenticationCustomScript() { @Override public AuthenticationScriptUsageType getUsageType() { return AuthenticationScriptUsageType.INTERACTIVE; } }; customScript.setName(OxConstants.SCRIPT_TYPE_INTERNAL_RESERVED_NAME); customScript.setLevel(-1); return new CustomScriptConfiguration(customScript, internalDefaultPersonAuthenticationType, new HashMap<String, SimpleCustomProperty>(0)); } }