package com.onelogin.saml2.settings;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.onelogin.saml2.exception.Error;
import com.onelogin.saml2.model.Contact;
import com.onelogin.saml2.model.Organization;
import com.onelogin.saml2.util.Util;
/**
* SettingsBuilder class of OneLogin's Java Toolkit.
*
* A class that implements the settings builder
*/
public class SettingsBuilder {
/**
* Private property to construct a logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(SettingsBuilder.class);
/**
* Private property that contains the SAML settings
*/
private Properties prop = new Properties();
/**
* Saml2Settings object
*/
private Saml2Settings saml2Setting;
public final static String STRICT_PROPERTY_KEY = "onelogin.saml2.strict";
public final static String DEBUG_PROPERTY_KEY = "onelogin.saml2.debug";
// SP
public final static String SP_ENTITYID_PROPERTY_KEY = "onelogin.saml2.sp.entityid";
public final static String SP_ASSERTION_CONSUMER_SERVICE_URL_PROPERTY_KEY = "onelogin.saml2.sp.assertion_consumer_service.url";
public final static String SP_ASSERTION_CONSUMER_SERVICE_BINDING_PROPERTY_KEY = "onelogin.saml2.sp.assertion_consumer_service.binding";
public final static String SP_SINGLE_LOGOUT_SERVICE_URL_PROPERTY_KEY = "onelogin.saml2.sp.single_logout_service.url";
public final static String SP_SINGLE_LOGOUT_SERVICE_BINDING_PROPERTY_KEY = "onelogin.saml2.sp.single_logout_service.binding";
public final static String SP_NAMEIDFORMAT_PROPERTY_KEY = "onelogin.saml2.sp.nameidformat";
public final static String SP_X509CERT_PROPERTY_KEY = "onelogin.saml2.sp.x509cert";
public final static String SP_PRIVATEKEY_PROPERTY_KEY = "onelogin.saml2.sp.privatekey";
// IDP
public final static String IDP_ENTITYID_PROPERTY_KEY = "onelogin.saml2.idp.entityid";
public final static String IDP_SINGLE_SIGN_ON_SERVICE_URL_PROPERTY_KEY = "onelogin.saml2.idp.single_sign_on_service.url";
public final static String IDP_SINGLE_SIGN_ON_SERVICE_BINDING_PROPERTY_KEY = "onelogin.saml2.idp.single_sign_on_service.binding";
public final static String IDP_SINGLE_LOGOUT_SERVICE_URL_PROPERTY_KEY = "onelogin.saml2.idp.single_logout_service.url";
public final static String IDP_SINGLE_LOGOUT_SERVICE_RESPONSE_URL_PROPERTY_KEY = "onelogin.saml2.idp.single_logout_service.response.url";
public final static String IDP_SINGLE_LOGOUT_SERVICE_BINDING_PROPERTY_KEY = "onelogin.saml2.idp.single_logout_service.binding";
public final static String IDP_X509CERT_PROPERTY_KEY = "onelogin.saml2.idp.x509cert";
public final static String CERTFINGERPRINT_PROPERTY_KEY = "onelogin.saml2.idp.certfingerprint";
public final static String CERTFINGERPRINT_ALGORITHM_PROPERTY_KEY = "onelogin.saml2.idp.certfingerprint_algorithm";
// Security
public final static String SECURITY_NAMEID_ENCRYPTED = "onelogin.saml2.security.nameid_encrypted";
public final static String SECURITY_AUTHREQUEST_SIGNED = "onelogin.saml2.security.authnrequest_signed";
public final static String SECURITY_LOGOUTREQUEST_SIGNED = "onelogin.saml2.security.logoutrequest_signed";
public final static String SECURITY_LOGOUTRESPONSE_SIGNED = "onelogin.saml2.security.logoutresponse_signed";
public final static String SECURITY_WANT_MESSAGES_SIGNED = "onelogin.saml2.security.want_messages_signed";
public final static String SECURITY_WANT_ASSERTIONS_SIGNED = "onelogin.saml2.security.want_assertions_signed";
public final static String SECURITY_WANT_ASSERTIONS_ENCRYPTED = "onelogin.saml2.security.want_assertions_encrypted";
public final static String SECURITY_WANT_NAMEID = "onelogin.saml2.security.want_nameid";
public final static String SECURITY_WANT_NAMEID_ENCRYPTED = "onelogin.saml2.security.want_nameid_encrypted";
public final static String SECURITY_SIGN_METADATA = "onelogin.saml2.security.sign_metadata";
public final static String SECURITY_REQUESTED_AUTHNCONTEXT = "onelogin.saml2.security.requested_authncontext";
public final static String SECURITY_REQUESTED_AUTHNCONTEXTCOMPARISON = "onelogin.saml2.security.requested_authncontextcomparison";
public final static String SECURITY_WANT_XML_VALIDATION = "onelogin.saml2.security.want_xml_validation";
public final static String SECURITY_SIGNATURE_ALGORITHM = "onelogin.saml2.security.signature_algorithm";
public final static String SECURITY_REJECT_UNSOLICITED_RESPONSES_WITH_INRESPONSETO = "onelogin.saml2.security.reject_unsolicited_responses_with_inresponseto";
// Compress
public final static String COMPRESS_REQUEST = "onelogin.saml2.compress.request";
public final static String COMPRESS_RESPONSE = "onelogin.saml2.compress.response";
// Misc
public final static String CONTACT_TECHNICAL_GIVEN_NAME = "onelogin.saml2.contacts.technical.given_name";
public final static String CONTACT_TECHNICAL_EMAIL_ADDRESS = "onelogin.saml2.contacts.technical.email_address";
public final static String CONTACT_SUPPORT_GIVEN_NAME = "onelogin.saml2.contacts.support.given_name";
public final static String CONTACT_SUPPORT_EMAIL_ADDRESS = "onelogin.saml2.contacts.support.email_address";
public final static String ORGANIZATION_NAME = "onelogin.saml2.organization.name";
public final static String ORGANIZATION_DISPLAYNAME = "onelogin.saml2.organization.displayname";
public final static String ORGANIZATION_URL = "onelogin.saml2.organization.url";
/**
* Load settings from the file
*
* @param propFileName
* OneLogin_Saml2_Settings
*
* @return the SettingsBuilder object with the settings loaded from the file
*
* @throws IOException
* @throws Error
*/
public SettingsBuilder fromFile(String propFileName) throws IOException, Error {
this.loadPropFile(propFileName);
return this;
}
/**
* Loads the settings from the properties file
*
* @param propFileName
* the name of the file
*
* @throws IOException
* @throws Error
*/
private void loadPropFile(String propFileName) throws IOException, Error {
InputStream inputStream = null;
try {
inputStream = getClass().getClassLoader().getResourceAsStream(propFileName);
if (inputStream != null) {
this.prop.load(inputStream);
LOGGER.debug("properties file " + propFileName + "loaded succesfully");
} else {
String errorMsg = "properties file '" + propFileName + "' not found in the classpath";
LOGGER.error(errorMsg);
throw new Error(errorMsg, Error.SETTINGS_FILE_NOT_FOUND);
}
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
LOGGER.warn("properties file '" + propFileName + "' not closed properly.");
}
}
}
/**
* Loads the settings from a properties object
*
* @param prop
* contains the properties
*
* @return the SettingsBuilder object with the settings loaded from the prop object
*/
public SettingsBuilder fromProperties(Properties prop) {
this.prop = prop;
return this;
}
/**
* Builds the Saml2Settings object. Read the Properties object and set all the SAML settings
*
* @return the Saml2Settings object with all the SAML settings loaded
*
* @throws IOException
*/
public Saml2Settings build() throws IOException {
saml2Setting = new Saml2Settings();
Boolean strict = loadBooleanProperty(STRICT_PROPERTY_KEY);
if (strict != null)
saml2Setting.setStrict(strict);
Boolean debug = loadBooleanProperty(DEBUG_PROPERTY_KEY);
if (debug != null)
saml2Setting.setDebug(debug);
this.loadSpSetting();
this.loadIdpSetting();
this.loadSecuritySetting();
this.loadCompressSetting();
saml2Setting.setContacts(loadContacts());
saml2Setting.setOrganization(loadOrganization());
return saml2Setting;
}
/**
* Loads the IdP settings from the properties file
*/
private void loadIdpSetting() {
String idpEntityID = loadStringProperty(IDP_ENTITYID_PROPERTY_KEY);
if (idpEntityID != null)
saml2Setting.setIdpEntityId(idpEntityID);
URL idpSingleSignOnServiceUrl = loadURLProperty(IDP_SINGLE_SIGN_ON_SERVICE_URL_PROPERTY_KEY);
if (idpSingleSignOnServiceUrl != null)
saml2Setting.setIdpSingleSignOnServiceUrl(idpSingleSignOnServiceUrl);
String idpSingleSignOnServiceBinding = loadStringProperty(IDP_SINGLE_SIGN_ON_SERVICE_BINDING_PROPERTY_KEY);
if (idpSingleSignOnServiceBinding != null)
saml2Setting.setIdpSingleSignOnServiceBinding(idpSingleSignOnServiceBinding);
URL idpSingleLogoutServiceUrl = loadURLProperty(IDP_SINGLE_LOGOUT_SERVICE_URL_PROPERTY_KEY);
if (idpSingleLogoutServiceUrl != null)
saml2Setting.setIdpSingleLogoutServiceUrl(idpSingleLogoutServiceUrl);
URL idpSingleLogoutServiceResponseUrl = loadURLProperty(IDP_SINGLE_LOGOUT_SERVICE_RESPONSE_URL_PROPERTY_KEY);
if (idpSingleLogoutServiceResponseUrl != null)
saml2Setting.setIdpSingleLogoutServiceResponseUrl(idpSingleLogoutServiceResponseUrl);
String idpSingleLogoutServiceBinding = loadStringProperty(IDP_SINGLE_LOGOUT_SERVICE_BINDING_PROPERTY_KEY);
if (idpSingleLogoutServiceBinding != null)
saml2Setting.setIdpSingleLogoutServiceBinding(idpSingleLogoutServiceBinding);
X509Certificate idpX509cert = loadCertificateFromProp(IDP_X509CERT_PROPERTY_KEY);
if (idpX509cert != null)
saml2Setting.setIdpx509cert(idpX509cert);
String idpCertFingerprint = loadStringProperty(CERTFINGERPRINT_PROPERTY_KEY);
if (idpCertFingerprint != null)
saml2Setting.setIdpCertFingerprint(idpCertFingerprint);
String idpCertFingerprintAlgorithm = loadStringProperty(CERTFINGERPRINT_ALGORITHM_PROPERTY_KEY);
if (idpCertFingerprintAlgorithm != null && !idpCertFingerprintAlgorithm.isEmpty())
saml2Setting.setIdpCertFingerprintAlgorithm(idpCertFingerprintAlgorithm);
}
/**
* Loads the security settings from the properties file
*/
private void loadSecuritySetting() {
Boolean nameIdEncrypted = loadBooleanProperty(SECURITY_NAMEID_ENCRYPTED);
if (nameIdEncrypted != null)
saml2Setting.setNameIdEncrypted(nameIdEncrypted);
Boolean authnRequestsSigned = loadBooleanProperty(SECURITY_AUTHREQUEST_SIGNED);
if (authnRequestsSigned != null)
saml2Setting.setAuthnRequestsSigned(authnRequestsSigned);
Boolean logoutRequestSigned = loadBooleanProperty(SECURITY_LOGOUTREQUEST_SIGNED);
if (logoutRequestSigned != null)
saml2Setting.setLogoutRequestSigned(logoutRequestSigned);
Boolean logoutResponseSigned = loadBooleanProperty(SECURITY_LOGOUTRESPONSE_SIGNED);
if (logoutResponseSigned != null)
saml2Setting.setLogoutResponseSigned(logoutResponseSigned);
Boolean wantMessagesSigned = loadBooleanProperty(SECURITY_WANT_MESSAGES_SIGNED);
if (wantMessagesSigned != null)
saml2Setting.setWantMessagesSigned(wantMessagesSigned);
Boolean wantAssertionsSigned = loadBooleanProperty(SECURITY_WANT_ASSERTIONS_SIGNED);
if (wantAssertionsSigned != null)
saml2Setting.setWantAssertionsSigned(wantAssertionsSigned);
Boolean wantAssertionsEncrypted = loadBooleanProperty(SECURITY_WANT_ASSERTIONS_ENCRYPTED);
if (wantAssertionsEncrypted != null)
saml2Setting.setWantAssertionsEncrypted(wantAssertionsEncrypted);
Boolean wantNameId = loadBooleanProperty(SECURITY_WANT_NAMEID);
if (wantNameId != null)
saml2Setting.setWantNameId(wantNameId);
Boolean wantNameIdEncrypted = loadBooleanProperty(SECURITY_WANT_NAMEID_ENCRYPTED);
if (wantNameIdEncrypted != null)
saml2Setting.setWantNameIdEncrypted(wantNameIdEncrypted);
Boolean wantXMLValidation = loadBooleanProperty(SECURITY_WANT_XML_VALIDATION);
if (wantXMLValidation != null)
saml2Setting.setWantXMLValidation(wantXMLValidation);
Boolean signMetadata = loadBooleanProperty(SECURITY_SIGN_METADATA);
if (signMetadata != null)
saml2Setting.setSignMetadata(signMetadata);
List<String> requestedAuthnContext = loadListProperty(SECURITY_REQUESTED_AUTHNCONTEXT);
if (requestedAuthnContext != null)
saml2Setting.setRequestedAuthnContext(requestedAuthnContext);
String requestedAuthnContextComparison = loadStringProperty(SECURITY_REQUESTED_AUTHNCONTEXTCOMPARISON);
if (requestedAuthnContextComparison != null && !requestedAuthnContextComparison.isEmpty())
saml2Setting.setRequestedAuthnContextComparison(requestedAuthnContextComparison);
String signatureAlgorithm = loadStringProperty(SECURITY_SIGNATURE_ALGORITHM);
if (signatureAlgorithm != null && !signatureAlgorithm.isEmpty())
saml2Setting.setSignatureAlgorithm(signatureAlgorithm);
Boolean rejectUnsolicitedResponsesWithInResponseTo = loadBooleanProperty(SECURITY_REJECT_UNSOLICITED_RESPONSES_WITH_INRESPONSETO);
if (rejectUnsolicitedResponsesWithInResponseTo != null) {
saml2Setting.setRejectUnsolicitedResponsesWithInResponseTo(rejectUnsolicitedResponsesWithInResponseTo);
}
}
/**
* Loads the compress settings from the properties file
*/
private void loadCompressSetting() {
Boolean compressRequest = loadBooleanProperty(COMPRESS_REQUEST);
if (compressRequest != null) {
saml2Setting.setCompressRequest(compressRequest);
}
Boolean compressResponse = loadBooleanProperty(COMPRESS_RESPONSE);
if (compressResponse != null) {
saml2Setting.setCompressResponse(compressResponse);
}
}
/**
* Loads the organization settings from the properties file
*/
private Organization loadOrganization() {
Organization orgResult = null;
String orgName = loadStringProperty(ORGANIZATION_NAME);
String orgDisplayName = loadStringProperty(ORGANIZATION_DISPLAYNAME);
URL orgUrl = loadURLProperty(ORGANIZATION_URL);
if ((orgName != null && !orgName.isEmpty()) || (orgDisplayName != null && !orgDisplayName.isEmpty()) || (orgUrl != null)) {
orgResult = new Organization(orgName, orgDisplayName, orgUrl);
}
return orgResult;
}
/**
* Loads the contacts settings from the properties file
*/
private List<Contact> loadContacts() {
List<Contact> contacts = new LinkedList<Contact>();
String technicalGn = loadStringProperty(CONTACT_TECHNICAL_GIVEN_NAME);
String technicalEmailAddress = loadStringProperty(CONTACT_TECHNICAL_EMAIL_ADDRESS);
if ((technicalGn != null && !technicalGn.isEmpty()) || (technicalEmailAddress != null && !technicalEmailAddress.isEmpty())) {
Contact technical = new Contact("technical", technicalGn, technicalEmailAddress);
contacts.add(technical);
}
String supportGn = loadStringProperty(CONTACT_SUPPORT_GIVEN_NAME);
String supportEmailAddress = loadStringProperty(CONTACT_SUPPORT_EMAIL_ADDRESS);
if ((supportGn != null && !supportGn.isEmpty()) || (supportEmailAddress != null && !supportEmailAddress.isEmpty())) {
Contact support = new Contact("support", supportGn, supportEmailAddress);
contacts.add(support);
}
return contacts;
}
/**
* Loads the SP settings from the properties file
*/
private void loadSpSetting() {
String spEntityID = loadStringProperty(SP_ENTITYID_PROPERTY_KEY);
if (spEntityID != null)
saml2Setting.setSpEntityId(spEntityID);
URL assertionConsumerServiceUrl = loadURLProperty(SP_ASSERTION_CONSUMER_SERVICE_URL_PROPERTY_KEY);
if (assertionConsumerServiceUrl != null)
saml2Setting.setSpAssertionConsumerServiceUrl(assertionConsumerServiceUrl);
String spAssertionConsumerServiceBinding = loadStringProperty(SP_ASSERTION_CONSUMER_SERVICE_BINDING_PROPERTY_KEY);
if (spAssertionConsumerServiceBinding != null)
saml2Setting.setSpAssertionConsumerServiceBinding(spAssertionConsumerServiceBinding);
URL spSingleLogoutServiceUrl = loadURLProperty(SP_SINGLE_LOGOUT_SERVICE_URL_PROPERTY_KEY);
if (spSingleLogoutServiceUrl != null)
saml2Setting.setSpSingleLogoutServiceUrl(spSingleLogoutServiceUrl);
String spSingleLogoutServiceBinding = loadStringProperty(SP_SINGLE_LOGOUT_SERVICE_BINDING_PROPERTY_KEY);
if (spSingleLogoutServiceBinding != null)
saml2Setting.setSpSingleLogoutServiceBinding(spSingleLogoutServiceBinding);
String spNameIDFormat = loadStringProperty(SP_NAMEIDFORMAT_PROPERTY_KEY);
if (spNameIDFormat != null && !spNameIDFormat.isEmpty())
saml2Setting.setSpNameIDFormat(spNameIDFormat);
X509Certificate spX509cert = loadCertificateFromProp(SP_X509CERT_PROPERTY_KEY);
if (spX509cert != null)
saml2Setting.setSpX509cert(spX509cert);
PrivateKey spPrivateKey = loadPrivateKeyFromProp(SP_PRIVATEKEY_PROPERTY_KEY);
if (spPrivateKey != null)
saml2Setting.setSpPrivateKey(spPrivateKey);
}
/**
* Loads a property of the type String from the Properties object
*
* @param propertyKey
* the property name
*
* @return the value
*/
private String loadStringProperty(String propertyKey) {
String propValue = prop.getProperty(propertyKey);
if (propValue != null) {
propValue = propValue.trim();
}
return propValue;
}
/**
* Loads a property of the type Boolean from the Properties object
*
* @param propertyKey
* the property name
*
* @return the value
*/
private Boolean loadBooleanProperty(String propertyKey) {
String booleanPropValue = prop.getProperty(propertyKey);
if (booleanPropValue != null) {
return Boolean.parseBoolean(booleanPropValue.trim());
} else {
return null;
}
}
/**
* Loads a property of the type List from the Properties object
*
* @param propertyKey
* the property name
*
* @return the value
*/
private List<String> loadListProperty(String propertyKey) {
String arrayPropValue = prop.getProperty(propertyKey);
if (arrayPropValue != null && !arrayPropValue.isEmpty()) {
String [] values = arrayPropValue.trim().split(",");
for (int i = 0; i < values.length; i++) {
values[i] = values[i].trim();
}
return Arrays.asList(values);
} else {
return null;
}
}
/**
* Loads a property of the type URL from the Properties object
*
* @param propertyKey
* the property name
*
* @return the value
*/
private URL loadURLProperty(String propertyKey) {
String urlPropValue = prop.getProperty(propertyKey);
if (urlPropValue == null || urlPropValue.isEmpty()) {
return null;
} else {
try {
return new URL(urlPropValue.trim());
} catch (MalformedURLException e) {
LOGGER.error("'" + propertyKey + "' contains malformed url.", e);
return null;
}
}
}
/**
* Loads a property of the type X509Certificate from the Properties object
*
* @param propertyKey
* the property name
*
* @return the X509Certificate object
*/
protected X509Certificate loadCertificateFromProp(String propertyKey) {
String certString = prop.getProperty(propertyKey);
if (certString == null || certString.isEmpty()) {
return null;
} else {
try {
return Util.loadCert(certString);
} catch (CertificateException e) {
LOGGER.error("Error loading certificate from properties.", e);
return null;
} catch (UnsupportedEncodingException e) {
LOGGER.error("the certificate is not in correct format.", e);
return null;
}
}
}
/**
* Loads a property of the type X509Certificate from file
*
* @param filename
* the file name of the file that contains the X509Certificate
*
* @return the X509Certificate object
*/
/*
protected X509Certificate loadCertificateFromFile(String filename) {
String certString = null;
try {
certString = Util.getFileAsString(filename.trim());
} catch (URISyntaxException e) {
LOGGER.error("Error loading certificate from file.", e);
return null;
}
catch (IOException e) {
LOGGER.error("Error loading certificate from file.", e);
return null;
}
try {
return Util.loadCert(certString);
} catch (CertificateException e) {
LOGGER.error("Error loading certificate from file.", e);
return null;
} catch (UnsupportedEncodingException e) {
LOGGER.error("the certificate is not in correct format.", e);
return null;
}
}
*/
/**
* Loads a property of the type PrivateKey from the Properties object
*
* @param propertyKey
* the property name
*
* @return the PrivateKey object
*/
protected PrivateKey loadPrivateKeyFromProp(String propertyKey) {
String keyString = prop.getProperty(propertyKey);
if (keyString == null || keyString.isEmpty()) {
return null;
} else {
try {
return Util.loadPrivateKey(keyString);
} catch (Exception e) {
LOGGER.error("Error loading privatekey from properties.", e);
return null;
}
}
}
/**
* Loads a property of the type PrivateKey from file
*
* @param filename
* the file name of the file that contains the PrivateKey
*
* @return the PrivateKey object
*/
/*
protected PrivateKey loadPrivateKeyFromFile(String filename) {
String keyString = null;
try {
keyString = Util.getFileAsString(filename.trim());
} catch (URISyntaxException e) {
LOGGER.error("Error loading privatekey from file.", e);
return null;
} catch (IOException e) {
LOGGER.error("Error loading privatekey from file.", e);
return null;
}
try {
return Util.loadPrivateKey(keyString);
} catch (GeneralSecurityException e) {
LOGGER.error("Error loading privatekey from file.", e);
return null;
} catch (IOException e) {
LOGGER.debug("Error loading privatekey from file.", e);
return null;
}
}
*/
}