During the SAML SSO configuration for our Jenkins, I faced an issue, when some attributes weren’t passed from Okta to the Jenkins instance.
So in this post will try to figure out what is SAML in general, will take a short overview of its architecture and main components, and will make some SAML-requests tracing/sniffing to see which data exactly is passed during authentication process using SAML SSO.
As there is a lot of technical information about SAML – we will take a closer look only at components that are used during Jenkins <=> Okta communication.
See the following posts about our Jenkins-Okta integration:
- Jenkins: SAML Authentication with Okta SSO and users groups
- Jenkins: SAML, Okta, user groups, and Role-Based Security plugin
During this post writing mainly used the Security Assertion Markup Language (SAML) V2.0 Technical Overview from 25 March 2008, so here can be some inaccuracies but in general it looks correct (I hope so).
Other useful materials about SAML are:
- SAML 2.0
- SAML Response (IdP -> SP)
- What is SAML and How Does it Work?
- How SAML Authentication Works
- and all the SAML XML-specifications can be found here: http://docs.oasis-open.org/security/saml/v2.0/
As here is a lot of text and it was initially written in this blog in Russian – my apologies for the errors/misprints here. Please, fill free to comment about them as well as any mistakes in the processes described below.
SAML: an overview
The SAML SSO authentication includes at least two main parties – a Service Provider (SP), and an Identity Provider (IdP), and the process itself consists of the Trust Establishment process and actually an authentication process.
For example, in our case, the Jenkins instance will play the Service Provider role and Okta will be the Identity Provider.
Shortly, an authentication process has the next flow:
- a user opens Jenkins URL in a browser
- Jenkins redirects this user to an SSO URL, Okta
- Okta authenticates the user and sends this information back to the Jenkins
- Jenkins performs an authorization check, for example via the Role-Based Security plugin and configured roles
To pass data about a user SAML uses an Assertion object which includes all necessary information – a user username, its authentication status, groups, etc, depending on an Assert type.
Which Asserts are necessary in a particular case – SAML defines in its SAML protocols (will be discussed in the SAML protocols part of this post), and SAML protocols are passed with the HTTP or SOAP, and this is defined in the SAML Bindings (see the SAML bindings part).
In its turn SAML protocols, Bindings and used Asserts are incorporated into Profiles (see the SAML profiles), for example – Web Browser SSO Profile (see the Web Browser SSO Profile), or an LDAP-profile, which defines which attributes and Identifier and passed in an Assert.
- Identity Provider (IdP): a system, which generates an assert (an object or document with an authentication data) about a subject. For example, it can be a user for which an IdP generates an assert which states that John Smith was successfully authenticated and he has attributes like a Group and a mailbox
Identity Provider is also known as SAML Authorities и Asserting Party.
- Service Provider (SP): a system, which uses information from the IdP. During that, a Service Provider relies on the assert with the authentication data but still can apply additional local policies to determine which permissions inside of this SP the user has
Service Providers also known as Relying Parties, as they rely on information from an assert received from an Identity Provider (Asserting Party).
SAML Use Cases
Before going deeper let’s take a short overview of SAML use cases.
During the SAML authentication information exchange at least two sides included – a SAML asserting party and a SAML relying party.
SAML asserting party – a system which creates a SAML asserts, and accordingly a SAML relying party – a side, which uses those asserts.
When a SAML asserting party or SAML relying party performs a request – it becomes a SAML requester side, and the second side – a SAML responder side.
During the SAML authentication participants in the process operates by the SAML roles which describe SAML services, SAML protocols and asserts types to be used.
For example, for the SSO – SAML defines SAML roles Identity Provider (IdP) and Service Provider (SP), reviewed above.
Another example can be the Attribute Authority role when one side generates an assert in the response of attributes request from another side – an Attribute Requester.
In most of the SAML asserts there is a subject that needs to be authenticated. Such a subject can be a user or, for example, a dedicated server.
Usually, an Assert contains information like “This is John Smith, he has a mailbox “email@example.com” and he was authenticated with the Password Authentication mechanism“.
In its turn a Service Provider will decide itself which of this information it needs and depending on its own local access policies will grant or deny access to John.
Web Single Sign-On Use Case
IdP-initiated Web SSO
Multi-domain Web Single Sign-on – one of the most used SAM Web SSO use cases.
In this case, a user has a login session (e.g. a security context) on some website, for example, airline.example.com. At some point in time directly or indirectly for a user he is redirected to a partner’s website, let’s say cars.example.co.uk, which is playing the Service provider role in this example. An IdP website (the airline.example.com in this case) creates an assert for this SP (cars.example.co.uk), affirming that this user is known, authenticated, and has a set of attributes.
Because the SP cars.example.co.uk trusts to its IdP airline.example.com – it creates a local authentication session for this user:
With this approach, a user is authenticated on the IdP first and after this can access a protected resource on an SP.
This way is known as an IdP-initiated Web SSO.
SP-initiated Web SSO
A more widely use case is viсe versa – when a user first accessing a Service Provider resource which redirects this user to an IdP service to authenticate him.
After the user performs authentification steps on an IdP – this IdP will create an assert that will be used by the SP to check the user’s permissions on this SP.
This approach is called SP-initiated Web SSO.
The SAML “consists” from a bunch of building blocks which fitted together allows building various ways to work with SAML.
Those components are describing mechanisms to be used to pass an identity data, authentication information, and a user’s attributes.
As already discussed, during SAML authentication asserts are used which includes a set of statements, and those statements contain information about a user. For example, an asset can contain a statement with information about user’s Name “John Smith“, and another statement with its email “firstname.lastname@example.org“, and his Group is DevOps.
SAML describes three main statement types:
- Authentication statements: those are created by the side which successfully authenticated a user (for example – by Okta in the IdP role)
- Attribute statements: a set of attributes, for example, a user’s mailbox
- Authorization decision statements: a set of authorization rules, for example, actions which are allowed for this user
The SAML assert contains data (the statements discussed above) about an authenticated object. An assert contains a subject of the assert (e.g. a user), conditions for this assert to be valid, and a set of statements.
The SAML assert structure and fields are described in the SAML assertion XML schema.
Usually, asserts are created on an IdP side which received a request from an SP. To pass those requests SAML protocols are used which describes their structure and content for those messages in the SAML-defined protocol XML schema.
Some of those protocols are Authentication Request Protocol, Single Logout Protocol, Assertion Query, and Request Protocol, etc.
Ways to deliver those messages via low-level network protocols such as HTTP or SOAP are set in the SAML bindings.
Those bindings are HTTP Redirect Binding, HTTP POST Binding, HTTP Artifact Binding, etc.
Below we will take an overview of HTTP Redirect Binding, which is used during Jenkins <=> Okta authentication (see the SP-Initiated SSO: Redirect/POST Bindings part of this post).
And the last is the SAML profiles which are defines SAML use cases, for example, the Web Browser SSO profile.
A Profile describes the content of SAML asserts, protocols, and bindings to be used together to solve specific business needs.
There are also Attribute Profiles, which not relates to messages protocols or bindings, but describes how to exchange information about attributes by using asserts.
Metadata defines ways to distribute information about the configuration used between IdP and Sp. For example, about SAML bindings used, participant’s roles (IdP, SP), supported attributes, encryption details, etc in its own SAML Metadata XML schema.
In some cases, a Service Provider may require more detailed information about the authentification type used on an IdP side.
In this case, a SAML Authentication Context is used which is added to the authentication statement of an assert passed between them.
Besides that, during a SAML request generation, an SP may specify an authentication context in its request to an IdP side with a requirement to authenticate a user with specified certain mechanisms to be used, for example, to authenticate a user with two-factor authentication.
All together can be displayed with the next scheme:
SAML XML Constructs and Examples
Relationship of SAML Components
SAML asserts includes one or more statements, and are passed via a network with HTTP, SOAP or other data transfer protocols:
To make a SAML-request tracing and parsing let’s use a Chrome’s
Install it, open Chrome Developer Tools, open Jenkins tab, log in and let’s investigate what data is transferred between our Jenkins and Okta.
The Assertion, Subject, and Statement Structure
Let’s take a closer look at an Assert, Subject and its statements:
<saml2:Assertion ID="id5145226399860569827675102" IssueInstant="2019-11-02T12:37:19.440Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exk1pgr3yktuVLp5a357</saml2:Issuer> ... <saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">email@example.com</saml2:NameID> <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData InResponseTo="_oyzxonwjrhnetdqqctfwbbfwmvgtrfa9jy1xu2o" NotOnOrAfter="2019-11-02T12:42:19.440Z" Recipient="https://ci.example.com/securityRealm/finishLogin"/></saml2:SubjectConfirmation> </saml2:Subject> <saml2:Conditions NotBefore="2019-11-02T12:32:19.440Z" NotOnOrAfter="2019-11-02T12:42:19.440Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> <saml2:AudienceRestriction> <saml2:Audience>https://ci.example.com/securityRealm/finishLogin</saml2:Audience> </saml2:AudienceRestriction> </saml2:Conditions> <saml2:AuthnStatement AuthnInstant="2019-11-02T12:37:16.992Z" SessionIndex="_oyzxonwjrhnetdqqctfwbbfwmvgtrfa9jy1xu2o" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> <saml2:AuthnContext> <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef> </saml2:AuthnContext> </saml2:AuthnStatement> ...
In this XML fragment we can see an assert example with one authentication statement:
- at first line with the
saml:prefix a SAML assert is declared (
<saml2:Assertion>) and its generation time (
- next, SAML version used –
- a unique identificator of an IdP which created this assert –
- then, in the
<saml2:Subject>block, information about an authenticated subject is added –
<saml2:NameID>firstname.lastname@example.org</saml2:NameID>and his identificator in an email view –
- in the
<saml2:Conditions>conditions are specified to consider this assert to be valid, for example, time range (
- and finally in the
<saml2:AuthnStatement>an authentication type used to authenticate this user – (
Attribute Statement Structure
The next part is the
... <saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"> <saml2:Attribute Name="Group" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue> <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">DevOps</saml2:AttributeValue> </saml2:Attribute> </saml2:AttributeStatement> ...
In addition to the information about authentication discussed above, an IdP can pass attributes about an authenticated object.
- here is the
<saml2:Attribute Name="Group">, an attribute is passed with two values – a group
<saml2:AttributeValue>Everyone</saml2:AttributeValue>, and a second group
<saml2:AttributeValue>DevOps</saml2:AttributeValue>, using the SAML Basic attribute profile (
As already mentioned SAML defines a bunch of different profiles for different use cases.
In our case with Jenkins and Okta the Web Browser SSO Profile is used which is the most widely used SAML authentification type used.
Web Browser SSO Profile
Web Browser SSO Profile defines a procedure to exchange SAML messages to realize Web SSO, in particular:
- first, it describes an authentication initialization vector – IdP-initiated or SP-initiated
- the second, which SAML bindings have to be used to pass those messages over the network
We already discussed IdP-initiated and SP-initiated roles above, and in our case, it will be the SP-initialized (a user opens Jenkins URL, which requests this user authentication from an IdP).
The back-way authentication initialization will work too, when a user first opens its Okta account, then clicks on a Jenkins icon in there – then Okta will play an initializator role and will generate an assert which will be passed to the Jenkins instance.
The second thing defined by the profile are bindings used to pass data between an IdP and an SP.
For example, an Authentication Request may be transferred from the SP to the IdP using HTTP Redirect Binding, HTTP POST Binding or HTTP Artifact Binding, and a Response message may be transferred from an IdP to an SP using HTTP POST Binding or HTTP Artifact Binding.
In doing so, in the same authentication session, an Authentication Request can be sent by using one binding type, and a Response message by using another one, which is described by an IdP and SP configuration.
Respectively, there are various authentication process types:
- SP-initiated SSO using Redirect Binding to pass the
<AuthnRequest>message from an SP to an IdP, and by using POST Binding to pass the
<Response>message from an IdP to an SP
- SP-initiated SSO using POST Binding for the
<AuthnRequest>message and the Artifact Binding to transfer the
- IDP-initiated SSO using POST Binding to transfer the
<Response>message from an IdP to an SP;
<AuthnRequest>is not used at all
Jenkins and Okta – SP-Initiated SSO: Redirect/POST Binding
And finally, let’s speak in details about the whole SSO authentification process between the Jenkins and Okta by using the SP-Initiated SSO: Redirect/POST Bindings, which can be easy to identify by the HTTP methods from the
Schematically this process can be displayed as the next:
And step by step SSO authentification here:
- a user opens a sp.example.com page (the Jenkins URL in this case), and he has no active login-session (e.g. security context). SP will save the URL requested by the user
- the SP returns a request to the user’s browser with 302 or 303 redirect code and in the HTTP Location header will specify an SSO service URL, and in the URL-variable
SAMLRequestwill pass an
The browser then will handle the received redirect and will issue HTTP
GETto an IdP URL, passing the
- the SSO service checks if the user already has an active login-session which has to comply with the authentication type requested as it is passed in the
AuthnRequestfrom the SP (Jenkins). If such a session is not found – then the user has to authenticate first on the IdP first with his login and password
- the user is authenticated on the IdP where a security context is created for him
- the IdP Single Sign-On Service generates a SAML
<Response>which includes an assert with this user security context. The SAML
<Response>is placed into the HTTP
SAMLResponsebody is transferred in the base64 encoding in the
The HTML generated is passed to the user’s browser as an HTTP-response.
- the browser will issue a
POST-request to the SP (Jenkins) passing the
The SP will check the <
Response>content and will create a new local security context for this user
- as the last step, the SP can perform an additional user’s authorization to check which permissions this user has in this system. For example, Jenkins can authorize the user by using the Role-Based Security plugin
Well, that’s all in general.
Also published on Medium.