Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
261:integration:saml [2026/04/27 09:56] – [Enable SAML for Stages] Weinlein, Thomas261:integration:saml [2026/04/28 09:04] (current) – [Configure signing] Weinlein, Thomas
Line 1: Line 1:
-====== Configure SAML Authentication (work in progress) ======+====== Configure SAML Authentication ======
  
 SAML stands for Security Assertion Markup Language. It is a current standard for authenticating users in a distributed system. SAML stands for Security Assertion Markup Language. It is a current standard for authenticating users in a distributed system.
Line 59: Line 59:
 </code> </code>
  
-===== Configure the SAML Service Provider (SP) =====+//Please make sure to call **''update.sh|bat''** after enabling or disabling SAML and restart Stages.//
  
-The SAML Service Provider describes your local Stages server. 
  
-To configure, add or enable the following section in ''conf/config.xml.'' +===== Generate the SAML SP metadata =====
-<code> +
-<authentication +
-     ...+
  
-        <service-provider +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
-                        providerId="yourStagesURL" +
-                        keyAlias="samlkeyalias">+
  
-        </service-provider>+<code xml> 
 +    <authentication> 
 +        [...] 
 +        <method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> 
 +            <properties> 
 +                [...] 
 +                <property name="serviceProviderMetadataPath" value="${sp.saml.metadata.path}"/> 
 +                [...] 
 +            </properties> 
 +        </method> 
 +    </authentication> 
 +</code>
  
-... +''conf/config.properties''
- +
-</authentication>+
  
 +<code properties>
 +sp.saml.metadata.path=file:data-cache/generated/sp-metadata.xml
 </code> </code>
  
-The ''providerId'' can be an arbitrary name, but it should be globally unique, so it is a good practice to use your Stages URL.+Restart Stages and access the Login page. The sp-metadata.xml should now be generated.
  
-The ''keyAlias'' identifies the key to be used for signing the SAML request, so it needs to match either the key you generated above or your server certificate alias. If it is not setthe SAML request will not be signed. +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.
-=====   =====+
  
-===== Generate the SAML SP metadata ===== +//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 configuring the SAML SP and logged on as root, you can download the SAML SP metadata directly by navigating to the URL ''[[http://<yourstages|https://<yourstages]]>/stages/rest/saml/metadata'' +
- +
-For SP metadata generated correctly the whole authentication section must be present in config.xml : [[https://doc.stagesasaservice.com/712/integration/saml#configure-the-saml-identity-provider-idp]] +
- +
-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. After the SAML IdP has been configured with the SP metadata, users will be able to authenticate successfully with Stages through the SAML IdP.+
  
-=====   =====+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.
  
  
Line 102: Line 100:
 The most reliable way to configure the SAML Identity Provider (IdP) is to ask the access management team for the IdP metadata. The most reliable way to configure the SAML Identity Provider (IdP) is to ask the access management team for the IdP metadata.
  
-From this metadata, you will be able to derive the parameters+Store this metadata in ''conf/secret/idp-metadata.xml'' and add the following configuration to  
 +''conf/config.xml'' 
 +<code xml> 
 +<method type="SAML2" name="saml-idp" enabled="${idp.saml.enabled}"> 
 +    <properties> 
 +        [...] 
 +        <property name="identityProviderMetadataPath" value="${idp.saml.metadata.path}"/> 
 +        [...] 
 +    </properties> 
 +    [...] 
 +</method> 
 +</code>
  
-  * EntityIdfromMetadata+''conf/config.properties'' 
 +<code properties> 
 +idp.saml.metadata.path = file:conf/secret/idp-metadata.xml 
 +</code>
  
-  * SingleSignOnServiceLocationFromMetadata (should be HTTPS, please see [[:general:saml-note-samesite]])+A complete SAML configuration should then look like that: 
 +<code xml> 
 +<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> 
 +</code>
  
-  * DisplayName (alternativeFirstName, LastName)+''conf/config.properties'' 
 +<code 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
  
-  * EMailAddress+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
  
-for the following configuration:+user.default.username = default 
 +user.default.licenseType = AuthPsReader 
 +</code>
  
-<code -> +After you configured the service provider and identity provider in ''config.xml'', update the configuration via "stages update'' and restart the Stages service.''
-<authentication +
-     enabled="true" +
-     keystoreFile="/opt/stages/conf/saml-keystore.jks" +
-     keystorePass="changeit">+
  
-    <service-provider +===== Changing the license pool and license type for existing users =====
-         providerId="yourStagesURL" +
-         keyAlias="samlkeyalias">+
  
-    </service-provider>+''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.  ''
  
-    <identity-provider +===== Configuring Stages attributes in default-matcher section with JavaScript =====
-        providerId="EntityIDfromMetadata" +
-        providerUrl="SingleSignOnServiceLocationFromMetadata" +
-        nameIdPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" +
-        sendBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" +
-        userFullnameTemplate="%firstname% %lastname%">+
  
-        <!-- userFullnameTemplate is used to build the user's full name from multiple IDP attributes +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:**  
-             as defined below as <identity-provider-attribute name=.../>. +
-             In the example above the firstname and lastname attributes are concatenated speparated by a space. -->+
  
-        <!-- hardcoded magic value that specifies the NameID from the SAML reply --> +<code javascript> <Stages_attribute>="=<JavaScript_expression>  
-        <identity-provider-attribute name="username" id="http://schemas.stages.methodpark.com/saml/v2/identity/claims/subject" />+</code 
  
-        <!-- either "fullname" or "firstname" and "lastname" need to be defined --> +**JavaScript notation of if-clauses:**   
-        <!--<identity-provider-attribute name="fullname" id="DisplayName" />--+<code javascriptif (condition1) 'returnValue1'; else if (condition2) 'returnValue2'; else if (condition3) 'returnValue3'; else 'returnValue4';   
-        <identity-provider-attribute name="firstname" id="FirstName" /> +</code 
-        <identity-provider-attribute name="lastname" id="LastName" />+
  
-        <identity-provider-attribute name="email" id="EMailAddress" />+**JavaScript notation of value conditions: 
 +**  SAML Attributes that are defined via identity_provider_attribute elements can be used in these scripts. E.g.   
 +<code xml>  
 +<identity-provider-attribute name="email" id="<EMailAddress>" />   
 +</code>  
  
-        <!-- This matches if the SAML assertion contains a SAML attribute "Organization" with value "External" --> +**Names of license types for license assignment** 
-        <!-- +^License name^License type^  
-        <identity-provider-attribute-match +|Modeler|QM|  
-            id="Organization" +|Contributor|FloatingADev|  
-            pattern="External" +|Participant|FloatingDev|  
-            defaultRolesUsername="default_supplier" +|Project Manager|FloatingPM|  
-            defaultLicenseType="DEV" +|Viewer|AuthPsReader|  
-            licensePoolIdent="" +
-            autocreateUser="true" +
-                    /> +
-        -->+
  
-        <!-- This is the default matcher, identified by id and pattern attributes set to "*" --> +**Example configuration:**  
-        <identity-provider-attribute-match +''\\ '' ''\\ ''This example creates Stages users with the following conditions:     
-            id="*+The pattern matches the entry of the SAML attribute "id"   
-            pattern="*" +* Depending on the users' email address (domain-part)SAML attribute name "emailis used to assign different values for defaultRolesUsername, defaultLicenseType and licensePoolIdent 
-            defaultRolesUsername="default" +
-            defaultLicenseType="QM" +
-            licensePoolIdent="" +
-            autocreateUser="true" +
-        /> +
- +
-        <!-- +
-            Specifying at least one signing certificate automatically enables +
-            signature verification of the authentication response. +
-            The key data can also be copied from the IdP metadata. +
-            If no signing certificate is specified, no signature +
-            validation will be performed. +
-        --> +
-        <certificate use="signing">${saml.idp.signatureCertificate} +
- +
-       <!-- MIIDCTCC...Qwgf5bXby+ug==   --> +
-        </certificate> +
- +
-        <!-+
-             In case the IDP only provides encrypted assertions specify +
-             encryption certifacte. The key data can also be copied from the +
-             IdP metadata. If no encryption certificate is specifiedno encrypted +
-             assertion can be accepted. +
-        --> +
-        <certificate use="encryption">${saml.idp.encryptionCertificate} +
-                <!-- MIIDCTCC...Qwgf5bXby+ug==  --> +
-       </certificate> +
-    </identity-provider>+
  
-    <!-+<code xml>  
-        This identity provider statement with the "STAGES+<attribute-match       
-        magic id enables local Stages logins to be available +    id="[saml_attribute_id]
-        for selection between multiple identity providers +    pattern="[matching_value]"       
-        (NOT IMPLEMENTED YET). +    defaultRolesUsername="= if (email.match(/.*@company1.com/)) 'User1';          
-        If the authentication with the IdP fails and the "STAGES+                       else if (email.match(/.*@company2.com/)) 'User2';  
-        provider is enabled, the Stages login screen is shown, so +                       else 'default';         "  
-        the user may log in with a local user idIf it is not +    defaultLicenseType="= if (email.match(/.*@company1.com/)) 'QM'; 
-        configured, the server answers with a 403 (Forbidden+                 else if (email.match(/.*@company2.com/)) 'PM';          
-        status code+                 else 'none';         "       
-    --> +    licensePoolIdent="= if (email.match(/.*@company2.com/)) 'company2';  
-    <identity-provider providerId="STAGES"/> +             else '';" 
-</authentication>+    autocreateUser="true
 +/>
 </code> </code>
  
-After you configured the service provider and identity provider in ''config.xml'', update the configuration via "stages update'' and restart the Stages service.''+Please note that the values of multi value attributes are provided to the scripts as one value as a comma separated string.
  
-===== Changing the license pool and license type for existing users ===== 
  
-''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 ''identity-provider-attribute-match'' to ''true'' if you want changes of the ''licensePoolIdent''  or ''defaultLicenseType''  attributes to be applied to existing users.  ''+===== Configure the SAML Request Type =====
  
-===== Configuring Stages attributes in default-matcher section with JavaScript =====+The default binding type of the SAML Request is ''POST''.
  
-''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:**  <code> <Stages_attribute>="=<JavaScript_expression>"  </code>  **JavaScript notation of if-clauses:**  <code> if (condition1) 'returnValue1'; else if (condition2) 'returnValue2'; else if (condition3) 'returnValue3'; else 'returnValue4';  </code>  **JavaScript notation of value conditions:**  SAML Attributes that are defined via identity_provider_attribute elements can be used in these scripts. E.g.  <code> <identity-provider-attribute name="emailid="<EMailAddress>" />  </code>  <code> Attribute contains value:  </code>  <code> <saml_attribute_id>.match(/.*value/        // <= 7.9.10.0, <= 7.10.1.0 <saml_attribute_name>.match(/.*value/      //> 7.9.10.0,> 7.10.1.0  </code>  Attribute equals value:  <code> <saml_attribute_id>=="value                 // <= 7.9.10.0, <= 7.10.1.0 <saml_attribute_name>=="value               //> 7.9.10.0,> 7.10.1.0  </code>  **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  <code> <identity-provider-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 '';+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
-     autocreateUser="true" +
- +
-/>+
  
 +<code xml>
 +<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>
 </code> </code>
  
-Please note that the values of multi value attributes are provided to the scripts as one value as a comma separated string.+===== Configure signature validation =====
  
 +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**.
  
-===== Configure the SAML Request Type =====+//Please use with care as it degrades security.// 
 +<code xml> 
 +<method type="SAML2" [...]> 
 +    <properties> <!-- implicit default values --> 
 +        <property name="authnRequestSigned" value="true" /> 
 +        <property name="wantsAssertionsSigned" value="true" /> 
 +        <property name="wantsResponsesSigned" value="true" /> 
 +    </properties> 
 +</method> 
 +</code> 
 +===== Configure multiple SAML IDPs =====
  
-The default binding type of the SAML Request is ''redirect''.+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.
  
-Some IDPs do not work with that type and rather need a POST RequestThis can only be found out on the IDP+<code xml> 
- +<authentication> 
-This can be configured in the ''identity-provider''  section via +    [...] 
- +    <method type="SAML2" name="saml-idp-1" enabled="${idp1.saml.enabled}"> 
-<code+        [...] 
-sendBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"+    </method
 +    <method type="SAML2" name="saml-idp-2" enabled="${idp2.saml.enabled}"
 +        [...] 
 +    </method> 
 +</authentication> 
 +</code>
  
 +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'', ...
 +<code properties>
 +login.sso.saml-idp-1 = Single Sign-On for company 1
 +login.sso.saml-idp-2 = Single Sign-On for company 2
 </code> </code>
  
Line 245: Line 288:
  
   * Azure AD IdP   * Azure AD IdP
-  * Okta +  * Keycloak
-  * JumpCloud +
-  * Cisco Central Web Authentication (CWA) +
-  * Oracle Access Manager (OAM)+
   * Shibboleth IdP   * Shibboleth IdP
-  * Active Directory Federation Services (ADFS) 
  
 Please let us know if you were able to make Stages SAML work with your server and it is not on this list yet. Please let us know if you were able to make Stages SAML work with your server and it is not on this list yet.