Multiple SAML IdP's configured
Last updated
Last updated
If you have application that have different need regarding the SAML IdP you can with Fortified ID WEB create several logical IdPs.
In this scenario we will us Fortified ID Portal and Fortified ID Password Reset as SAML SP that will use different IdPs.
On Fortified ID WEB we ha two IdP2s created.
This use case assumes that you have good knowledge of the product in question.
Fortified ID WEB installed and configured
LDAP directory. Location are the users to authenticate. The example code is configured using an Active Directory. We are using mail attribute of the Active Directory user.
Fortified ID Portal installed and configured
Fortified ID Password Reset installed and configured
FakeSMTP. This is used when a user reset its own password. When authenticating to the self service we will use UserID (mail) and a mail delivered one-time password (otp). Download and install FakeSMTP on the same host as the use cases and start the smtp service on port 25. Note. If you have an "real" SMTP server then use that instead.
Note. All configuration and testing is done on the scenario server.
Here are some information about what is core of this use case.
We have one installation of Fortified ID WEB with two logical SAML IdPs configured. The key configuration parts, see config.json at the bottom of this use case, are
Line 59-88 Here we reference two different metadata_templates. One for each IdP. Make sure you verify the 2 files referenced for each IdP. See ZIP-file and the files fortifiedid_web_saml_idp_1_template.xml and fortifiedid_web_saml_idp_2_template.xml in fodler \..\FortifiedID\web\customer\config\resources_internal\saml\metadata_templates
Line 117-212 and line 213-308 IdP1 - From line 117-212 you have all authenticators for IdP1 IdP2 - From line 213-308 you have all authenticators for IdP2 Note. You do not need to have all the authenticators under one IdP2 but for me it more logical. Note. You can also extract the pipes module to separate files and reference to them using globals.
Line 312-475 and line 476-688 Pipes for IdP1 - From line 312-475 you have all pipes for IdP1 including the assertion pipe. Pipes for IdP2 - From line 476-688 you have all pipes for IdP2 including the assertion pipe. I have created two Pipes modules, one for each IdP. You can all the pipes in the same pipe module. Note. You can also extract the pipes module to separate files and reference to them using globals.
Download and install Fortified ID Web Fortified ID Portal, Fortified ID Password Reset
To install Integrity Web Integrity Portal and Password Reset, see documentation and installation.
Add files and folders from ZIP-file to Fortified ID Web, Fortified ID Portal and Fortified ID Password Reset
Download the USE_CASE.zip.
Replace the customer folders for your installations with the ones from the zip-file. Note. This use case was initially done on a Windows server, if you run Container/Docker or Linux you might have to changes something to work in your environments like file paths e.g..
Open the globals.json in both customer folders and update to match your environment.
Start services
Start Fortified ID WEB
Start Fortified ID Portal
Start Fortified ID Password Reset
Verify Fortified ID WEB is started
Verify Fortified ID Portal is started
Verify Fortified ID Password Reset is started
Open a browser
Browse to https://localhost:8445/portal
This is the address to Fortified ID Portal acting as a SAML SP
Type the username and password of a user in your Active Directory.
Note. Remember that we in config is using mail attribut as username. Verify that you user has a value in mail attribute.
You will now be logged in to Fortified ID Portal
Open a browser
Browse to https://localhost:8446/pwdreset
This time, click the I have forgotten my password link
You should now be redirect to Password Reset and then saml_idp2.
Add the one-time password. Note. I use the FAKESmtp application local in the Fortified ID WEB server.
You should now be logged into Password Reset
Other configuration and reference files will be found in the ZIP-file you downloaded.
{
"globals": "@include:globals.json",
"modules": [
{
"name": "CefEventModule",
"config": {}
},
{
"name": "HttpClient",
"config": {
"name": "default",
"idle_timeout_ms": 5000,
"connect_timeout_ms": 5000
}
},
{
"name": "LdapClient",
"enabled": true,
"instances": 1,
"config": {
"name": "${globals.ldap.ldap1.name}",
"connection": {
"host": "${globals.ldap.ldap1.connection.host}",
"port": "${globals.ldap.ldap1.connection.port}",
"bind_dn": "${globals.ldap.ldap1.connection.bind_dn}",
"bind_password": "${globals.ldap.ldap1.connection.bind_password}",
"use_ssl": "${globals.ldap.ldap1.connection.use_ssl}",
"ssl_trust_all": "${globals.ldap.ldap1.connection.ssl_trust_all}"
}
}
},
{
"name": "SmtpClient",
"enabled": true,
"config": {
"name": "${globals.smtp.smtp1.name}",
"host": "${globals.smtp.smtp1.host}",
"port": "${globals.smtp.smtp1.port}",
"user_name": "${globals.smtp.smtp1.user_name}",
"password": "${globals.smtp.smtp1.password}",
"auth_methods": "DIGEST-MD5, CRAM-SHA256, LOGIN"
}
},
{
"name": "SAML",
"config": {
"metadata_cache": "${globals.saml.generic.metadata_cache}",
"http_port": "${globals.http.port}",
"http_use_ssl": true,
"http_keystore_ref": {
"type": "${globals.keystore.https.ref.type}",
"path": "${globals.keystore.https.ref.path}",
"password": "${globals.keystore.https.ref.password}"
},
"http_keystore_type": "${globals.keystore.https.type}",
"http_key_alias": "${globals.keystore.https.http_key_alias}",
"http_key_password": "${globals.keystore.https.http_key_password}",
"enable_http": true,
"metadata_template": [
{
"id": "${globals.saml.idp1.metadata_id}",
"metadata_file_path": "${globals.saml.idp1.metadata_file_path}",
"sign_ref": [
{
"keystore": {
"alias": "${globals.keystore.saml.sign_ref_keystore_alias}",
"key_password": "${globals.keystore.saml.sign_ref_keystore_key_password}",
"password": "${globals.keystore.saml.sign_ref_keystore_password}",
"path": "${globals.keystore.saml.sign_ref_keystore_path}"
}
}
]
},
{
"id": "${globals.saml.idp2.metadata_id}",
"metadata_file_path": "${globals.saml.idp2.metadata_file_path}",
"sign_ref": [
{
"keystore": {
"alias": "${globals.keystore.saml.sign_ref_keystore_alias}",
"key_password": "${globals.keystore.saml.sign_ref_keystore_key_password}",
"password": "${globals.keystore.saml.sign_ref_keystore_password}",
"path": "${globals.keystore.saml.sign_ref_keystore_path}"
}
}
]
}
],
"metadata": [
{
"path": "${globals.file_paths.base_dir}/config/resources_internal/saml/sp_metadata_files/sp_portal.xml"
},
{
"path": "${globals.file_paths.base_dir}/config/resources_internal/saml/sp_metadata_files/sp_pwdreset.xml"
}
]
}
},
{
"name": "AuthN",
"enabled": true,
"config": {
"context_path": "/authn",
"webroot_dir": "web",
"http_port": "${globals.http.port}",
"http_use_ssl": true,
"http_keystore_ref": {
"type": "${globals.keystore.https.ref.type}",
"path": "${globals.keystore.https.ref.path}",
"password": "${globals.keystore.https.ref.password}"
},
"http_keystore_type": "${globals.keystore.https.type}",
"http_key_alias": "${globals.keystore.https.http_key_alias}",
"http_key_password": "${globals.keystore.https.http_key_password}",
"authenticators": [
{
"id": "idp_1",
"type": "SAMLIDP",
"config": {
"context_path": "/saml_idp1/authn/chain",
"base_path": "/saml_idp1/authn",
"expiry": "PT1S",
"force_re_auth": false,
"idp": "${globals.saml.idp1.idp_entityid}",
"chain": [
{
"id": "selector_root",
"required": true
}
],
"assertion_config": [
{
"target_sp": [
"FortifiedID_Portal"
],
"nameid_parameter": "mail",
"auth_context_parameter": "AuthnContextClassRef",
"additional_attribute_parameter": [
"givenName",
"sn",
"mail",
"roles",
"display_name",
"distinguishedName"
],
"pre_assertion_pipe": "Retrieve_data_for_SAML_response_for_Portal"
},
{
"target_sp": [
"FortifiedID_Password_Reset"
],
"nameid_parameter": "mail",
"auth_context_parameter": "AuthnContextClassRef",
"additional_attribute_parameter": [
"givenName",
"sn",
"mail",
"roles",
"display_name",
"distinguishedName"
],
"pre_assertion_pipe": "Retrieve_data_for_SAML_response_for_Password_Reset"
}
]
}
},
{
"id": "selector_root",
"type": "Selector",
"config": {
"base_path": "/saml_idp1/authn",
"webroot_dir": "web/authenticator/selector",
"auto_select": false,
"overlay_dirs": [
"${globals.file_paths.base_dir}/config/resources_external/overlays/idp1/1_selector_root",
"${globals.file_paths.base_dir}/config/resources_external/overlays/0_look_and_feel"
],
"options": [
{
"id": "1",
"target": "uid_pwd_ldap",
"label": "ldap_label",
"logo": "assets/svg/microsoft.svg"
}
]
}
},
{
"id": "uid_pwd_ldap",
"type": "UserNameAndPassword",
"config": {
"base_path": "/saml_idp1/authn",
"webroot_dir": "web/authenticator/username_password",
"cancel_location": "https://localhost:8446/pwdreset",
"overlay_dirs": [
"${globals.file_paths.base_dir}/config/resources_external/overlays/idp1/2_main_username_password",
"${globals.file_paths.base_dir}/config/resources_external/overlays/0_look_and_feel"
],
"pipe_id": "Validate_Username_Password",
"exports": [
{
"name": "used_auth",
"value": "username_password_ldap"
},
{
"name": "AuthnContextClassRef",
"value": "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
}
]
}
},
{
"id": "idp_2",
"type": "SAMLIDP",
"config": {
"context_path": "/saml_idp2/authn/chain",
"base_path": "/saml_idp2/authn",
"expiry": "PT1S",
"force_re_auth": false,
"idp": "${globals.saml.idp2.idp_entityid}",
"chain": [
{
"id": "password_reset",
"required": true
}
],
"assertion_config": [
{
"target_sp": [
"FortifiedID_PWD_Reset"
],
"nameid_parameter": "mail",
"auth_context_parameter": "AuthnContextClassRef",
"additional_attribute_parameter": [
"email",
"display_name",
"on_behalf_of_display_name",
"on_behalf_of_user_name",
"on_behalf_of_email",
"distinguishedName",
"pwd_last_set",
"pwd_last_set_allowed_days"
],
"pre_assertion_pipe": "Retrieve_data_for_SAML_response_for_Password_Reset"
}
]
}
},
{
"id": "password_reset",
"type": "Chain",
"config": {
"require_subject": false,
"_proceed_on_error": true,
"_failure_location": "http://www.sf.se",
"base_path": "/saml_idp2/authn",
"chain": [
{
"id": "username_validator",
"required": true
},
{
"id": "otp_validator",
"required": true
}
]
}
},
{
"id": "username_validator",
"type": "UserLookup",
"config": {
"base_path": "/saml_idp2/authn",
"webroot_dir": "web/authenticator/user_lookup",
"allowed_retries": 0,
"pipe_id": "Validate_Username_and_generate_a_OTP",
"overlay_dirs": [
"${globals.file_paths.base_dir}/config/resources_external/overlays/idp2/1_pwdreset_username_validation",
"${globals.file_paths.base_dir}/config/resources_external/overlays/0_look_and_feel"
],
"exports": [
{
"name": "used_auth",
"value": "username_lookup"
}
]
}
},
{
"id": "otp_validator",
"type": "OTPValidator",
"config": {
"base_path": "/saml_idp2/authn",
"webroot_dir": "web/authenticator/otp_validation",
"_allowed_otp_retry": 2,
"pipe_id": "Validate_the_OTP",
"overlay_dirs": [
"${globals.file_paths.base_dir}/config/resources_external/overlays/idp2/2_pwdreset_token_validation",
"${globals.file_paths.base_dir}/config/resources_external/overlays/0_look_and_feel"
],
"exports": [
{
"name": "AuthnContextClassRef",
"value": "urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorContract"
}
]
}
}
]
}
},
{
"name": "Pipes",
"_info": "This is Pipes for IdP 1",
"config": {
"pipes": [
{
"id": "Validate_Username_Password",
"config": {
"valves": [
{
"name": "DumpRequest",
"config": {
"label": "*** DumpRequest ***"
}
},
{
"name": "DumpExports",
"config": {
"label": "*** DumpExports ***"
}
},
{
"name": "LDAPSearch",
"enabled": true,
"config": {
"destination": "${globals.ldap.ldap1.name}",
"base_dn": "${globals.ldap.ldap1.connection.base_dn}",
"scope": "SUB",
"filter": "mail={{{request.identifier}}}",
"attributes": [
{
"name": "mail",
"multivalue": false
}
]
}
},
{
"name": "LDAPBind",
"enabled": true,
"config": {
"destination": "${globals.ldap.ldap1.name}",
"dn": "{{{item.id}}}",
"password": "{{{request.password}}}"
}
},
{
"name": "DumpState",
"config": {
"label": "*** DumpState ***"
}
}
]
}
},
{
"id": "Retrieve_data_for_SAML_response_for_Portal",
"config": {
"valves": [
{
"name": "DumpRequest",
"config": {
"label": "*** DumpRequest från DumpData Portal****"
}
},
{
"name": "DumpExports",
"config": {
"label": "*** DumpExports från DumpData Portal****"
}
},
{
"name": "ExportsPut",
"exec_if_expr": "exports.used_auth == ('username_password_ldap')",
"enabled": true,
"config": {
"name": "LDAP_search_filter",
"value": "mail={{{request.username}}}",
"replace": true
}
},
{
"name": "LDAPSearch",
"enabled": true,
"config": {
"destination": "${globals.ldap.ldap1.name}",
"base_dn": "${globals.ldap.ldap1.connection.base_dn}",
"scope": "SUB",
"filter": "{{{exports.LDAP_search_filter}}}",
"attributes": [
{
"name": "givenName",
"multivalue": false
},
{
"name": "sn",
"multivalue": false
},
{
"name": "sAMAccountName",
"multivalue": false
},
{
"name": "mail",
"multivalue": false
},
{
"name": "carLicense",
"multivalue": true
},
{
"name": "displayName",
"multivalue": false
},
{
"name": "distinguishedName",
"multivalue": false
}
]
}
},
{
"name": "ExportsPut",
"enabled": true,
"config": {
"name": "username",
"value": "{{{item.mail}}}",
"replace": true
}
},
{
"name": "ItemPropertyAdd",
"enabled": true,
"config": {
"name": "display_name",
"value": "{{{item.displayName}}}"
}
},
{
"name": "ItemPropertyRename",
"enabled": true,
"config": {
"old_name": "carLicense",
"new_name": "roles"
}
},
{
"name": "DumpExports",
"config": {
"label": "*** DumpExports****"
}
},
{
"name": "DumpState",
"config": {
"label": "*** DumpState ***"
}
}
]
}
}
]
}
},
{
"name": "Pipes",
"_info": "This is Pipes for IdP 2",
"config": {
"pipes": [
{
"id": "Validate_Username_and_generate_a_OTP",
"config": {
"valves": [
{
"name": "DumpRequest",
"config": {
"label": "*** DumpRequest ***"
}
},
{
"name": "DumpExports",
"config": {
"label": "*** DumpExports ***"
}
},
{
"name": "LDAPSearch",
"enabled": true,
"config": {
"destination": "${globals.ldap.ldap1.name}",
"base_dn": "${globals.ldap.ldap1.connection.base_dn}",
"scope": "SUB",
"filter": "mail={{{request.identifier}}}",
"attributes": [
{
"name": "mail",
"multivalue": false
}
]
}
},
{
"name": "GenerateOtp",
"enabled": true,
"config": {
"otp_length": 6,
"alpha_numeric": false,
"valid_time": 60,
"dest_parameter": "generated_otp",
"otp_parameter": "generated_otp_value"
}
},
{
"name": "ExportsPut",
"enabled": true,
"config": {
"name": "generated_otp",
"value": "{{{item.generated_otp}}}",
"replace": true
}
},
{
"name": "SmtpSender",
"enabled": true,
"config": {
"smtp_destination": "smtp01",
"username_parameter": "{{{request.identifier}}}",
"subject_parameter": "** Your verification code **",
"message_template": "${globals.file_paths.base_dir}/config/resources_internal/mail_template/mail_template.txt",
"mail_to_parameter": "{{{item.mail}}}",
"mail_from_parameter": "noreply@mycompany.com",
"_mail_cc_parameter": "admin@mycompany.com",
"remove_prefixes": [
"SMTP:",
"sip:"
]
}
},
{
"name": "DumpState",
"config": {
"label": "*** DumpState ***"
}
}
]
}
},
{
"id": "Validate_the_OTP",
"config": {
"valves": [
{
"name": "DumpRequest",
"config": {
"label": "*** DumpRequest ***"
}
},
{
"name": "DumpExports",
"config": {
"label": "*** DumpExports ***"
}
},
{
"name": "ValidateOtp",
"enabled": true,
"config": {
"username_parameter": "{{{exports.username}}}",
"otp_parameter": "{{{request.otp}}}",
"src_parameter": "{{{exports.generated_otp}}}"
}
}
]
}
},
{
"id": "Retrieve_data_for_SAML_response_for_Password_Reset",
"config": {
"valves": [
{
"name": "DumpRequest",
"config": {
"label": "*** DumpRequest från DumpData Portal****"
}
},
{
"name": "DumpExports",
"config": {
"label": "*** DumpExports från DumpData Portal****"
}
},
{
"name": "ExportsPut",
"exec_if_expr": "exports.used_auth == ('username_lookup')",
"enabled": true,
"config": {
"name": "LDAP_search_filter",
"value": "mail={{{request.username}}}",
"replace": true
}
},
{
"name": "LDAPSearch",
"enabled": true,
"config": {
"destination": "${globals.ldap.ldap1.name}",
"base_dn": "${globals.ldap.ldap1.connection.base_dn}",
"scope": "SUB",
"filter": "{{{exports.LDAP_search_filter}}}",
"attributes": [
{
"name": "sAMAccountName",
"multivalue": false
},
{
"name": "mail",
"multivalue": false
},
{
"name": "displayName",
"multivalue": false
},
{
"name": "pwdLastSet",
"multivalue": false
}
]
}
},
{
"name": "ExportsPut",
"enabled": true,
"config": {
"name": "username",
"value": "{{{item.mail}}}",
"replace": true
}
},
{
"name": "ItemPropertyRename",
"config": {
"new_name": "user_name",
"old_name": "sAMAccountName"
}
},
{
"name": "ItemPropertyRename",
"config": {
"new_name": "display_name",
"old_name": "displayName"
}
},
{
"name": "ItemPropertyRename",
"config": {
"new_name": "pwd_last_set",
"old_name": "pwdLastSet"
}
},
{
"name": "ItemPropertyAdd",
"config": {
"name": "pwd_last_set_allowed_days",
"value": "0"
}
},
{
"name": "DumpState",
"config": {
"label": "*** DumpState ***"
}
}
]
}
}
]
}
}
]
}
You should be redirected to the Fortified ID WEB acting as SAML IdP and see the following Note. The IdP used for Portal is saml_idp1
Click Username & Password (LDAP), you should now see If you login you will be authenticated through saml_idp1. If you click "I have forgotten my password" you will be redirected to Password Reset that will redirect to saml_idp2 for authentication.
You should see
After username verification you will be prompted with add a one-time password. Verify user mail client, I used FAKESmtp for an email with the one-time password.