SAML stands for Security Assertion Markup Language. It is a current standard for authenticating users in a distributed system.
Stages acts as a SAML Service Provider (SP) and interacts with a SAML Identity provider (IdP) to authenticate users.
If you already have a SSL server certificate for Stages, you can use that certificate to sign the SAML requests. If you use encrypted SAML assertions - a separate certificate is required. If you do not have a certificate or you want to use a separate certificate, use the follwing command:
keytool -genkeypair -alias "samlkeyalias" -keyalg RSA -keysize 2048 -validity 1095 -keystore "conf/saml-keystore.jks"
Enter your Stages Domain Name when asked for the First and Last Name. The rest of the parameters can be set arbitrarily.
You can choose an arbitrary key name (e.g. samlkeyalias) and location for the keystore (e.g. conf/saml-keystore.jks), they just need to be the same as you configure below.
To configure, add or enable the following section in conf/config.xml:
<authentication> [...] <method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> <properties> <property name="serviceProviderEntityId" value="${sp.id}"/> <property name="keystorePath" value="${sp.saml.keystore.path}"/> <property name="keystorePassword" value="${sp.saml.keystore.password}"/> <property name="privateKeyPassword" value="${sp.saml.keystore.password}"/> <property name="keyStoreAlias" value="${sp.saml.keystore.keyAlias}"/> [...] </properties> </method> </authentication>
To globally enable SAML, set the enabled attribute to true. The keystore location and password need to match the keystore from above.
The serviceProviderEntityId can be an arbitrary name, but it should be globally unique, so it is a good practice to use your Stages URL.
The keyStoreAlias identifies the key to be used for signing the SAML request, so it needs to match the key you generated above.
conf/config.properties:
sp.id = https://stages.example.com #needs to be generated. Path needs to be relative to ${STAGES_ROOT} sp.saml.keystore.path = file:conf/secret/saml-keystore.pk12 idp.saml.enabled = true
conf/secret.properties:
# for keystore at sp.saml.keystore.path sp.saml.keystore.keyAlias = stages sp.saml.keystore.password = SECRET
Please make sure to call update.sh|bat after enabling or disabling SAML and restart Stages.
When you are done with generating the keystore and other service provider attributes, you should add the following line to the authentication method section from above to generate the sp-metadata.xml file for the SAML IdP administrators
<authentication> [...] <method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> <properties> [...] <property name="serviceProviderMetadataPath" value="${sp.saml.metadata.path}"/> [...] </properties> </method> </authentication>
conf/config.properties
sp.saml.metadata.path=file:data-cache/generated/sp-metadata.xml
Restart Stages and access the Login page. The sp-metadata.xml should now be generated.
The resulting XML file can be sent to the SAML IdP administrators and contains all information necessary to set up the trust relationship on the IdP side.
Please note that you need to delete the sp-metadata.xml file whenever you change the service provider configuration. An existing file will never be updated
After the SAML IdP has been configured with the SP metadata, you will receive an idp-metadata.xml file with the IDP specific part of the SAML configuration.
The SAML Identity Provider describes the remote service that Stages uses to authenticate users. Typically, it is run by the access management group within your IT organization.
The most reliable way to configure the SAML Identity Provider (IdP) is to ask the access management team for the IdP metadata.
Store this metadata in conf/secret/idp-metadata.xml and add the following configuration to
conf/config.xml
<method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> <properties> [...] <property name="identityProviderMetadataPath" value="${idp.saml.metadata.path}"/> [...] </properties> [...] </method>
conf/config.properties
idp.saml.metadata.path = file:conf/secret/idp-metadata.xml
A complete SAML configuration should then look like that:
<method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> <properties> <property name="serviceProviderEntityId" value="${sp.id}"/> <property name="keystorePath" value="${sp.saml.keystore.path}"/> <property name="keystorePassword" value="${sp.saml.keystore.password}"/> <property name="privateKeyPassword" value="${sp.saml.keystore.password}"/> <property name="keyStoreAlias" value="${sp.saml.keystore.keyAlias}"/> <property name="serviceProviderMetadataPath" value="${sp.saml.metadata.path}"/> <property name="identityProviderMetadataPath" value="${idp.saml.metadata.path}"/> <property name="nameIdPolicyFormat" value="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /> <property name="mappedAttributes(_subject_nameid_)" value="username"/> <property name="mappedAttributes(${idp.saml.attribute.firstname})" value="firstname"/> <property name="mappedAttributes(${idp.saml.attribute.lastname})" value="lastname"/> <property name="mappedAttributes(${idp.saml.attribute.email})" value="email"/> <property name="internal.userFullnameTemplate" value="${idp.saml.fullname.template}"/> </properties> <filters> <!-- This is the default matcher, identified by id and pattern attributes set to "*" --> <attribute-match id="*" pattern="*" defaultUserGroupsUsername="${user.default.username}" defaultLicenseType="${user.default.licenseType}" autocreateUser="${idp.saml.autocreate}" /> </filters> </method>
conf/config.properties
sp.id = https://stages.example.com #needs to be generated. Path needs to be relative to ${STAGES_ROOT} sp.saml.keystore.path = file:conf/secret/saml-keystore.pk12 #will be generated on first login page access (path needs to be relative to ${STAGES_ROOT}) sp.saml.metadata.path = file:data-cache/generated/saml-sp-metadata.xml idp.saml.enabled = false #exported metadata from SAML IDP (path needs to be relative to ${STAGES_ROOT}) idp.saml.metadata.path = file:conf/secret/saml-idp-metadata.xml idp.saml.attribute.firstname = urn:oid:2.5.4.42 idp.saml.attribute.lastname = urn:oid:2.5.4.4 idp.saml.attribute.email = urn:oid:1.2.840.113549.1.9.1 idp.saml.fullname.template = %firstname% %lastname% idp.saml.autocreate = true user.default.username = default user.default.licenseType = AuthPsReader
After you configured the service provider and identity provider in config.xml, update the configuration via “stages update and restart the Stages service.
By default, existing users are not modified by the SAML authentication process when the SAML configuration was changed after the user had been created. However, you can set the forceLicensePoolReassignment attribute on an attribute-match to true if you want changes of the licensePoolIdent or defaultLicenseType attributes to be applied to existing users.
JavaScript control flow statements (e.g. “if”,”switch“) can be used to configure values for Stages attributes. All assertion attributes of the SAML response are accessible as variables and can be used in the JavaScript expression JavaScript expressions can be used with the following Stages attributes: * defaultRolesUsername * defaultLicenseType * licensePoolIdent General JavaScript expression notation:
<Stages_attribute>="=<JavaScript_expression>"
JavaScript notation of if-clauses:
if (condition1) 'returnValue1'; else if (condition2) 'returnValue2'; else if (condition3) 'returnValue3'; else 'returnValue4';
JavaScript notation of value conditions: SAML Attributes that are defined via identity_provider_attribute elements can be used in these scripts. E.g.
<identity-provider-attribute name="email" id="<EMailAddress>" />
Names of license types for license assignment
| License name | License type |
|---|---|
| Modeler | QM |
| Contributor | FloatingADev |
| Participant | FloatingDev |
| Project Manager | FloatingPM |
| Viewer | AuthPsReader |
Example configuration:
This example creates Stages users with the following conditions:
* The pattern matches the entry of the SAML attribute “id”.
* Depending on the users' email address (domain-part), SAML attribute name “email” is used to assign different values for defaultRolesUsername, defaultLicenseType and licensePoolIdent
<attribute-match id="[saml_attribute_id]" pattern="[matching_value]" defaultRolesUsername="= if (email.match(/.*@company1.com/)) 'User1'; else if (email.match(/.*@company2.com/)) 'User2'; else 'default'; " defaultLicenseType="= if (email.match(/.*@company1.com/)) 'QM'; else if (email.match(/.*@company2.com/)) 'PM'; else 'none'; " licensePoolIdent="= if (email.match(/.*@company2.com/)) 'company2'; else '';" autocreateUser="true" />
Please note that the values of multi value attributes are provided to the scripts as one value as a comma separated string.
The default binding type of the SAML Request is POST.
Some IDPs do not work with that type and rather need a “REDIRECT”. This can only be found out on the IDP.
This can be configured in the authentication method properties section via
<method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> <properties> [...] <property name="authnRequestBindingType" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" [...] </properties> [...] </method>
By default Stages send authentication requests signed and expects assertions in the response as well as the response itself to be signed. In case this is not supported by the IDP it can be disabled by setting the according property to false.
Please use with care as it degrades security.
<method type="SAML2" [...]> <properties> <!-- implicit default values --> <property name="authnRequestSigned" value="true" /> <property name="wantsAssertionsSigned" value="true" /> <property name="wantsResponsesSigned" value="true" /> </properties> </method>
Stages does now allow to configure multiple IDPs. Just add another authentication method of type SAML2 and ensure it has an unique name. E.g.
<authentication> [...] <method type="SAML2" name="saml-idp-1" enabled="${idp1.saml.enabled}"> [...] </method> <method type="SAML2" name="saml-idp-2" enabled="${idp2.saml.enabled}"> [...] </method> </authentication>
This will create a SSO button on the login page for each IDP.
Please provide a user understandable naming by defining a translation property for each login.sso.[name] propertyin each supported language:
conf/local.properties, conf/local_de.properties, …
login.sso.saml-idp-1 = Single Sign-On for company 1 login.sso.saml-idp-2 = Single Sign-On for company 2
Stages SAML has successfully been deployed with the following IdP servers:
Please let us know if you were able to make Stages SAML work with your server and it is not on this list yet.