IdP initiated saml recieved on SP always has RelayState as null - saml-2.0

I have been tasked to implement a SAML2.0 SSO proof of concept and I have successfully integrated the spring saml extension which has been pretty straightforward, thanks to the author. Although, I still haven't been able to get the RelayState parameter to work, I always get its value as null on the receiving SP.
I am using SSOCircle's public IdP with an IdP initiated flow (although we have not blocked the SP initiated mode) and appending the RelayState in the URL.
I am trying to use the SAMLRelayStateSuccessHandler where I could get the RelayState parameter from the SAMLCredential instance but its always null. I traced it back to the HTTPPostDecoder.doDecode(MessageContext messageContext) method (HTTP post binding) and it was null there as well. I also traced the browser network url and noticed the SP consumer end point post url i.e. /saml/SSO contains SAMLResponse but there is no RelayState parameter (my understanding is it will be a separate parameter).
I feel the IdP is probably not sending the RelayState to my SP but also don't see any configuration on the IdP side to enable/disable it so not sure.
I would appreciate advice on debugging this or if someone could share their similar experiences.

I donot have this issue any more but did not explicitly add any fix either. My best guess is ssocircle put in a fix on their end after which the RelayState url started flowing end to end for me.
Appreciate the help by #hos. Did not want to keep the question open so add this as an answer.

Related

Authorization request to get access on behalf of a user results in a 'cookiesDisabled' page

I'm trying to do an Authorization request following the documentation about it on Microsoft (Getting access on behalf of a user: https://learn.microsoft.com/en-us/graph/auth-v2-user). I'm making the request using Azure's Logic Apps. I already made an app registration in Azure AD and gave it the following permissions (I used the app for a few different requests before so that's why it contains a lot of unnecessary api permissions). I already succeeded in getting access without a user (https://learn.microsoft.com/en-us/graph/auth-v2-service). Now I really don't know what I'm doing wrong, so if anybody has an idea of what it is, please let me know. I will try to explain as carefully as possible using screenshots so you guys get the idea of what I'm trying to do.
On the first screen below you can see the api permission I added to my app registration. For this request I'm only asking authorization for the one with arrow next to it(as you will see later on).
On the second screen you can see the HTTP post request I'm trying to make to the authorize endpoint. I blurred out the Tenant and Client_id for privacy reasons. I only added the required parameters in the body as described by Microsoft. In the scope parameter you can see the api permission I'm asking permission for.
On the third screenshot you can see the output of the request. Instead of getting an Authorization code as requested, I get an HTML body.
When I paste that HTML body into a browser it gives me the following result:
I have no clue what I'm doing wrong. I tripled checked to make sure cookies are enabled, made sure third-party cookies are not disabled and added login.microsoftonline to my trusted websites.
I'm starting to think I'm doing something very simple wrong, but I can't figure out exactly what. Any help is welcome! :D
Sorry can't add a comment so posting as an answer
What you are trying to implement is the Authorization Code grant flow of OAUTH 2.0. In Authorization code grant flow following steps occur
1) User is presented with the scopes that an application requires when accessing certain resources,
2) The user authorizes this. and the user is redirected to a redirect url
3) The application then exchanges the code sent with the redirect url to get the actual token which in this case will be sent to the Microsoft Graph for validation.
4) User then sees the information pulled.
The major crux of Authorization Code grant flow is that "User Authorization is required" This basically means that this flow is used when the call is invoked from a browser client where the user is actually interacting. This flow should not go through the Azure Logic Apps. If you want a service or a daemon to access the resources in that case you should use Client Credentials Grant flow

Switch SAML binding from Post to Redirect

As an SP, we've opted for the POST binding option - it seemed to be the advised approach. SAML is now set up and working with the IDP. We would now like to change to Redirect as it is better handled in Ajax calls after timeout.
My question is whether we can switch from POST to Redirect without incurring a setup change on the IDP side. Seeing as both bindings are just using the UserAgent (browser) as a transport anyway, I figured it may be possible. But the binding is defined in the AssertionConsumerService in the metadata which indicates that IDP would need to be informed and have its configuration changed.
Sending a SAML Response (which is what is sent to an Assertion Consumer Service endpoint) via Redirect is not supported by the SAML spec since responses easily get too large to send as a query parameter. See line 420 in the SAML Web SSO Profile spec https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf
Identity Provider issues to Service Provider In step 5, the identity provider issues a message to be delivered by
the user agent to the service provider. Either the HTTP POST, or HTTP
Artifact binding can be used to transfer the message to the service
provider through the user agent. The message may indicate an error, or
will include (at least) an authentication assertion. The HTTP Redirect
binding MUST NOT be used, as the response will typically exceed the
URL length permitted by most user agents.
You can switch to Artifact, though SP metadata will need to updated on the IDP to relay the changed endpoint.

SAML consumer URL

We are implementing SAML integration and I am the service provider and my identity provider is asking me to send "SAML Consumer URL" and "RelayState"
I would need help to understand what is SAML consumer URL & RelayState and how do I get/generate it for my application.
Thank you for your time and help!
TLDR, AssertionConsumerUrl (ACS) endpoint is SAML protocol endpoint, RelayState is like cross-domain cookie, used to coordinate messages and actions of IdPs and SPs.
In 5.1.Web Browser SSO Profile of SAML 2.0 Technical Review, it will give you a general understanding of how the flow goes.
Down to the SSO implementation, for example Shibboleth, this FlowAndConfig doc details the SSO flow pretty well.
In 2. SP Determines IdP and Issues Authentication Request:
Cookie Set by SP
During this step, the SP will preserve the original
resource requested by the browser using a "relay state" mechanism,
which is configured by a relayState property on the <SessionInitiator>
element. The default mechanism does not rely on a cookie any longer,
but many systems do, and send a state management cookie containing the
resource URL to the client along with the request prepared for the IdP
or DS/WAYF.
In 5. Back to the SP:
The browser delivers the response from the IdP to an Assertion Consumer Service endpoint at the SP.
relay state info returned from IdP to SP
Cookie Read by SP
The "relay state" information returned by the IdP, if any, will have
been created by the SP and if using a cookie, will point to a
specially named cookie that should accompany the authentication
response supplied to the ACS endpoint in this step. This is the cookie
set in Step 2 above. If this cookie is missing (or if no relay state
exists at all), the associated application's homeURL property is
substituted as a fall back.
Also, Shibboleth has some wiki for those two terms as well.
AssertionConsumerService concept
RelayState concept
Hope it helps!

Okta Kentor.AuthServices IdentityServer3 IDP-initiated SSO is triggering SP-initiated SSO - error or design?

Using IdentityServer3, Kentor.AuthServices 0.19 (with OWIN middleware) and a standard MVC 4 WebApi 2 app, we have followed instructions at https://github.com/KentorIT/authservices/blob/master/doc/IdentityServer3Okta.md
and it appeared that we achieved successful IDP-initiated login.
However, when we looked closely at this, and using KentorStubIdp (where we first noticed we were prompted to provide a SAML response), we found the following
IDP hits our endpoint, e.g. identityserver/okta/acs, status 303
Successful redirection to our redirection endpoint in our app, which is coded to return a redirection to the identityserver authorisation endpoint, thus
var client = new AuthorizeRequest(new Uri(identityServerUrl + "connect/authorize"));
var returnUrlForIdp = client.CreateAuthorizeUrl(
"{client_identifier}",
"id_token token",
scopesForAuth,
hostUrl,
state,
nonce,
acrValues: string.Format("idp:{0}", idp),
responseMode: "form_post"
);
return Redirect(returnUrlForIdp);
This results in a 302 to identityserver/connect/authorise. It appears that this has all the login information it needs, and I would have expected a 200 straight into the app, but instead we get a 302 to identityserver/login?signin=xxx which gives a 401 which appears to trigger...
The subsequent call to the login endpoint gets a 303 redirection back to the IDP, which marks the start of an ultimately successful SP-initiated login. Meaning it comes back to identityserver/okta/acs, then the /callback endpoint, then /connect/authorise then the user is logged in.
I cannot find any meaningful difference between the first and second calls to /connect/authorise except
The successful attempt is preceeded by a call to identityserver/callback
Cookies for idsvr and idsvr.session appear not to be set on the first call but are in the second
Also, Kentor config settings seem to be in order - e.g.
AllowUnsolicitedAuthnResponse = true
and
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive although this last one didn't seem to have an effect either way
At this point I'm just trying to work out a) whether this is how it is supposed to work under the covers and b) if not, where should I focus my attention to diagnose the problem.
Is there a particular set of circustances that trigger authservices to initiate an SP-initiated SAML request if a, IDP-initiated one is lacking info?
Any advice much appreciated.
Using Idp-initiated sign on with SAML2 + OIDC is a bit tricky, as OIDC doesn't support it. Which means that IdSrv3 is not really built for that scenario either.
The outline of what you would need is:
Idp sends unsolicited response to IdSrv3/AuthServices.
AuthServices validates response
IdSrv3 establishes log in session on IdSrv3.
User is redirected to client application's login init url
Client app initiates a OIDC sig in towards IdSrv3.
IdSrv3 Single signs on with session established in 3.
User is redirect back to client app.
Looks like step 2 works, but step 3 is not properly done. Which means that in step 6 there is no session, so user is redirected all the way to the Idp to pick up existing session. This works, but is somewhat ugly. And if you later on want to do single sign out there is a session count mismatch which might cause issues.

How to securely set authorization header using angularJs?

It is common to authenticate to web services using an authorization header which contains a secret token. And since the security of this mechanism depends on the token to be secret care should be taken that this token is not leaked.
There are countless tutorials on the web which explains how such an authorization header can be set using angular and least the ones that I have actually read use an $http interceptor and now one discusses that the token is not leaked.
There are some public and some private APIs out there which can be talked to cross domain thanks to CORS. And obviously I do not want to send my internal authorization tokens on any of those requests.
Some other techniques come to mind such as setting the token manually only on each and every request, but that means lots of duplicate code. The $http server could be wrapped in an $authenticatedHttp service so that it is always appearent from the object used whether it is the authenticated service or the normal one. However the $http service has so many methods to be wrapped.
Is there a better solution?
UPDATE
From the answers I have the impression that my question was not understood. I try it with a more concrete example:
I have a private web page. People have to login with username/password and let's say for simplicity's sake that we use HTTP basic auth, so username/password are bas64 encoded and are transmitted on every request in the HTTP header "Authorization". So far there is no problem.
But there is this great&free weather widget. I can retrieve the current weather information in JSON format from https://myWhateverWeatherService.tld/weather.json. After the login to my private web service I also retrieve the weather information (CORS allows me to do this).
The problem is that even though myWhateverWeatherService.tld does not require any authentication at all, angular's $http service will still append the Authorization header. And I don't trust the guys at myWhateverWeatherService.tld. Maybe they just set up the service so they can steal Authorization token and do lot's of nasty stuff with them.
I need some reliable way to deal with that. I already thought about checking the url with some regex in the interceptor. This is possible, but it is also not to difficult to forget about a certain case that my regex will miss.
The token is always sent through the wire, I guess that is the most vulnerable part of it.
Since the token must always be present on the http header itself, the only way to make the request more secure is to encrypt the whole request, and for that you should use SSL.
If you are concerned about the safety of storing the token on the client machine, you can keep it only on the browser´s memory, without persisting it on a localstorage or something like that. So every time the user closes the browser and open it again, s/he must log in.

Resources