Quick Start

Intro

This quick start guide will take you through all the steps necessary to get your IdP server installed, connected to the authentication portal backend and set up with a single service provider. This will enable you to then run your IdP server and make a test login to the configured SP, thus ensuring that you have a good grasp of how to configure the system before going on to add any other service providers, whether they are ones supported 'out of the box' by MIRACL Trust® SSO, or ones you wish to add from scratch.

You can choose to set up either Dropbox or AWS as a Service Provider. Dropbox is very simple to set up, although you will need a paid account in order to use the SAML SSO module. A free AWS account does include SAML.

To view the instructions for setting up other Service Providers please see the and the full list of Service Providers supported out of the box.

Please choose a tab for whichever Service Provider you wish to test:


Table of Contents:

1. Enable connection to authentication portal backend
2. IdP Server Installation
3. Add auth portal details to config
4. Generating certificates
5. Configure DropBox as a Service Provider


Enable connection to authentication portal backend

To begin using MIRACL Trust® SSO, you must first log into the MIRACL Trust® authentication portal at https://trust.miracl.cloud, click on the 'Apps' link in the dashboard and create a new SSO with SAML app. Note that, normally, the entered Redirect URL must be the publicly available url which will be serving your installation of the SSO IdP server, and it must use the /login endpoint. For this test tutorial, however, setting it as http://127.0.0.1:8000/login will enable local testing of your setup:

add_new_app

portal_download

Clicking on 'Show keys' will display the Client ID and Secret values which you will need to enter in the config.json file.

IdP Server Installation

DEB installation

Redis is a dependency, so first:

sudo apt-get update && sudo apt-get install redis-server

For ubuntu/debian you can install via the following commands when logged in as root:

wget -qO - http://repo.miracl.com/build-team-public.asc | apt-key add --

Create a new file:

/etc/apt/sources.list.d/miracl.list

Now add the following to miracl.list:

deb http://repo.miracl.com/apt/ubuntu all main (Note that, since it comes with i386 additional architecture, Ubuntu 14.04 should use deb [arch=amd64] http://repo.miracl.com/apt/ubuntu all main)

Save and close the file, then continue with the commands:
sudo apt-get update
sudo apt-get install miracl-srv-idp

RPM installation

First, the EPEL repositories need to be enabled, so:

sudo yum install epel-release

Redis is a dependency, so first:

sudo yum install redis

You can now install via the following:

Create a new repo file: /etc/yum.repos.d/miracl-rpm.repo

Then add the following:

[miracl]
name= Latest Release for RHEL/Centos 7Server
baseurl=http://repo.miracl.com/yum/redhat/7Server
gpgkey=http://repo.miracl.com/build-team-public.asc
enabled=1
gpgcheck=1

Save and close the file.

During initial install of any package from this repo, you will be asked to accept the key.

sudo yum update

Finally, install with:

sudo yum install miracl-srv-idp

Docker Installation

Please the Installation menu section for instructions on Docker installation.

Add auth portal details to config

Once you have installed the idp server via deb, rpm or Docker, configuring and running your project is a simple case of editing a single json config file and running the program.

If you installed using deb or rpm this config.json file will now be found in /etc/srv-idp/. If you are using a Docker install, it will be loaded remotely by consul or etcd.

You can open the json config file (e.g. sudo gedit /etc/srv-idp/config.json) and copy and paste the following json config into it before making the necessary adjustments, as will be explained (note that, for simplicity, this is a stripped down version of the full config file, hence you will see some empty entries for other SPs in the 'assertion', 'attribute' and 'response' subsections of the 'profile' section. The full config file is available to be copied from Configuration > Example config file page in this documentation):

{
  "remoteConfigProvider": "",
  "remoteConfigEndpoint": "",
  "remoteConfigPath": "",
  "remoteConfigSecretKeyring": "",
  "serverAddress": ":8000",
  "serverPublicAddress": "http://127.0.0.1:8000",
  "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>",
  "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>",
  "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>",
  "log": {
    "level": "DEBUG",
    "network": "",
    "address": ""
  },
  "stats": {
    "prefix": "srv-idp",
    "network": "udp",
    "address": ":8125",
    "flush_period": 100
  },
  "redis": {
    "network": "tcp",
    "address": ":6379",
    "database": 0,
    "password": "",
    "connect_timeout": 0,
    "read_timeout": 0,
    "write_timeout": 0,
    "pool_max_idle": 0,
    "pool_max_active": 0,
    "pool_idle_timeout": 0,
    "max_age": 3600
  },
  "zfa": {
    "client_id": "",
    "client_secret": "",
    "backend": "https://api.mpin.io"
  },
  "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": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\"><head><title>SSO REDIRECT TO: {{.URL}}</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><meta name=\"language\" content=\"en\" /><meta name=\"description\" content=\"Redirect the user to the Service Provider: {{.URL}}\" /></head><body onload=\"document.getElementById('SAMLResponseForm').submit()\"><form method=\"post\" action=\"{{.URL}}\" id=\"SAMLResponseForm\"><div><input type=\"hidden\" name=\"SAMLResponse\" id=\"SAMLResponse\" value=\"{{.SAMLResponse}}\" /><input type=\"hidden\" name=\"RelayState\" id=\"RelayState\" value=\"{{.RelayState}}\" /><input type=\"submit\" value=\"Continue\" /></div></form></body></html>",
    "cache_duration": 48,
    "max_sp_delay": 90
  },
  "profile": {
    "assertion": {
      "global": "<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"{{.ID}}\" IssueInstant=\"{{.TimeNow}}\" Version=\"2.0\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\"><Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">{{.MetadataEntityID}}</Issuer>{{.SignatureBlock}}<Subject>{{.NameID}}<SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData NotOnOrAfter=\"{{.TimeExpire}}\" Address=\"{{.RecipientIP}}\" Recipient=\"{{.Recipient}}\" {{if not (eq .AuthnRequestID \"\")}}InResponseTo=\"{{.AuthnRequestID}}\"{{end}}/></SubjectConfirmation></Subject><Conditions NotBefore=\"{{.TimeNow}}\" NotOnOrAfter=\"{{.TimeExpire}}\"><AudienceRestriction><Audience>{{.SPEntityID}}</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"{{.SessionCreateTime}}\" SessionIndex=\"{{.SessionIndex}}\" SessionNotOnOrAfter=\"{{.TimeExpire}}\"><SubjectLocality Address=\"{{.RemoteAddress}}\" /><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef></AuthnContext></AuthnStatement>{{.AttributeStatement}}</Assertion>",
      "zabbix": "<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"{{.ID}}\" IssueInstant=\"{{.TimeNow}}\" Version=\"2.0\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\"><Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">{{.MetadataEntityID}}</Issuer>{{.SignatureBlock}}<Subject>{{.NameID}}<SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData NotOnOrAfter=\"{{.TimeExpire}}\" Address=\"10.10.24.66\" Recipient=\"{{.Recipient}}\" {{if not (eq .AuthnRequestID \"\")}}InResponseTo=\"{{.AuthnRequestID}}\"{{end}}/></SubjectConfirmation></Subject><Conditions NotBefore=\"{{.TimeNow}}\" NotOnOrAfter=\"{{.TimeExpire}}\"><AudienceRestriction><Audience>{{.SPEntityID}}</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"{{.SessionCreateTime}}\" SessionIndex=\"{{.SessionIndex}}\"><SubjectLocality Address=\"{{.RemoteAddress}}\" /><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef></AuthnContext></AuthnStatement>{{.AttributeStatement}}</Assertion>"
    },
    "nameid": {
      "global": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\">{{.ServiceProviderUserID}}</NameID>",
      "office365": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\">{{.SessionUserName | urlquery}}</NameID>",
      "email": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\">{{.SessionUserEmail}}</NameID>",
      "github": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\">{{.SessionUserName}}</NameID>"
    },
    "attribute": {
      "global": "<AttributeStatement>{{ if not (eq .ServiceProviderUserID \"\")}}<Attribute FriendlyName=\"uid\" Name=\"urn:oid:0.9.2342.19200300.100.1.1\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.ServiceProviderUserID}}</AttributeValue></Attribute>{{end}}{{ if not (eq .SessionUserEmail \"\")}}<Attribute FriendlyName=\"mail\" Name=\"urn:oid:0.9.2342.19200300.100.1.3\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"eduPersonPrincipalName\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute>{{end}}</AttributeStatement>",
      "empty": "",
      "box": "<AttributeStatement><Attribute Name=\"primary_email\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
      "office365": "<AttributeStatement><Attribute Name=\"IDPEmail\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
      "aws": "<AttributeStatement><Attribute Name=\"https://aws.amazon.com/SAML/Attributes/Role\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><AttributeValue>arn:aws:iam::YOURAWSACCOUNTNUMBER:role/YOURSSOROLE,arn:aws:iam::YOURAWSACCOUNTNUMBER:saml-provider/YOURPROVIDER</AttributeValue></Attribute><Attribute Name=\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
      "samanage": "<AttributeStatement><Attribute NameFormat=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\" Name=\"IDPEmail\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
      "datadog": "<AttributeStatement>{{ if not (eq .SessionUserEmail \"\")}}<Attribute FriendlyName=\"eduPersonPrincipalName\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"sn\" Name=\"urn:oid:2.5.4.4\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"givenName\" Name=\"urn:oid:2.5.4.42\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute>{{end}}</AttributeStatement>",
      "tsystems_otc_admin": "<AttributeStatement><Attribute FriendlyName=\"mail\" Name=\"urn:oid:0.9.2342.19200300.100.1.3\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"groups\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue>restricted</AttributeValue></Attribute></AttributeStatement>"
    },
    "response": {
      "global": "<Response xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\" Version=\"2.0\" Destination=\"{{.Destination}}\" {{if not (eq .AuthnRequestID \"\")}}InResponseTo=\"{{.AuthnRequestID}}\"{{end}} IssueInstant=\"{{.TimeNow}}\" ID=\"{{.ID}}\">{{if not (eq .MetadataEntityID \"\")}}<Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">{{.MetadataEntityID}}</Issuer>{{end}}{{.SignatureBlock}}<Status xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\"><StatusCode xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\" Value=\"{{.StatusCodeTL}}\">{{if not (eq .StatusCodeSL \"\")}}<StatusCode xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\" Value=\"{{.StatusCodeSL}}\" />{{end}}</StatusCode>{{if not (eq .StatusMessage \"\")}}<StatusMessage xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\">{{.StatusMessage}}</StatusMessage>{{end}}</Status>{{.Assertion}}</Response>"
    },
    "signature": {
      "global": "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod><SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\"></SignatureMethod><Reference URI=\"{{.ReferenceURI}}\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></Transform><Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></DigestMethod><DigestValue></DigestValue></Reference></SignedInfo><SignatureValue></SignatureValue><KeyInfo><X509Data><X509Certificate>{{.Certificate}}</X509Certificate></X509Data></KeyInfo></Signature>",
      "sha1": "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></SignatureMethod><Reference URI=\"{{.ReferenceURI}}\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></Transform><Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod><DigestValue></DigestValue></Reference></SignedInfo><SignatureValue></SignatureValue><KeyInfo><X509Data><X509Certificate>{{.Certificate}}</X509Certificate></X509Data></KeyInfo></Signature>"
    }
  },
  "ldap": {
    "server": {
      "global": {
        "method": "plain",
        "address": "xx.xx.xx.xxx:389",
        "user": "cn=admin,dc=ldap,dc=example,dc=com",
        "password": "strong password"
      }
    },
    "query": {
      "dept1": {
        "server": "global",
        "search": [
            {"dn": "ou=dept1,dc=ldap,dc=example,dc=com", "filter": "(mail={{.UserID}})"}
        ]
      }
    }
  },
  "sp": {
    "dropbox": {
      "description": "Dropbox is a cloud storage provider",
      "issuer": "Dropbox",
      "relay_state": "",
      "login_url": "https://www.dropbox.com/login",
      "logout_url": "https://www.dropbox.com/logout",
      "slo_url": "",
      "metadata": "<!-- dropbox doesn't provide a link to download its sp metadata, so this is hand-crafted --><?xml version=\"1.0\" encoding=\"UTF-8\"?> <md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"www.dropbox.com\"> <md:SPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"> <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat> <md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://www.dropbox.com/saml_login\"/> </md:SPSSODescriptor> </md:EntityDescriptor>",
      "sign_response": true,
      "sign_assertion": false,
      "encrypt_assertion": false,
      "user_id_transform": [
        {}
      ],
      "authorize": [
        [
          {}
        ]
      ],
      "profile": {
        "assertion": "global",
        "nameid": "email",
        "attribute": "global",
        "response": "global",
        "signature": "global"
      }
    }
  }
}

To connect your SSO IdP server to the authentication backend you should make the following edits to the above config file:

  1. Near the top of the file, for deb/rpm installation edit your server details:

    "serverAddress": ":8000",
    "serverPublicAddress": "http://127.0.0.1:8000",

    If you wish to run a simple local test, you can leave these details as they are.

    serverAddress can set the internal port, while serverPublicAddress should contain the publicly-available IP address of your SSO IdP server so will match what you entered in the redirect url entry in the backend authentication portal (minus the /login endpoint)

  2. Add the client id and secret obtained from the authentication portal to the 'mfa' section of your config file:

    "zfa": {
        "client_id": "",
        "client_secret": "",
        "backend": "https://api.mpin.io"
    },

Generating certificates

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 script 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):


"idp": {
    "private_key": "",
    "public_certificate": "",

You can now save your config file to the correct location (/etc/srv-idp/config.json for a debian/rpm installation, or to your consul/etcd location for Docker)

Setting up MIRACL Trust® SSO as an Identity Provider within Dropbox

  1. Run your IdP server by opening a terminal and running sudo service srv-idp start. This will enable you to download your IdP metadata, as required in step 8.

  2. Log in to your Dropbox for Business account.

  3. Click on Admin Console.
    The 'Dropbox Admin Console' is launched in a new browser tab

  4. Click on Settings:

  5. Click on Single sign-on

    dbox_settings

  6. Select Required

  7. Set the Sign in URL as the https://<myssoip>/sso endpoint on your IdP server. If you are running a local test it will be http://127.0.0.1:8000/sso

  8. Upload your X.509 certificate. To do this you can just upload the public certificate generated earlier - (idp.crt) in the command given above. This file is in newline format and begins with -----BEGIN CERTIFICATE----- and ends with -----END CERTIFICATE-----. Dropbox also receives certificates in .pem format.

Run your idp-server

You can login and test your IdP and Dropbox Service Provider setup with the following steps:

  1. In your browser visit the https://<myssoip>/services endpoint (http://127.0.0.1:8000/services if running a local test). The /services endpoint prompts a login and then displays all the services which the current user is authorized to access (this can be controlled by LDAP / AD / email domain filters as will be explained in the configuration section of this documentation)

  2. From the login QR code which is displayed follow the link to download and install the MIRACL Trust® app before using the app to scan the QR code. When using the app to login to your SSO service for the first time you will be asked to register an email address so as to confirm your identity and register you as a user. This email address must match an already registered user in your dropbox account, as email is the attribute which is passed from the IdP to the SP.

  3. Once logged in click on the 'IdP-initiated login' link. You will then be re-directed and logged in to Dropbox!

Table of Contents:

1. Enable connection to authentication portal backend
2. IdP Server Installation
3. Add auth portal details to config
4. Generating certificates
5. Configure AWS as a Service Provider


Enable connection to authentication portal backend

To begin using MIRACL Trust® SSO, you must first log into the MIRACL Trust® authentication portal at https://trust.miracl.cloud, click on the 'Apps' link in the dashboard and create a new SSO with SAML app. Note that, normally, the entered Redirect URL must be the publicly available url which will be serving your installation of the SSO IdP server, and it must use the /login endpoint. For this test tutorial, however, setting it as http://127.0.0.1:8000/login will enable local testing of your setup:

add_new_app

Once this has been done, you can download the installation file for the server, as a deb, rpm or Docker file:

portal_download

Clicking on 'Show keys' will display the Client ID and Secret values which you will need to enter in the config.json file.

IdP Server Installation

DEB installation

Redis is a dependency, so first:

sudo apt-get update && sudo apt-get install redis-server

For ubuntu/debian you can install via the following commands when logged in as root:

wget -qO - http://repo.miracl.com/build-team-public.asc | apt-key add --

Create a new file:

/etc/apt/sources.list.d/miracl.list

Now add the following to miracl.list:

deb http://repo.miracl.com/apt/ubuntu all main (Note that, since it comes with i386 additional architecture, Ubuntu 14.04 should use deb [arch=amd64] http://repo.miracl.com/apt/ubuntu all main)

Save and close the file, then continue with the commands:
sudo apt-get update
sudo apt-get install miracl-srv-idp

RPM installation

First, the EPEL repositories need to be enabled, so:

sudo yum install epel-release

Redis is a dependency, so first:

sudo yum install redis

You can now install via the following:

Create a new repo file: /etc/yum.repos.d/miracl-rpm.repo

Then add the following:

[miracl]
name= Latest Release for RHEL/Centos 7Server
baseurl=http://repo.miracl.com/yum/redhat/7Server
gpgkey=http://repo.miracl.com/build-team-public.asc
enabled=1
gpgcheck=1

Save and close the file.

During initial install of any package from this repo, you will be asked to accept the key.

sudo yum update

Finally, install with:

sudo yum install miracl-srv-idp

Docker installation

Please the Installation menu section for instructions on Docker installation.

Add auth portal details to config

Once you have installed the idp server via deb, rpm or Docker, configuring and running your project is a simple case of editing a single json config file and running the program.

If you installed using deb or rpm this config.json file will now be found in /etc/srv-idp/. If you are using a Docker install, it will be loaded remotely by consul or etcd.

You can open the json config file (e.g. sudo gedit /etc/srv-idp/config.json) and copy and paste the following json config into it before making the necessary adjustments, as will be explained (note that, for simplicity, this is a stripped down version of the full config file, hence you will see some empty entries for other SPs in the 'assertion', 'attribute' and 'response' subsections of the 'profile' section. The full config file is available to be copied from Configuration > Example config file page in this documentation):

{
    "remoteConfigProvider": "",
    "remoteConfigEndpoint": "",
    "remoteConfigPath": "",
    "serverAddress": ":8000",
    "serverPublicAddress": "http://127.0.0.1:8000",
    "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>",
    "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>",
    "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>",
    "log": {
        "level": "DEBUG",
        "network": "",
        "address": ""
    },
    "stats": {
        "prefix": "srv-idp",
        "network": "udp",
        "address": ":8125",
        "flush_period": 100
    },
    "redis": {
        "network": "tcp",
        "address": ":6379",
        "database": 0,
        "password": "",
        "connect_timeout": 0,
        "read_timeout": 0,
        "write_timeout": 0,
        "pool_max_idle": 0,
        "pool_max_active": 0,
        "pool_idle_timeout": 0,
        "max_age": 3600
    },
    "zfa": {
        "client_id": "",
        "client_secret": "",
        "backend": "https://api.mpin.io"
    },
    "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": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\"><head><title>SSO REDIRECT TO: {{.URL}}</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><meta name=\"language\" content=\"en\" /><meta name=\"description\" content=\"Redirect the user to the Service Provider: {{.URL}}\" /></head><body onload=\"document.getElementById('SAMLResponseForm').submit()\"><form method=\"post\" action=\"{{.URL}}\" id=\"SAMLResponseForm\"><div><input type=\"hidden\" name=\"SAMLResponse\" id=\"SAMLResponse\" value=\"{{.SAMLResponse}}\" /><input type=\"hidden\" name=\"RelayState\" id=\"RelayState\" value=\"{{.RelayState}}\" /><input type=\"submit\" value=\"Continue\" /></div></form></body></html>",
        "cache_duration": 48,
        "max_sp_delay": 90
    },
    "profile": {
        "assertion": {
            "global": "<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"{{.ID}}\" IssueInstant=\"{{.TimeNow}}\" Version=\"2.0\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\"><Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">{{.MetadataEntityID}}</Issuer>{{.SignatureBlock}}<Subject>{{.NameID}}<SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData NotOnOrAfter=\"{{.TimeExpire}}\" Address=\"{{.RecipientIP}}\" Recipient=\"{{.Recipient}}\" {{if not (eq .AuthnRequestID \"\")}}InResponseTo=\"{{.AuthnRequestID}}\"{{end}}/></SubjectConfirmation></Subject><Conditions NotBefore=\"{{.TimeNow}}\" NotOnOrAfter=\"{{.TimeExpire}}\"><AudienceRestriction><Audience>{{.SPEntityID}}</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"{{.SessionCreateTime}}\" SessionIndex=\"{{.SessionIndex}}\" SessionNotOnOrAfter=\"{{.TimeExpire}}\"><SubjectLocality Address=\"{{.RemoteAddress}}\" /><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef></AuthnContext></AuthnStatement>{{.AttributeStatement}}</Assertion>",
            "zabbix": "<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"{{.ID}}\" IssueInstant=\"{{.TimeNow}}\" Version=\"2.0\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\"><Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">{{.MetadataEntityID}}</Issuer>{{.SignatureBlock}}<Subject>{{.NameID}}<SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData NotOnOrAfter=\"{{.TimeExpire}}\" Address=\"10.10.24.66\" Recipient=\"{{.Recipient}}\" {{if not (eq .AuthnRequestID \"\")}}InResponseTo=\"{{.AuthnRequestID}}\"{{end}}/></SubjectConfirmation></Subject><Conditions NotBefore=\"{{.TimeNow}}\" NotOnOrAfter=\"{{.TimeExpire}}\"><AudienceRestriction><Audience>{{.SPEntityID}}</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"{{.SessionCreateTime}}\" SessionIndex=\"{{.SessionIndex}}\"><SubjectLocality Address=\"{{.RemoteAddress}}\" /><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef></AuthnContext></AuthnStatement>{{.AttributeStatement}}</Assertion>"
        },
        "nameid": {
            "global": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\">{{.ServiceProviderUserID}}</NameID>",
            "office365": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\">{{.SessionUserName | urlquery}}</NameID>",
            "email": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\">{{.SessionUserEmail}}</NameID>",
            "github": "<NameID NameQualifier=\"{{.MetadataEntityID}}\" SPNameQualifier=\"{{.SPEntityID}}\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\">{{.SessionUserName}}</NameID>"
        },
        "attribute": {
            "global": "<AttributeStatement>{{ if not (eq .ServiceProviderUserID \"\")}}<Attribute FriendlyName=\"uid\" Name=\"urn:oid:0.9.2342.19200300.100.1.1\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.ServiceProviderUserID}}</AttributeValue></Attribute>{{end}}{{ if not (eq .SessionUserEmail \"\")}}<Attribute FriendlyName=\"mail\" Name=\"urn:oid:0.9.2342.19200300.100.1.3\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"eduPersonPrincipalName\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute>{{end}}</AttributeStatement>",
            "empty": "",
            "box": "<AttributeStatement><Attribute Name=\"primary_email\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
            "office365": "<AttributeStatement><Attribute Name=\"IDPEmail\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
            "aws": "<AttributeStatement><Attribute Name=\"https://aws.amazon.com/SAML/Attributes/Role\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><AttributeValue>arn:aws:iam::YOURAWSACCOUNTNUMBER:role/YOURSSOROLE,arn:aws:iam::YOURAWSACCOUNTNUMBER:saml-provider/YOURPROVIDER</AttributeValue></Attribute><Attribute Name=\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
            "samanage": "<AttributeStatement><Attribute NameFormat=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\" Name=\"IDPEmail\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>",
            "datadog": "<AttributeStatement>{{ if not (eq .SessionUserEmail \"\")}}<Attribute FriendlyName=\"eduPersonPrincipalName\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"sn\" Name=\"urn:oid:2.5.4.4\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"givenName\" Name=\"urn:oid:2.5.4.42\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue xmlns:XMLSchema-instance=\"http://www.w3.org/2001/XMLSchema-instance\" XMLSchema-instance:type=\"xs:string\">{{.SessionUserEmail}}</AttributeValue></Attribute>{{end}}</AttributeStatement>",
            "tsystems_otc_admin": "<AttributeStatement><Attribute FriendlyName=\"mail\" Name=\"urn:oid:0.9.2342.19200300.100.1.3\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute><Attribute FriendlyName=\"groups\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\"><AttributeValue>restricted</AttributeValue></Attribute></AttributeStatement>"
        },
        "response": {
            "global": "<Response xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\" Version=\"2.0\" Destination=\"{{.Destination}}\" {{if not (eq .AuthnRequestID \"\")}}InResponseTo=\"{{.AuthnRequestID}}\"{{end}} IssueInstant=\"{{.TimeNow}}\" ID=\"{{.ID}}\">{{if not (eq .MetadataEntityID \"\")}}<Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">{{.MetadataEntityID}}</Issuer>{{end}}{{.SignatureBlock}}<Status xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\"><StatusCode xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\" Value=\"{{.StatusCodeTL}}\">{{if not (eq .StatusCodeSL \"\")}}<StatusCode xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\" Value=\"{{.StatusCodeSL}}\" />{{end}}</StatusCode>{{if not (eq .StatusMessage \"\")}}<StatusMessage xmlns=\"urn:oasis:names:tc:SAML:2.0:protocol\">{{.StatusMessage}}</StatusMessage>{{end}}</Status>{{.Assertion}}</Response>"
        },
        "signature": {
            "global": "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod><SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\"></SignatureMethod><Reference URI=\"{{.ReferenceURI}}\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></Transform><Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></DigestMethod><DigestValue></DigestValue></Reference></SignedInfo><SignatureValue></SignatureValue><KeyInfo><X509Data><X509Certificate>{{.Certificate}}</X509Certificate></X509Data></KeyInfo></Signature>",
            "sha1": "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></SignatureMethod><Reference URI=\"{{.ReferenceURI}}\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></Transform><Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod><DigestValue></DigestValue></Reference></SignedInfo><SignatureValue></SignatureValue><KeyInfo><X509Data><X509Certificate>{{.Certificate}}</X509Certificate></X509Data></KeyInfo></Signature>"
        }
    },
    "ldap": {
        "server": {
            "global": {
                "method": "none",
                "address": "127.0.0.1:389",
                "user": "cn=Directory Manager",
                "password": "secret"
            }
        },
        "query": {
            "global": {
                "server": "global",
                "search": [
                    {
                        "dn": "ou=people,dc=example,dc=com",
                        "filter": "(uid={{.UserID}})"
                    },
                    {
                        "dn": "ou=people,dc=example,dc=com",
                        "filter": "({{index .DN 0}})"
                    }
                ]
            }
        }
    },
    "sp": {
        "aws": {
            "description": "Amazon Web Services (AWS) Cloud Computing",
            "issuer": "urn:amazon:webservices",
            "relay_state": "",
            "login_url": "http://<myssoip>/login/aws",
            "logout_url": "https://console.aws.amazon.com/iam/logout!doLogout",
            "slo_url": "",
            "metadata": "<?xml version=\"1.0\"?> <!-- https://signin.aws.amazon.com/static/saml-metadata.xml --> <EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" entityID=\"urn:amazon:webservices\" validUntil=\"2017-11-16T00:00:00Z\"> <SPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\" WantAssertionsSigned=\"true\"> <KeyDescriptor use=\"signing\"> <ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"> <ds:X509Data> <ds:X509Certificate>MIIDbTCCAlWgAwIBAgIEY0CCkzANBgkqhkiG9w0BAQsFADBnMR8wHQYDVQQDExZ1 cm46YW1hem9uOndlYnNlcnZpY2VzMSIwIAYDVQQKExlBbWF6b24gV2ViIFNlcnZp Y2VzLCBJbmMuMRMwEQYDVQQIEwpXYXNoaW5ndG9uMQswCQYDVQQGEwJVUzAeFw0x NjExMTYwMDAwMDBaFw0xNzExMTYwMDAwMDBaMGcxHzAdBgNVBAMTFnVybjphbWF6 b246d2Vic2VydmljZXMxIjAgBgNVBAoTGUFtYXpvbiBXZWIgU2VydmljZXMsIElu Yy4xEzARBgNVBAgTCldhc2hpbmd0b24xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyOeWZrYlX2CMbGjsXgaObzQ+cnFx2sVNZA8D nFM/MGw9aFDyDoh5aRq5OBZIbHiS28DEA/VslxPX/pyom4lowau+bigi7EQc/VcI yEGJSycph6Hwt/0W/z9E9KoFmHQm2KpTKi8CLKzQySAs1XLYGB2TIrPZ8XhVAUOg qXNu6knUbukj2Q0+h86Gyeu3Yent99+GZexAg7aOxZ2M4fiRPD+opRB05+lIN8iB hVkMgV09Z7gJV0zbc/FQeMXBR4hYaO4BHDErHgf2NN5Ph+s8Ph/HRMQmNwPmRECb 9g5xOVWiwkkDsMo/+NuK+dRBHVUNIdmVN6IiW+ZeKyMLDtFgqwIDAQABoyEwHzAd BgNVHQ4EFgQUKY+dhiL8DbT+baYJaZbmhwTYSlowDQYJKoZIhvcNAQELBQADggEB AMUM5d4A7+ja0BYebmkrYUTNPWj6eu2qZkSph6VnVN5W1kKHtGE+ufxbDuSH3au8 3hZXlNxGhSWxQZjTtYNCnrrr/xCHVFuLodGZZIWDVucMuUXtLDI8W95zZd2IM/Tj qyNWKNIHWYia9xD9s8NIxdvb3HUsZxdyS8jxBAXtkCMGZDR/GzCSzBHQeWcByfMd YNWnxQk/oZWxvRX/kLWQ2NKEaxS3nLMqaTEPo592ppC5NB8JCv0o+oVsGmSC1kcG 1PxW6QEoSNnpS/GMw9irzce4d6S2Vf2xsmWPZ6QJIEOglrShfh/cpNtfCiWvY8J4 rNQTrVUxO1NyKGL0xv0dFa8=</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </KeyDescriptor> <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> <AssertionConsumerService index=\"1\" isDefault=\"true\" Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"https://signin.aws.amazon.com/saml\"/> <AttributeConsumingService index=\"1\"> <ServiceName xml:lang=\"en\">AWS Management Console Single Sign-On</ServiceName> <RequestedAttribute isRequired=\"true\" Name=\"https://aws.amazon.com/SAML/Attributes/Role\" FriendlyName=\"RoleEntitlement\"/> <RequestedAttribute isRequired=\"true\" Name=\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\" FriendlyName=\"RoleSessionName\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.1\" FriendlyName=\"eduPersonAffiliation\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.2\" FriendlyName=\"eduPersonNickname\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.3\" FriendlyName=\"eduPersonOrgDN\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.4\" FriendlyName=\"eduPersonOrgUnitDN\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.5\" FriendlyName=\"eduPersonPrimaryAffiliation\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.6\" FriendlyName=\"eduPersonPrincipalName\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.7\" FriendlyName=\"eduPersonEntitlement\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.8\" FriendlyName=\"eduPersonPrimaryOrgUnitDN\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.9\" FriendlyName=\"eduPersonScopedAffiliation\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.10\" FriendlyName=\"eduPersonTargetedID\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.11\" FriendlyName=\"eduPersonAssurance\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.2.1.2\" FriendlyName=\"eduOrgHomePageURI\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.2.1.3\" FriendlyName=\"eduOrgIdentityAuthNPolicyURI\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.2.1.4\" FriendlyName=\"eduOrgLegalName\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.2.1.5\" FriendlyName=\"eduOrgSuperiorURI\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.2.1.6\" FriendlyName=\"eduOrgWhitePagesURI\"/> <RequestedAttribute isRequired=\"false\" Name=\"urn:oid:2.5.4.3\" FriendlyName=\"cn\"/> </AttributeConsumingService> </SPSSODescriptor> <Organization> <OrganizationName xml:lang=\"en\">Amazon Web Services, Inc.</OrganizationName> <OrganizationDisplayName xml:lang=\"en\">AWS</OrganizationDisplayName> <OrganizationURL xml:lang=\"en\">https://aws.amazon.com</OrganizationURL> </Organization> </EntityDescriptor>",
            "sign_response": true,
            "sign_assertion": true,
            "encrypt_assertion": false,
            "user_id_transform": [
                {}
            ],
            "authorize": [
                [
                    {
                        "email": "^[^@]+@yourcompany.com$"
                    },
                    {
                        "ldap": "query1"
                    }
                ]
            ],
            "profile": {
                "assertion": "global",
                "nameid": "global",
                "attribute": "aws",
                "response": "global",
                "signature": "global"
            }
        }
    }
}

To connect your SSO IdP server to the authentication backend you should make the following edits to the above config file:

  1. Near the top of the file, for deb/rpm installation edit your server details:

    "serverAddress": ":8000",
    "serverPublicAddress": "http://127.0.0.1:8000",

    If you wish to run a simple local test, you can leave these details as they are.

    serverAddress can set the internal port, while serverPublicAddress should contain the publicly-available IP address of your SSO IdP server so will match what you entered in the redirect url entry in the backend authentication portal (minus the /login endpoint)

  2. Add the client id and secret obtained from the authentication portal to the 'mfa' section of your config file:

    "zfa": {
        "client_id": "",
        "client_secret": "",
        "backend": "https://api.mpin.io"
    },

These are the necessary config steps to make your SSO IdP server ready to connect to the backend authentication portal when you start the server.

Generating certificates

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 script 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):


"idp": {
    "private_key": "",
    "public_certificate": "",

You can now save your config file to the correct location (/etc/srv-idp/config.json for a debian/rpm installation, or to your consul/etcd location for Docker)

Configure AWS as a Service Provider

  1. Run your IdP server by opening a terminal and running sudo service srv-idp start. This will enable you to download your IdP metadata, as required in step 7.

  2. Log in to Amazon AWS Console and click on IAM under 'Security, Identity and Compliance'.

  3. Click on Identity providers in the menu on the left.

  4. Click on the Create Provider button:

  5. Choose SAML from the 'Provider Type' dropdown: configure provider

  6. Enter a Provider Name - e.g. 'MyCompany'.

  7. Upload your SAML metadata document – this is an XML file available from the /metadata endpoint on your IdP server. So if you are running a local test, it will be http://127.0.0.1:8000/metadata (be sure to save this as a .xml file) Note that, for a production setup, if you manually download your IdP metadata file, the validUntil date at the top of the file will need to be edited to an appropriate date (it defaults to 48hrs from the current date)

  8. Click on Next Step.
    The 'Verify Provider Information' page is displayed.

  9. Click on Create.
    A message is displayed: "To use this provider, you must create an IAM role using this provider in the role's trust policy. Do this now."

  10. Click on Do this now.

  11. Click on Create New Role.

  12. Enter a Role Name - e.g. 'SSOTest'.

  13. Select the Role for Identity Provider Access radio button.

  14. Click on 'Grant Web Single Sign-On (WebSSO) access to SAML providers'.

  15. On the next page, ensure that the provider created in step 5 above is selected in the 'SAML Provider' drop-down menu.

  16. Click on Next Step followed by Next Step.

  17. Choose an appropriate permissions policy template.

  18. Click on Next Step followed by Create Role.

Configuring your AWS Service Provider profile with MIRACL Trust® SSO (IDP-initiated login)

In the SSO config file, edit the AWS profile using the newly declared Identity Provider and Role:

  1. Find the AWS entry in the profile > attribute section:

  2. Replace both instances of YOURAWSACCOUNTNUMBER with your actual AWS account number, and also YOURSSOROLE and YOURSSOROLE with the values set in the AWS Console as detailed above:
    
    <AttributeStatement><Attribute Name=\"https://aws.amazon.com/SAML/Attributes/Role\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><AttributeValue>arn:aws:iam::YOURAWSACCOUNTNUMBER:role/YOURSSOROLE,arn:aws:iam::YOURAWSACCOUNTNUMBER:saml-provider/YOURPROVIDER</AttributeValue></Attribute><Attribute Name=\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><AttributeValue>{{.SessionUserEmail}}</AttributeValue></Attribute></AttributeStatement>
    
  3. Find the 'aws' entry in the sp section:

  4. Note that the AWS login_url is IdP-initiated (i.e. initiated on your IdP server as opposed to on an AWS-served url) and, in order to work, must make use of the /login endpoint. To complete the url the name of the service is appended to the /login endpoint. Note that the name must match the heading of the SP's subsection in the "sp" config section (i.e. 'aws'). The below login_url will work if you are testing locally: aws_sp

    Note also that the logout_url is the standard SP logout url which AWS makes available for SAML IdPs to use, and that the metadata is the standard metadata which AWS makes available for IdPs to use in order to connect with them. It has already been entered for you and can be used 'as is'.

    The attribute value must be set as aws, in order to invoke the correct settings described above.

    AWS also requires that SAML responses and assertions are signed.

  5. Save and close the file.

  6. Then sudo service srv-idp restart to restart the server with the new config changes.

Now, you can visit https://<myssoip>/login/aws and a QR code prompting SSO login will appear.

From the login QR code which is displayed follow the link to download and install the MIRACL Trust® app before using the app to scan the QR code. When using the app to login to your SSO service for the first time you will be asked to register an email address so as to confirm your identity and register you as a user.

Top