The Config File Explained


Table of Contents:


Intro

What follows is an explanation of how to make the necessary configurations to enable communication between your IdP server, the authentication portal backend and your chosen Service Providers.

Note that, in terms of connecting to a list of Service Providers supported 'out of the box', a lot of configuration 'donkey work' has been done for you in the Example config file available in this menu section. This includes pre-configured settings for the SAML assertions and attributes that are needed for a list of individual SPs including Google, AWS, Dropbox, Github, Salesforce and SAP Hana.

You can make use of this example config file and, for any Service Providers you do not wish to connect to, simply remove their subsection from the "sp" section.

How to make use of the example config will be explained below and then further in each SP's section in the Service Provider setup menu.

Note that all entries for parameters in the config file must be in single line format and all " characters must be escaped. This applies particularly to the entries for private_key, public_certificate and metadata fields.

For the purposes of copying and pasting into your config file:

A private .key and a public .crt file can be output in the terminal in single line format with a command such as:

  openssl req -x509 -nodes -newkey rsa:2048 -keyout idp.key -out idp.crt -days 1000 -subj /C=UK/ST=London/L=London/O=Development/CN=example.com \
  && echo -e "\nCONFIG PRIVATE KEY:\n" \
  && echo $(cat idp.key | tr -d '\n' | sed -E 's/-----[^-]+-----//g') \
  && echo -e "\nCONFIG PUBLIC CERTIFICATE:\n" \
  && echo $(cat idp.crt | tr -d '\n' | sed -E 's/-----[^-]+-----//g') \
  && echo ""

An xml metadata file which has been downloaded from a Service Provider can be output in the terminal in single line format - and with " characters escaped - with a command such as echo -e "\n"$(cat metadata.xml | tr -d '\n' | sed -E 's/"/\\"/g')"\n"

Note that it is strongly advisable to ensure that the base url "/", "/status", "/splist" and "/metadata" endpoints are not publicly exposed.
It is also important that your network settings allow connection to the https://api.mpin.io/.well-known/openid-configuration endpoint, as this is where the program attempts to get the platform configuration. It also needs outgoing access to https://api.mpin.authorize/, https://api.mpin.io/oidc/certs and https://api.mpin.io/oidc/token

General Server Configuration

Basic server details are set at the very top of the file:


"remoteConfigProvider": "consul",
"remoteConfigEndpoint": "http://12.34.567.89:8600",
"remoteConfigPath": "/config/srv-idp",
"remoteConfigSecretKeyring": "",
"serverAddress": ":8000",
"serverPublicAddress": "http://xx.xx.xxx.xx:8000",

If you are serving your config.json file remotely with Consul or etcd, you can add the details to the remoteConfig fields as above. Note that remoteConfigPath is the path where the config.json file will be stored, while remoteConfigSecretKeyring is the path to the openpgp secret keyring used to decrypt the remote configuration data (e.g. "/etc/srv-idp/configkey.gpg"); if empty a non secure connection will be used instead.

If you enter values for the remoteConfig fields then the server will look to your remote Consul or Etcd configuration, using the local config.json for default values.

You can use serverAddress to set the port the SSO service runs on, and enter your public url in serverPublicAddress.

Configuration of error handling pages

The program is set up to serve authentication errors (404s, LDAP errors, SAML errors etc.) in json format. To display the errors, in order of preference it will look for:

  1. An errorPageURL with a pre-configured web page in e.g. php
  2. If no entry is given for the url, a simple html template can be specified in the errorPageTemplate field, as shown below
  3. If neither of these are used, it will default to serve the errors in json format

"errorPageURL": "",
"errorPageTemplate": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><title>SSO ERROR</title></head><body><h1>SSO ERROR</h1><h2>{{.Data}}</h2><div><a href=\"{{.URL}}/services\" title=\"SSO Login\">SSO LOGIN</a> <a href=\"{{.URL}}/logout\" title=\"Terminate the main SSO session\">SSO LOGOUT</a></div><div><table><tr><th>FIELD</th><th>VALUE</th></tr><tr><td>Program</td><td>{{.Program}}</td></tr><tr><td>Version</td><td>{{.Version}}</td></tr><tr><td>Release</td><td>{{.Release}}</td></tr><tr><td>IdP URL</td><td>{{.URL}}</td></tr><tr><td>DateTime</td><td>{{.DateTime}}</td></tr><tr><td>Timestamp</td><td>{{.Timestamp}}</td></tr><tr><td>Status</td><td>{{.Status}}</td></tr><tr><td>Code</td><td>{{.Code}}</td></tr><tr><td>Message</td><td>{{.Message}}</td></tr><tr><td>Data</td><td>{{.Data}}</td></tr></table></div></body></html>",

Note that, for an errorPageURL, the JSON error message is compressed with FLATE, encoded in base64 and added as a query parameter "e". Please see the menu section Example error page for a simple php page which could be used to decompress and handle the errors.

The above error page template example shows the variables that are available. Note that the Data field contains the error message.

Configuration of the logout page

It is possible to configure a logout page which gives a list of services the user is logged into for the current session. The logout page will be served at /logout endpoint of your server. Visiting this will delete the cookie associated with the session. The user can then click on any of these services to log out of that particular service (the logout links are configured in the individual SP config sections, as will be explained below).

The way in which the logout page is handled is similar to the error handling as described above. In order of preference, the program will look for:

  1. A logoutPageURL with a pre-configured web page in e.g. php
  2. If no entry is given for the url, a simple html template can be specified in the logoutPageTemplate field, as shown below
  3. If neither of these are used, it will default to serving the logout urls in json format

"logoutPageURL": "",
"logoutPageTemplate": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><title>SSO LOGOUT</title></head><body><h1>SSO LOGOUT</h1><h2>The IDP Session has been successfully deleted</h2><div><a href=\"{{.URL}}/services\" title=\"SSO Login\">SSO LOGIN</a></div><h3>Logout links of visited Service Providers:</h3><ul>{{ range $name, $logout := .SPList }}<li><a href=\"{{ $logout }}\" title=\"Logout from {{ $name }}\" target=\"_blank\">{{ $name }}</a></li>{{ end }}</ul></body></html>",

Note that, for a logoutPageURL, a JSON struct containing a map of logout links for each Service Provider will be compressed with FLATE, encoded in base64 and added as a query parameter "x". Please see the menu section Example logout page for a simple php page which could be used to decompress and display the logged-in services for the current session. This provides links to the logout url that is configured in the individual SP config sections, as will be explained below.

Configuration of the services page

It is also possible to make use of the /services endpoint to present a 'landing page' list of services that the user is authorized to access. Accessing this endpoint will present the user with a QR code to login, followed by a 'landing page' which presents the SPs that user is authorized to access by LDAP/AD config as below.

The way in which the services page is handled is similar to the error and logout pages as described above. In order of preference, the program will look for:

  1. A servicesPageURL with a pre-configured web page in e.g. php
  2. If no entry is given for the url, a simple html template can be specified in the servicesPageTemplate field, as shown below
  3. If neither of these are used, it will default to serving the logout urls in json format

"servicesPageURL": "",
"servicesPageTemplate": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><title>SSO Authorized Service Providers</title></head><body><h1>SSO Authorized Service Providers</h1><div><a href=\"{{.URL}}/logout\" title=\"Terminate the main SSO session\">SSO LOGOUT</a></div><ul>{{ range $sp := .SPList }}<li><strong>{{ $sp.Name }}</strong><br /><em>{{ $sp.Description }}</em><ul><li><a href=\"{{ $sp.IDPLogin }}\" title=\"IdP-Login: {{ $sp.Description }}\" target=\"_blank\">IdP-initiated login</a></li><li><a href=\"{{ $sp.Login }}\" title=\"Login: {{ $sp.Description }}\" target=\"_blank\">Login Page</a></li><li><a href=\"{{ $sp.Logout }}\" title=\"Logout: {{ $sp.Description }}\" target=\"_blank\">Logout</a></li></ul></li>{{ end }}</ul></body></html>",

Please see the menu section Example services page for a simple php page which could be used to display the available services.

Stats for system performance

The program uses StatsD to collect usage metrics which can then be used with a StatsD-compatible client such as Graphite to visually render key system performance information such as session starts, logins, communicating with the authentication server, spikes in 404 statuses etc.

An example config would be:


"prefix": "srv-idp",
"network": "udp",
"address": ":8125",
"flush_period": 100

Note that prefix defines the prefix that is given to each bucket of stats. Address can be in the format of 'url:port' or just 'port'.

The above example would be suitable for a Graphite installation, as Graphite (https://github.com/etsy/statsd/blob/master/docs/graphite.md) listens on port 8125 by default. A useful Docker image for Graphite can be found at https://github.com/hopsoft/docker-graphite-statsd

REDIS for session data storage

The system uses REDIS to collect data for logged in sessions. The default config can be seen in the example config.json file, and this will work as is. Redis can be used locally or remotely.

ZFA config

In the zfa section of the config file you must enter the details of your SSO app, which you will have already created as per the Quick Start menu section:


"zfa": {
    "client_id": "pam*********qq",
    "client_secret": "hyEp*****************************zyasmDlYOI",
    "backend": "https://api.mpin.io"    
},

The key thing here is that the client_id and client_secret must match exactly what is entered for your SSO app in the MFA portal. Backend is always https://api.mpin.io

IdP Config

The idp section of the config file must contain the details for your private key and public certificate, the metadata associated with your IdP server, and the SAML response form which is used to send the responses back to Service Providers which identify you as the IdP:


  "idp": {
    "private_key": "",
    "public_certificate": "",
    "metadata": "<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" validUntil=\"{{.ValidUntil}}\" cacheDuration=\"{{.CacheDuration}}\" entityID=\"{{.EntityID}}\"><IDPSSODescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"><KeyDescriptor use=\"signing\"><KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{{.SigningCertificate}}</X509Certificate></X509Data></KeyInfo></KeyDescriptor><KeyDescriptor use=\"encryption\"><KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><X509Data><X509Certificate>{{.EncryptionCertificate}}</X509Certificate></X509Data></KeyInfo><EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes128-cbc\"></EncryptionMethod><EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes192-cbc\"></EncryptionMethod><EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"></EncryptionMethod><EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"></EncryptionMethod></KeyDescriptor><NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat><SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"{{.SsoRedirectLocation}}\"></SingleSignOnService><SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"{{.SsoPostLocation}}\"></SingleSignOnService></IDPSSODescriptor></EntityDescriptor>",
    "response_form": "<html><body onload=\"document.getElementById('SAMLResponseForm').submit()\"><form method=\"post\" action=\"{{.URL}}\" id=\"SAMLResponseForm\"><input type=\"hidden\" name=\"SAMLResponse\" id=\"SAMLResponse\" value=\"{{.SAMLResponse}}\" /><input type=\"hidden\" name=\"RelayState\" id=\"RelayState\" value=\"{{.RelayState}}\" /><input type=\"submit\" value=\"Continue\" /></form></body></html>",
    "cache_duration": 48,
    "max_sp_delay": 90
  },

Your config.json file must also contain your private key and public certificate. While you may have your own chosen method, these can be generated by openssl with a command such as:


openssl req -x509 -nodes -newkey rsa:2048 -keyout idp.key -out idp.crt -days 1000 -subj /C=UK/ST=London/L=London/O=Development/CN=example.com \
&& echo -e "\nCONFIG PRIVATE KEY:\n" \
&& echo $(cat idp.key | tr -d '\n' | sed -E 's/-----[^-]+-----//g') \
&& echo -e "\nCONFIG PUBLIC CERTIFICATE:\n" \
&& echo $(cat idp.crt | tr -d '\n' | sed -E 's/-----[^-]+-----//g') \
&& echo ""

This will generate a key and certificate within your current directory (pwd) and display them in the terminal in a format ready to be pasted straight into the config file (they will appear in the correct order with the private key appearing first).

You can use the metadata as found in the example config file and it will programmatically pick up the correct values. Likewise, for response_form you can use the values given in the example config file.

cache_duration is the maximum length of time in hours a consumer should cache the metadata

max_sp_delay is the maximum allowed time difference in seconds between the messages exchanged by the IDP and the SP

Profile config

This contains the config for the SAML information which you, the IdP, send to the SPs. The format which is accepted by Service Providers may differ depending on the SP. Hence there are some different configs available for the different SPs.

For the different Service Providers in the example config file, these profile configs have been set up so that they can be used 'as is'. It may be necessary to, e.g. add your AWS account number to the AWS entry in 'Attribute'. These can then be invoked when setting up an individual Service Provider in the SP section, as will be explained below. You will see that the profile section is broken down into four sub-sections:

profile_section

assertion contains the details of the SAML assertions which identify the IdP to the SP. Some SPs require this in a particular format.

nameid gives optional configurations for the way in which some SPs require the nameid of the subject to be sent.

attribute contains the attributes for the individual user which are sent to the SP. Some SPs ask for particular info to be provided here, rather than in their online admin console. For example the attribute statement for AWS must contain the associated account number, role and provider name (this is further expanded on in the AWS entry in the Service Provider setup menu section). If the attribute section for a Service Provider is blank, this means that the attributes can be added in the Service Provider's admin interface. Some SPs require this in a particular format.

response this is a template response for sending response information back to the SP

signature confirms the origin of the SAML assertions and that the IdP is valid

LDAP section

Please note that in the MFA platform all identities are converted to lowercase. Hence, if you assign an email containing uppercase characters to a Windows user in Active Directory the user will be required to authenticate with the lowercase equivalent. For example John.Smith@example.com will need to authenticate as john.smith@example.com

Here you can enter your ldap server details:

"ldap": {
  "server": {
    "global": {
      "method": "plain",
      "address": "52.xx.xx.xxx:389",
      "user": "cn=admin,dc=ldap,dc=example,dc=com",
      "password": "strong_password"
    }
  },
  "query": {
    "query1": {
      "server": "global",
      "search": [
        {
        "dn": "ou=dept1,dc=ldap,dc=example,dc=com",
        "filter": "(mail={{.UserID}})"
        }
      ]
    }
  }
},

Within the server subsection it is possible to add more than one LDAP server and then have one or more queries for each server, within the query subsection. As an example you could add a query for 'query2' which also queries the 'global' server:

  "query": {
    "query1": {
      "server": "global",
      "search": [
        {
        "dn": "ou=dept1,dc=ldap,dc=example,dc=com",
        "filter": "(mail={{.UserID}})"
        }
      ]
    },
    "query2": {
      "server": "global",
      "search": [
        {
        "dn": "ou=dept2,dc=ldap,dc=example,dc=com",
        "filter": "(mail={{.UserID}})"
        }
      ]
    }
  }

The "filter" in the above example programatically picks up the current UserID value from the IdP (which is the user's email address) and checks it with the 'mail' attribute on the LDAP server. More detailed guidance on LDAP usage, inclduing exctraction of custom attributes, can be found in the LDAP section in the left-hand menu.

How LDAP can then be invoked will be illustrated in the SP section below.

SP section

This is where the setup is made for the individual Service Providers. The main things to specify are:

  1. The login url and logout url. If the Service Provider caters for SP-initiated login, this will be obtained in the process of setting the SP-related config in the SP's online admin console (screenshots and more details are given for each SP in the Service Provider Setup menu section of this documentation). If the SP only allows for IdP-initiated login, then you will need to configure a login url in the format http://{myssoip}/login/[sp-name] (note that the root url here is that of your SSO server, /login is a configured server endpoint, and [sp-name] must match the top-level name the service is given in its subsection in the SP config file - "salesforce" in this case)

  2. The metadata which, if not generic for all IdPs, is downloaded from the SP's admin console and can then be pasted here. Note that this must be converted to a single line and the " characters need to be escaped with "\" to meet the json structure requirements. This can be achieved by running echo -e "\n"$(cat metadata.xml | tr -d '\n' | sed -E 's/"/\\"/g')"\n" on the downloaded metadata.xml file. The contents will then be output in the terminal in a format that can be pasted into the "metadata" field in the SP subsection.

An example SP config is Salesforce:


"salesforce": {
      "description": "Salesforce Customer Relationship Management (CRM)",
      "issuer": "https://saml.salesforce.com",
      "relay_state": "/",
      "login_url": "https://example--samlidp.cs61.my.salesforce.com",
      "logout_url": "https://example--samlidp.lightning.force.com/secur/logout.jsp",
      "slo_url": "",
      "metadata": "<-- insert your downloaded salesforce metadata here -->",
      "sign_response": true,
      "sign_assertion": true,
      "encrypt_assertion": true,
      "user_id_transform": [
        {}
      ],
      "authorize": [
        [
          {"ldap": "query1"}
        ]
      ],
      "profile": {
        "assertion": "global",
        "nameid": "global",
        "attribute": "global",
        "response": "global",
        "signature": "global"
      }
    },

Note the sign_response, sign_assertion and encrypt_assertion parameters. Some SPs will require that these are set to True in order to establish communication with the IdP.

In the authorize sub-section it is possible to invoke an LDAP query from earlier in the config file and/or to set a regex list of email addresses/domains. The above example shows a call to the dummy 'query1' LDAP query.

The following shows an OR list of regex email domains (note that each expression is within its own set of square brackets):

"authorize": [
                [{"email": "^[^@]+@test.com$"}],
                [{"email": "^[^@]+@example.com$"}],
                [{"email": "^[^@]+@mycompany.co.uk$"}]
            ],

The following shows an AND query being used to allow only authorized users from a particular email domain AND who are also in a particular LDAP group (note that both expressions are within the one set of square brackets):

"authorize":[
        [{"email":"^[^@]+@example.com$"},{"ldap":"dept1"}]
  ],

Some SPs require that the user id is sent in a particular format. For example, Bamboo will not accept a full email address - only the user name from the first part of the email. This can be dealt with by user_id_transform:


     "user_id_transform": [
        {
          "search": "^([^@]+)@[^@]+$",
          "replace": "$1"
        }
      ],

The above example would convert 'john.smith@example.com' to just 'john.smith'.

Finally note that, in the profile subsection, you must invoke the relevant assertion, nameid, attribute, response and signature profiles from the previous Profile section explained above. An SP will use global unless there is a profile named after them.

Top