Applies to: Pro, Plus, & Enterprise Plans
This article details an example of implementing Single Sign-On (SSO) from a development perspective, using both Absorb's Single Sign-on and RESTful API features. For the purposes of this article we'll assume a basic understanding of the SSO process along with some background in development. A higher level explanation of IdP initiated SSO can be found here. More information on our RESTful API can be found here & here.
Once a user is authenticated in your system, the Identity Provider (IdP), the user will look to navigate to your Absorb Training portal, the Service Provider (SP). Most likely this will be done through a link that passes them to Absorb. To do this, your system should first confirm the user exists in your Absorb portal. If the user does not exist, it should be created then logged in. It’s possible to automate this process using the REST API. Below I'll go over a simple implementation of this that will check if the authenticating user exists and if not, it will be created using the API.
C# sample code from this article can be downloaded at the very bottom of the page.
Verifying the User
Before we get into the code you should have an API key provided to you through support or your CSM. This will be needed to correctly authenticate. Along with that you will need the credentials of an admin account with the appropriate permissions to view and create users. This account should be able to manage all users so it can correctly find any user attempting to login. Lastly this example will make use of a package called RestSharp (http://restsharp.org/) to build the rest client and make requests.
This method is designed to take in a user's username and return true based on if the account exists or if it doesn't, it will return true if a user was successfully created during the process. If none exists and the account was not created successfully it will return false and login will not proceed. It’s expected that this method will be called before initiating SSO.
We'll start by generating a token using the hard-coded values for the Rest Admin and my supplied API key. The most common error with this is related to the credentials being wrong. You should be able to login with that account to ensure the username and password are correct. We have initialized the rest client with the other class variables which should take in the base URL of your portal.
Generating the token can be done in the following way,
The request is essentially "POST https://company.myabsorb.com/api/Rest/v1/authenticate" with the authentication model attached to the body. If the credentials are all correct this should return the trimmed token.
With the token stored we can now search for the user attempting to sign in.
The main addition here involves deserializing the response into a usermodel (https://myabsorb.com/api/rest/v1/Help/ResourceModel?modelName=UserModel). In this case we only need
- First Name
- Last Name
If the response returns one user then we’re set to proceed with the login. (If your setup doesn't use the username as the unique identifier, i.e. ExternalID, then you may need to include a check if duplicate users are found). If no user is found, the we must create one. The code to create a user is below,
To start the user model is initialized with a default department. We have hard coded a department to make things simple but this can be automated however you see fit. We're also hard coding a password for simplicity but in practice, a random one should be generated for each new user. Since they’re signing in through SSO the password won’t impact them but is still required by the LMS.
If the user is created successfully this method will return true and pass that to VerifyUser which in turn passes that to our Initiate SSO method and proceeds with the login.
The next steps involve building a SAML Response and posting that to the target URL. To do this, we make use of a third-party package called ComponentSpace (http://www.componentspace.com/) with SAML2. Below is the entirety of the Initiate SAML method. We first define the target url which will be of the form https://company.myabsorb.com/account/saml then set our encryption methods. It’s currently suggested to use SHA-256.
A certificate is loaded along with defining the issuerUrl (which should just be your IdP url). Next, we gather all this up and pass it to a GenerateSamlResponse method. This method involves building the various attributes that make up the SAML response. The description of each attribute is described in detail in the SAML specification document found here (https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf).
We've mainly just included the attributes that are required by Absorb. The idPropertyValue should align with what has been set in Absorb such as Username, ExternalID, Email, etc. This is required by us so we can determine how to identify the user. Again, issuer is the IdP Url and target Url is your absorb portal + /account/saml. Next we build the SAML assertion and add it to the response,
Finally, this is then passed back to the Initiate SAML SSO method which posts everything to Absorb. From there the user is redirected and if everything was done successfully the user is logged in.