I am trying to understand SSO using SAML. I have come across the RelayState parameter and am very confused exactly why it comes first in SSO to send encoded URLs? What exactly does it mean?
Please read the following from the Google Developer documentation:
Google generates a SAML authentication request. The SAML request is encoded and embedded into the URL for the partner's SSO service. The RelayState parameter containing the encoded URL of the Google application that the user is trying to reach is also embedded in the SSO URL. This RelayState parameter is meant to be an opaque identifier that is passed back without any modification or inspection
The original meaning of RelayState is that the SP can send some value to the IDP together with the AuthnRequest and then get it back. The SP can put whatever value it wants in the RelayState and the IDP should just echo it back in the response.
This RelayState parameter is meant to be an opaque identifier that is passed back without any modification or inspection
There is also another, de facto standard use for RelayState when using Idp-initiated log on. In that case, there is no incoming request from the SP, so there can be no state to be relayed back. Instead, the RelayState is used by the IDP to signal to the SP what URL the SP should redirect to after successful sign on. In the standard (Bindings 4.1.5) it is stated that RelayState "MAY be the URL of a resource at the service provider."
It looks like Google is using RelayState for the target URL even on SP-initiated sign on, which is perfectly fine. But the IDP should, as the documentation says, just relay it back.
RelayState is an identifier for the resource at the SP that the IDP will redirect the user to (after successful login). It is a way to make the process of SSO more transient to the user because they are redirected again to the same page they originally requested at the SP.
As per official SAML document,
Some bindings define a "RelayState" mechanism for preserving and conveying state information. When
such a mechanism is used in conveying a request message as the initial step of a SAML protocol, it
places requirements on the selection and use of the binding subsequently used to convey the response.
Namely, if a SAML request message is accompanied by RelayState data, then the SAML responder
MUST return its SAML protocol response using a binding that also supports a RelayState mechanism, and
it MUST place the exact RelayState data it received with the request into the corresponding RelayState
parameter in the response.
This below flow diagram may help you step by step. ACS URL and relayState both are different. relayState gives you one more info/url to handle where exactly user want to go. more details
Related
I am looking for a way to tie the SAML request I make to an IDP to the SAML Assertion it sends back. Is there a way to do that?
One idea I had was to use the SessionIndex. I have found that in practice, in some cases the SessionIndex can be used to do this, because some SAML servers return the ID from the initial request as the SessionIndex in the SAML Assertion, but I have also found that is not done universally / does not seem to be required by the spec. It seems like the intention of the SessionIndex is just to tie together the SAML Assertion with subsequent calls, e.g. logout attempts, so there's no requirement that it be tied to the initial request. I draw that conclusion from this post, which says "At least one assertion containing an MUST contain a element with at least one element containing a Method of urn:oasis:names:tc:SAML:2.0:cm:bearer. If the identity provider supports the Single Logout profile, defined in Section 4.4, any such authentication statements MUST include a SessionIndex attribute to enable per-session logout requests by the service provider." I have also reviewed this post, which breaks down the use of SessionIndex and I think supports the same conclusion.
I don't see anything else in the spec that seems promising, but I am hoping I may be missing something - is there any reliable way to pass data to the IDP in a SAML request and get it back in the SAML Assertion?
FYI, the reason why I want this is to support mobile sso login where my mobile device uses an embedded web browser to make an OAuth2 call to my web server, the web server authenticates the user, and then sends back an authorization code to the mobile device with a redirect. I want to use PKCE to secure the OAuth2 flow between the mobile device and the web server, but that requires me to be able to tie the initial request call to the final redirect with a shared code.
There are at least two methods that can be used, so long as the user journey starts where it should, on the page they are trying to get to, making this a service-provider initiated authentication request. As the service provider in a SAML-based federation, you start the process by sending the identity provider an AuthnRequest.
The first method availables comes by tracking the AuthnRequest's ID. In a good SAML implementation, that AuthnRequest's ID is big and random and likely not repeatable in our lifetime. The SAML Profiles spec says on lines 625-626:
If the containing message is in response to an <AuthnRequest>, then
the InResponseTo attribute MUST match the request's ID.
Therefore, as long as you keep track of the ID's that you send out, then you can tie the Request's ID to the Response's inResponseTo.
The second method at your disposal is RelayState. This is an aptly-named element of an AuthnRequest that you can use to transfer state to the Identity Provider an back. This is a field that you can use as you see fit as the service provider, and the responder has to send it back. The Bindings spec says on lines 265-271:
Some bindings define a "RelayState" mechanism for preserving and
conveying state information. When such a mechanism is used in
conveying a request message as the initial step of a SAML protocol, it
places requirements on the selection and use of the binding
subsequently used to convey the response. Namely, if a SAML request
message is accompanied by RelayState data, then the SAML responder
MUST return its SAML protocol response using a binding that also
supports a RelayState mechanism, and it MUST place the exact
RelayState data it received with the request into the corresponding
RelayState parameter in the response.
As such, you can put something in that field, and the IdP must parrot it back untouched. You should make sure that what you put in there doesn't compromise the user or security, so just be mindful of how you use it. It's going to end up in logs somewhere.
In SAML, if the SP sends a RelayState parameter during an SP-initiated SSO login, the IdP (OneLogin) should send the RelayState back exactly as the SP sent it. This can be used to navigate to a particular page, etc.
However, OneLogin doesn't seem to be sending it back. When configuring a OneLogin app, the configuration has a field called RelayState. I've never needed it before now so I've left that empty thinking it's is the 'default' RelayState in case the SP doesn't send one or in case its a IdP initiated login but this doesn't seem to be the case.
Is there a way to get OneLogin to send back the RelayState the SP sent during an SP-initiated login? Do I need to add some variable/tag in this RelayState app configuration field? As an aside, even if I put something random in the RelayState field OneLogin is not getting sent to the SP even on an IdP initiated login (so maybe I need to turn it on somewhere I'm not seeing).
I tested here using our SP application and OneLogin without any issues. The relay state included with the SAML authn request was returned by OneLogin with the SAML response.
My understanding is that the relay state that can be configured in OneLogin is for IdP-initiated SSO only. I've left this blank. There was no special setting required in OneLogin to get it to correctly return the relay state as part of SP-initiated SSO.
Are you sending the authn request using HTTP-Redirect or HTTP-Post?
Either should work. I suggest double checking the RelayState parameter is included correctly with the authn request.
I'm reading the SAML specification and experimenting with Keycloak and Shibboleth IdPs and I'm not sure how to implement one feature in an SP-initiated login.
I have a service that traditionally used to have an SP status information displayed on its login page (e.g. application version, status). After switching to using an IdP login page I'd like to keep displaying such per-SP additional information on the login page of the IdP. I'm interested in the data exchange, not in templating the login page itself.
Does SAML 2.0 specification allow for sending arbitrary data to the IdP for the purpose of logging in? If not, what are other options that can be used to decorate IdP login page using SP-generated data?
Sort of. The authentication request from SP to IdP is allowed to have "custom" extensions (the Extensions parent element), the content of the extensions is up to you. From the spec:
[Optional] This extension point contains optional
protocol message extension elements that are agreed on between the
communicating parties. No extension schema is required in order to
make use of this extension point, and even if one is provided, the lax
validation setting does not impose a requirement for the extension to
be valid. SAML extension elements MUST be namespace-qualified in a
non-SAML-defined namespace.
If you're writing your own IdP, you could certainly make use of Extensions and do whatever you wish with it. "Standard" (commercial/OSS) IdPs won't know what to do with your extension. It'd be an interesting test to see if Shibboleth or Keycloak libraries parse the Extensions element and give you the contents.
The other, more standard possibility is using RelayState. This is a spec-compliant way of passing some provider-specific state information around, incl. from SP to IdP:
3.1.1 Use of RelayState Some bindings define a "RelayState" mechanism for preserving and conveying state information. When such a mechanism
is used in conveying a request message as the initial step of a SAML
protocol, it places requirements on the selection and use of the
binding subsequently used to convey the response. Namely, if a SAML
request message is accompanied by RelayState data, then the SAML
responder MUST return its SAML protocol response using a binding that
also supports a RelayState mechanism, and it MUST place the exact
RelayState data it received with the request into the corresponding
RelayState parameter in the response.
Again, all IdPs or downstack libraries will parse RelayState but how they handle it from there depends on their reading of the spec. For one, the spec requires RelayState to be 80 bytes and integrity protection via a signature or "other means". This limitation is often ignored by IdPs and SPs.
What SP-specific information are you trying to display on IdP login page?
The only thing that an SP can send to the IdP is the Subject (see lines 585-589 of the spec).
I started with Service Provider based SSO for SAML. Since the user had to enter his email before proceeding with the login, a state variable was initiated and passed on to the SSO. It comes back through the callback URL and hence was check again for the sanity purpose. It protected against CSRF attacks.
Now IdP initiated SSO doesn't allow me to set state variable at all. Login starts at Identity Provider and only an auth token is provided to the app. I do not know which user is authenticating from the beginning. If I remove the state variable check, it could trigger a CSRF attack as well.
I am also using omniauth in rails which makes state variable a compulsory param and SSO provider is auth0.
What is the way to attach state variable to IdP initiated SSO solutions?
The de-facto standard value of the RelayState parameter in IDP-init-SSO SAML flows is the URL that you want to send the user to after successful validation of the SAML assertion at the SP. That would work for the vast majority of SAML deployments out there.
However, that mechanism indeed does not protect against CSRF attacks this is why the spec is silent on the value of RelayState in IDP-init-SSO and leaves it open to agree on mechanisms between IDP and SP to prevent CSRF through the value of that parameter. One such mechanism would be to use a signed value in the RelayState but as said, nothing is standardized and it would thus depend on a bi-lateral agreement between IDP and SP which does not scale.
In summary: send the value of the URL that you want the user to go to as the RelayState value in the "unsolicited" SAML Response that you send to the SP. How you get the IDP's SAML stack to do that is implementation specific. For Auth0 you can read on this at: https://auth0.com/docs/protocols/saml/saml-configuration#idp-initiated-sso, and in your case it would look like:
https://{accountname}.auth0.com/samlp/YOUR_CLIENT_ID?RelayState=http://FINAL_DESTINATION_URL
I've implemented my Service Provider and Identify Provider following the SAML Profile for Web SSO using HTTP POST Protocol Binding. However, I am a bit confused as to how the Identity Provider will provide an <AuthnStatement> if the HTTP POST coming from the Service Provider is not tied to a session on the Identity Provider.
Could someone enlighten me how one would be able to do this?
The other approach I could use is the HTTP Redirect Binding, but that requires User-Agent intervention (i.e., the browser), often using the User-Agent simply as a pass-thru intermediary to faciliate the Request-Response message exchange. I'd rather use HTTP POST for this reason, because the message exchange occurs server-side, so the user sees nothing happening on their screen.
However, using HTTP Redirect makes more sense to me with respect to how I'd be able to tie a session to a request. Since the HTTP Redirect is facilitated via a User-Agent, the request to the IdP will have a session (if previously authenticated). What I don't get though is how to send an <AuthnRequest> on a HTTP Redirect. Answered by JST
So I'm a bit confused and would love to hear what other people are doing. Here are my questions again:
Using the HTTP POST Protocol Binding with the IsPassive option the <AuthnRequest>, how do I tie a request made by the Service Provider to a session on the Identity Provider? In other words, how does the Identity Provider know who is making the request if the POST is coming from the Service Provider which is technically an anonymous session?
Using the HTTP Redirect Protocol Binding, how do I send an <AuthnRequest> to the Identity Provider if I am using a HTTP Redirect? Answered by JST
UPDATE
Sorry for the confusion if I was unclear in my explanation above. I am implementing both the IdP and SP (via a plugin). The IdP is an existing application for which I want the SP (a third-party system) to use for authentication (i.e., Web SSO). I am developing a simple PoC at the moment. The SP is actually a third-party Spring application for which I am developing a plugin to perform the SAML operations.
I should have mentioned that I am trying to do this using the IsPassive option, that meaning the User-Agent doesn't come into play during the message exchange. It is simply the catalyst that gets the SAML-party started. Right? With that in mind, given that the user is anonymous at Step 1, what does the SP send to the IdP to allow the IdP figure out whether the user is already authenticated? Because of IsPassive, the HTTP POST isn't sent via the User-Agent
UPDATE
Question 1 Revised: How does the IdP resolve the Principal when the AuthnRequset is sent with the IsPassive option on?
Straight from the SAML 2.0 Profiles document, page 15, lines 417 to 419:
In step 4, the principal is identified
by the identity provide by some means
outside the scope of this profile.
What I'm really after is an explanation how to implement some means.
The thing to keep in mind is that there's no connection between a session on the IdP and a session on the SP. They don't know about each other, and communicate only through the SAML messages. The general steps for SP-initiated SAML SSO are:
Anonymous user visits resource (page) at SP.
SP identifies that user needs to be authenticated at IdP.
SP constructs AuthnRequest and sends to IdP.
IdP does some sort of authentication, constructs SAML Response and sends to SP.
SP validates Response and, if valid, does whatever is necessary to identify user at SP and get them to originally requested resource.
Yes, there does need to be some way to connect the SP's AuthnRequest to the IdP's Response. That's covered by the SAML spec: the SP's AuthnRequest includes an ID value, and the corresponding response from the IdP MUST include an InResponseTo attribute (on its SubjectConfirmationData element) with that ID value. The Authentication Request Protocol also allows the SP to pass a RelayState parameter to the IdP, which the IdP is then REQUIRED to pass along unchanged with the SAML Response. You (in the SP role) can use that RelayState value to capture state information allowing the user to be relayed to the originally requested resource.
That implies that when you implement an SP, you'll need some mechanism for recording ID and RelayState values, and your Response processing needs to validate InResponseTo and RelayState values it receives. How you choose to create and interpret RelayState values is up to you, but keep in mind that there is a length limit. (We use random GUID values corresponding to locally saved state data, which has the extra advantage of not giving any hint of meaning to the RelayState values.)
How does the IdP know who is making the request? The AuthnRequest must include an Issuer element that identifies the SP. It might also contain an AssertionConsumerServiceURL (the URL to which the Response is to be sent), or the IdP may have a local mapping of the Issuer to the proper URL.
How do you send an AuthnRequest using HTTP Redirect? The only difference between AuthnRequest sent using POST vs. Redirect, besides using GET rather than POST, is that the AuthnRequest XML has to get compressed (using the DEFLATE encoding).
Hope that answers most of your questions.
John,
I might suggest taking a step back and doing some more research before you decide to write your own SAML IDP/SP Implementation. You appear to be mixing Bindings with Profiles, Unsolicited vs Solicited Web SSO as well as the fact that SAML requires that the User Agent (aka Browser) is the bearer of almost all the messages between the IDP and SP. There is also a ton of info in the spec that will will have to implement to ensure your solution is actually secure.
I would suggest starting with our SAML Knowledge Base and then moving on to the OASIS SAML 2.0 Technical Overview for information on these flows.
Alternatively, if you decide to go best-of-breed you can check out our PingFederate product which can enable ALL the SAML IDP/SP use cases for you in < a day.
Hope this helps -
Ian
Unlike Ian, I am not associated with a company producing SAML-related products. However, I'd give somewhat similar advice: step back and identify why you are implementing SP or IdP. Are you really acting as both SP and IdP, or are you really just one or the other? If you're implementing/acting as IdP only, then it's fairly likely that a product like PingFederate or something similar offers all you need through configuration rather than requiring you to write custom code. If you're implementing SP, then such a product MAY be able to help you out, but it depends to a large extent on the characteristics of the system you're integrating it into. I am speaking as a developer who has done both IdP and SP implementations, and evaluated several tools before determining that because of our specific system, clients, and requirements, a custom implementation was our best option. It's been in place for over a year, with several clients using it (including some using varying commercial IdP tools).
If you can identify your use cases in terms of SAML profiles/bindings, then you'll be better equipped to make a buy-vs-build decision.