/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*******************************************************************************/
package org.cloudfoundry.identity.uaa.provider.saml;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.provider.SamlIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.SamlIdentityProviderDefinition.ExternalGroupMappingMode;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import static org.cloudfoundry.identity.uaa.provider.AbstractIdentityProviderDefinition.EMAIL_DOMAIN_ATTR;
import static org.cloudfoundry.identity.uaa.provider.AbstractIdentityProviderDefinition.PROVIDER_DESCRIPTION;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.ATTRIBUTE_MAPPINGS;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.EXTERNAL_GROUPS_WHITELIST;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.STORE_CUSTOM_ATTRIBUTES_NAME;
import static org.springframework.util.StringUtils.hasText;
public class BootstrapSamlIdentityProviderConfigurator implements InitializingBean {
private static Log logger = LogFactory.getLog(BootstrapSamlIdentityProviderConfigurator.class);
private String legacyIdpIdentityAlias;
private volatile String legacyIdpMetaData;
private String legacyNameId;
private int legacyAssertionConsumerIndex;
private boolean legacyMetadataTrustCheck = true;
private boolean legacyShowSamlLink = true;
private List<SamlIdentityProviderDefinition> identityProviders = new LinkedList<>();
private List<SamlIdentityProviderDefinition> toBeFetchedProviders = new LinkedList<>();
private Timer dummyTimer = new Timer() {
@Override public void cancel() { super.cancel(); }
@Override public int purge() {return 0; }
@Override public void schedule(TimerTask task, long delay) {}
@Override public void schedule(TimerTask task, long delay, long period) {}
@Override public void schedule(TimerTask task, Date firstTime, long period) {}
@Override public void schedule(TimerTask task, Date time) {}
@Override public void scheduleAtFixedRate(TimerTask task, long delay, long period) {}
@Override public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {}
};
public BootstrapSamlIdentityProviderConfigurator() {
dummyTimer.cancel();
}
public List<SamlIdentityProviderDefinition> getIdentityProviderDefinitions() {
return Collections.unmodifiableList(new ArrayList<>(identityProviders));
}
protected void parseIdentityProviderDefinitions() {
identityProviders.clear();
if (getLegacyIdpMetaData()!=null) {
SamlIdentityProviderDefinition def = new SamlIdentityProviderDefinition();
def.setMetaDataLocation(getLegacyIdpMetaData());
def.setMetadataTrustCheck(isLegacyMetadataTrustCheck());
def.setNameID(getLegacyNameId());
def.setAssertionConsumerIndex(getLegacyAssertionConsumerIndex());
String alias = getLegacyIdpIdentityAlias();
if (alias==null) {
throw new IllegalArgumentException("Invalid IDP - Alias must be not null for deprecated IDP.");
}
def.setIdpEntityAlias(alias);
def.setShowSamlLink(isLegacyShowSamlLink());
def.setLinkText("Use your corporate credentials");
def.setZoneId(IdentityZone.getUaa().getId()); //legacy only has UAA zone
identityProviders.add(def);
}
Set<String> uniqueAlias = new HashSet<>();
for (SamlIdentityProviderDefinition def : toBeFetchedProviders) {
String alias = getUniqueAlias(def);
if (uniqueAlias.contains(alias)) {
throw new IllegalStateException("Duplicate IDP alias found:"+alias);
}
uniqueAlias.add(alias);
identityProviders.add(def);
}
}
protected String getUniqueAlias(SamlIdentityProviderDefinition def) {
return def.getUniqueAlias();
}
public void setIdentityProviders(Map<String, Map<String, Object>> providers) {
identityProviders.clear();
toBeFetchedProviders.clear();
if (providers == null) {
return;
}
for (Map.Entry entry : providers.entrySet()) {
String alias = (String)entry.getKey();
Map<String, Object> saml = (Map<String, Object>)entry.getValue();
String metaDataLocation = (String)saml.get("idpMetadata");
String nameID = (String)saml.get("nameID");
Integer assertionIndex = (Integer)saml.get("assertionConsumerIndex");
Boolean trustCheck = (Boolean)saml.get("metadataTrustCheck");
Boolean showLink = (Boolean)((Map)entry.getValue()).get("showSamlLoginLink");
String socketFactoryClassName = (String)saml.get("socketFactoryClassName");
String linkText = (String)((Map)entry.getValue()).get("linkText");
String iconUrl = (String)((Map)entry.getValue()).get("iconUrl");
String zoneId = (String)((Map)entry.getValue()).get("zoneId");
String groupMappingMode = (String)((Map)entry.getValue()).get("groupMappingMode");
String providerDescription = (String)((Map)entry.getValue()).get(PROVIDER_DESCRIPTION);
Boolean addShadowUserOnLogin = (Boolean)((Map)entry.getValue()).get("addShadowUserOnLogin");
Boolean skipSslValidation = (Boolean)((Map)entry.getValue()).get("skipSslValidation");
Boolean storeCustomAttributes = (Boolean)((Map)entry.getValue()).get(STORE_CUSTOM_ATTRIBUTES_NAME);
if (storeCustomAttributes == null) {
storeCustomAttributes = false; //default value
}
if (skipSslValidation==null) {
if (socketFactoryClassName != null) {
skipSslValidation = false;
} else {
skipSslValidation = true;
}
}
List<String> emailDomain = (List<String>) saml.get(EMAIL_DOMAIN_ATTR);
List<String> externalGroupsWhitelist = (List<String>) saml.get(EXTERNAL_GROUPS_WHITELIST);
Map<String, Object> attributeMappings = (Map<String, Object>) saml.get(ATTRIBUTE_MAPPINGS);
SamlIdentityProviderDefinition def = new SamlIdentityProviderDefinition();
def.setStoreCustomAttributes(storeCustomAttributes);
if (hasText(providerDescription)) {
def.setProviderDescription(providerDescription);
}
if (alias==null) {
throw new IllegalArgumentException("Invalid IDP - alias must not be null ["+metaDataLocation+"]");
}
if (metaDataLocation==null) {
throw new IllegalArgumentException("Invalid IDP - metaDataLocation must not be null ["+alias+"]");
}
def.setIdpEntityAlias(alias);
def.setAssertionConsumerIndex(assertionIndex== null ? 0 :assertionIndex);
def.setMetaDataLocation(metaDataLocation);
def.setNameID(nameID);
def.setMetadataTrustCheck(trustCheck==null?true:trustCheck);
if(hasText(groupMappingMode)) { def.setGroupMappingMode(ExternalGroupMappingMode.valueOf(groupMappingMode)); }
def.setShowSamlLink(showLink==null?true: showLink);
def.setSocketFactoryClassName(socketFactoryClassName);
def.setLinkText(linkText);
def.setIconUrl(iconUrl);
def.setEmailDomain(emailDomain);
def.setExternalGroupsWhitelist(externalGroupsWhitelist);
def.setAttributeMappings(attributeMappings);
def.setZoneId(hasText(zoneId) ? zoneId : IdentityZone.getUaa().getId());
def.setAddShadowUserOnLogin(addShadowUserOnLogin==null?true:addShadowUserOnLogin);
def.setSkipSslValidation(skipSslValidation);
toBeFetchedProviders.add(def);
}
}
public String getLegacyIdpIdentityAlias() {
return legacyIdpIdentityAlias;
}
public void setLegacyIdpIdentityAlias(String legacyIdpIdentityAlias) {
if ("null".equals(legacyIdpIdentityAlias)) {
this.legacyIdpIdentityAlias = null;
} else {
this.legacyIdpIdentityAlias = legacyIdpIdentityAlias;
}
}
public String getLegacyIdpMetaData() {
return legacyIdpMetaData;
}
public void setLegacyIdpMetaData(String legacyIdpMetaData) {
if ("null".equals(legacyIdpMetaData)) {
this.legacyIdpMetaData = null;
} else {
this.legacyIdpMetaData = legacyIdpMetaData;
}
}
public String getLegacyNameId() {
return legacyNameId;
}
public void setLegacyNameId(String legacyNameId) {
this.legacyNameId = legacyNameId;
}
public int getLegacyAssertionConsumerIndex() {
return legacyAssertionConsumerIndex;
}
public void setLegacyAssertionConsumerIndex(int legacyAssertionConsumerIndex) {
this.legacyAssertionConsumerIndex = legacyAssertionConsumerIndex;
}
public boolean isLegacyMetadataTrustCheck() {
return legacyMetadataTrustCheck;
}
public void setLegacyMetadataTrustCheck(boolean legacyMetadataTrustCheck) {
this.legacyMetadataTrustCheck = legacyMetadataTrustCheck;
}
public boolean isLegacyShowSamlLink() {
return legacyShowSamlLink;
}
public void setLegacyShowSamlLink(boolean legacyShowSamlLink) {
this.legacyShowSamlLink = legacyShowSamlLink;
}
@Override
public void afterPropertiesSet() throws Exception {
parseIdentityProviderDefinitions();
}
}