Security Assertion Markup Language (SAML) version 2.0 is an XML-based protocol that uses security tokens containing assertions to pass information about a principal (usually an end user) between a SAML authority, named an Identity Provider, and a SAML consumer, named a Service Provider.
Note: See the bottom of this post for a useful SAML glossary of terms.
A typical scenario for implementation is:
- Your user is logged in to a company web site or a commonly used web site
- The user needs to access an external system that has an account for the user already configured. Ideally the user would be able to seamlessly access the external system with out having to login again.
- In this scenario, SAML integration can be implemented between the currently system and the external system.
SAML provides a standard for logging users into an application based on their session in another context. This single sign-on (SSO) login standard has significant advantages over logging in using a username/password:
- No need to type in credentials
- No need to remember and renew passwords on different systems
- Helps to eliminate the use of weak passwords
- If the user should no longer face access it can be turned off for all integrated systems
Most organizations already know the identity of users because they are logged in to their local domain. It makes sense to use this information to log users in to other applications, such as web-based applications, especially cloud hosted solutions.
How SAML Works
SAML SSO works by transferring the user’s identity from one place (the identity provider) to another (the service provider). This is done through an exchange of digitally signed XML documents.
Consider the following scenario: A user is logged into a system that acts as an identity provider. The user wants to log in to a remote application, such as a support or accounting application (the service provider). The following happens:
- The user accesses the remote application using a link on an intranet, a bookmark, or similar and the application loads.
- The application identifies the user’s origin (by application subdomain, user IP address, or similar) and redirects the user back to the identity provider, asking for authentication. This is the authentication request.
- The user either has an existing active browser session with the identity provider or establishes one by logging into the identity provider.
- The identity provider builds the authentication response in the form of an XML-document containing the user’s username or email address, signs it using an X.509 certificate, and posts this information to the service provider.
- The service provider, which already knows the identity provider and has a certificate fingerprint, retrieves the authentication response and validates it using the certificate fingerprint.
- The identity of the user is established and the user is provided with app access.
There are many tools and services available to help implement SAML with in your system infrastructure and applications including for your own code as well as third party services that can be integrated.
- SAMTool Tool Kits – https://www.samltool.com/toolkits.php
- Node module – https://www.npmjs.com/package/saml2-js
- OneLogin sample code – https://developers.onelogin.com/saml
- Spring Security SAML – https://projects.spring.io/spring-security-saml/
- ComponentSpace – https://www.componentspace.com/
Third Party Services:
- Okta – https://www.okta.com/products/single-sign-on/
- Auth0 – https://auth0.com/
- OneLogin – https://www.onelogin.com/
- RSA – https://www.rsa.com/
- Idaptive – https://www.idaptive.com/
- Broadcom –https://techdocs.broadcom.com/content/broadcom/techdocs/us/en/ca-enterprise-software/layer7-identity-and-access-management/single-sign-on/12-8.html
- PingIdenty – https://www.pingidentity.com/en/platform/platform-overview.html
Example Implementation with ASP.Net and VB.net
Here is an example of using ComponentSpace’s SAML for ASP.NET component. A specific URL is called for the login and the XML assertion data is signed using X509 Certificates for security purposes.
A X509 certificate is the public part of the SSL that we install for websites. You can download it from the browser’s certificate view when you have the website open for example.
The Identity Provider (IDP) in this case could be a link off an internal web application. When the user clicks that link to a page on the external system, a SAML response is submitted to the external system. The external system then captures the response, parses the XML and authenticates it as follows:
- The response is captured
- It is verified using the X509 certificate
- Encryption of assertions is optional. Some implementations may not send encrypted assertions so we simply verify the source using the X509 certificate. Some implementations will use encryption and in that case, they must use your X509 certificate because only then will you be able to decrypt it using your private key.
- Once the data is retrieved from SAML response which typically includes an agreed upon identifier of the user that is used by both parties – the user can be validated against your system and granted access.
Here is sample code using ASP.Net, VB.Net and the ComponentSpace tools.
Imports System.Configuration Imports System.Collections Imports System.Security.Cryptography.X509Certificates Imports System.Web Imports System.Web.Security Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.Web.UI.WebControls.WebParts Imports System.Web.UI.HtmlControls Imports System.Xml Imports System.Security Imports ComponentSpace.SAML2 Imports ComponentSpace.SAML2.Assertions Imports ComponentSpace.SAML2.Protocols Imports ComponentSpace.SAML2.Bindings Imports ComponentSpace.SAML2.Profiles.ArtifactResolution Imports ComponentSpace.SAML2.Profiles.SSOBrowser Imports System.Collections.Generic Public Class SAMLLogin Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load Try 'Receive the SAML response. Dim samlResponse As SAMLResponse = Nothing Dim relayState As String = Nothing ReceiveSAMLResponse(samlResponse, relayState) Catch exception As Exception Throw exception.Message End Try End Sub 'Function to Process SAML Response. Private Sub ReceiveSAMLResponse(ByRef samlResponse As SAMLResponse, ByRef relayState As String) 'Start of code block to receive response Dim CertificateFile As String = CERTIFICATEPATH Dim PrivateKey As String = PASSWORD ' Receive the SAML response. Dim samlResponseXml As XmlElement = Nothing ServiceProvider.ReceiveSAMLResponseByHTTPPost(Request, samlResponseXml, relayState) 'End of code block to receive response 'Start of block to verify the response signature If SAMLMessageSignature.IsSigned(samlResponseXml) Then Dim x509Certificate As X509Certificate2 = DirectCast(LoadCertificate(CertificateFile, Nothing), X509Certificate2) If Not SAMLMessageSignature.Verify(samlResponseXml, x509Certificate) Then lblError.Text = "The SAML response signature failed to verify." Exit Sub End If End If 'End of code block to verify the response signature 'Start of code block to initial (serialize) SAML response object from response samlResponse = New SAMLResponse(samlResponseXml) If Not samlResponse.IsSuccess() Then lblError.Text = "Received error response" Exit Sub End If 'End of code block to initial (serialize) SAML response object from response 'Extract the asserted identity from the SAML response Dim samlAssertion As SAMLAssertion = Nothing Dim DecryptedAssertionXML As XmlElement = Nothing Dim EncryptedAssertionXML As EncryptedAssertion = Nothing If samlResponse.GetEncryptedAssertions().Count > 0 Then 'Check if the response contained assertions Dim x509Certificate As X509Certificate2 = DirectCast(LoadCertificate(CertificateFile, PrivateKey), X509Certificate2) 'Load certificate EncryptedAssertionXML = samlResponse.GetEncryptedAssertions()(0) 'Get encryption assertions DecryptedAssertionXML = EncryptedAssertionXML.DecryptToXml(x509Certificate) 'Decrypt assertions If Not SAMLAssertionSignature.Verify(DecryptedAssertionXML) Then 'Verify decrypted assertions lblError.Text = "Signed assertion failed to verify." 'Signature of assertion invalid Exit Sub Else samlAssertion = New SAMLAssertion(DecryptedAssertionXML) 'If signature valid, serialize the assertion i.e. initiate a class using xml End If Else 'Error when no assertions found in the response lblError.Text = "No assertions in response" Exit Sub End If If Not AssertionIDCache.Add(samlAssertion) Then 'Enforce single use of the assertion. Add assertion to a cache so it cannot be reused. lblError.Text = "The SAML assertion has already been used" 'Error when same assertion is already used before Exit Sub End If 'At this stage, we have successfully retrieved an assertion and decrypted is successfully 'and have serialized it. Now we can retrieve the user into enclosed and perform a login routine Dim logininfo As String = "" 'Get all attribute statements which are a group of attributes. See image below for an example of attribute statement. Dim attrstmts As List(Of AttributeStatement) = samlAssertion.GetAttributeStatements() For Each attr As AttributeStatement In attrstmts For Each samlAttribute As SAMLAttribute In attr.GetUnencryptedAttributes() 'Navigate through all attributes to find the ones we need If samlAttribute.Name.ToLower = "logininfo" Then 'Attribute found For Each attributeValue As AttributeValue In samlAttribute.Values logininfo = attributeValue.ToString 'Get the value of the attribute Next End If Next Next If logininfo.Trim.Length > 0 Then PerformLoginRoutin(logininfo) 'Perform login routine Else lblError.Text = "Blank logininfo was retrieved." 'Error when required attribute could not be retrieved or invalid End If End Sub Private Function LoadCertificate(ByVal fileName As String, ByVal password As String) As X509Certificate2 Try Return New X509Certificate2(fileName, password, X509KeyStorageFlags.MachineKeySet) Catch exception As Exception Throw exception End Try End Function End Class
Assertion: This is data provided by the IdP that provides the following statements to the providing service:
- Authentication Statement – The user specified in the assertion was authenticated successfully and the specific time stamp.
- Attribute Statements – Provides the attribute values for the user. Specifically, the NameID must be provided as that is the username, but the other attributes are optional.
- Authorization Decision Statements – These declare that a request to allow access to the assertion subject has been approved or denied.
Assertion Consumer Service (ACS): This is the URL end point of the service provider that is responsible for receiving and parsing SAML assertions.
Attribute: Defines the data about a user including items like username, first name, ID, etc.
Default Relay State: This defines the URL that a user will be sent to after successful authentication.
Endpoint: The specific URL’s used by Service Providers (SP) and Identity Providers (IdP) to communicate to one another.
Identity Provider (IdP): This is the authority responsible for verifying and asserting a user’s identity and access.
Metadata: Defines the set of information to be supplied between the Identity Provider (IdP) to the Service Provider (SP). It is structured in xml format.
NameID: A required attribute within the assertion data that specifies the username.
Service Provider (SP): This is the service that the user is requesting to access.
Single Sign On URL: This is the URL endpoint that is responsible for handling SAML transactions.