SAML Single Logout for Keycloak - keycloak

I'm trying to implement single logout for SAML in keycloak and the documentation doesn't mention this properly and is confusing. I was looking for exact steps on how to implement it. So far, what i have done is:
Generate the logout request payload, base64 encode it, url encode it and send it to the logout url as a param. Assume that the realm name is Abc
http://auth-server/auth/realms/Abc/protocol/saml?SAMLRequest={encodedSAMLRequest}
The saml payload is
<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="random uuid" Version="2.0" IssueInstant="2021-02-09T06:53:26Z" Destination="ip-address:8443/auth/realms/Abc/protocol/saml">
<saml:Issuer>https://ip-address:8443/auth/realms/Abc</saml:Issuer>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user-email#abc.com</saml:NameID>
</samlp:LogoutRequest>
However, while sending this, i get 400 error saying "Unknown login requestor"
(eventhough I want to logout)
The site here says the request is valid. Maybe I am missing some extra parameter or something? I would also need an exact way to send. I have to use scala. Thanks in advance!

I think your Issuer might be wrong.
It looks like your issuer is a Keycloak URI, but it is supposed to be a URI representing your application (service provider). It is the same as the client ID field of your configured SAML client in the Keycloak admin gui

Related

SAML IDP initiated SSO transaction

Webapp #1 has a button to webapp #2. When our users click that button, they should be redirected to webapp #2, and be automatically logged-in.
The integration is SAML, so webapp #1 (the IDP) sends a SAML "request" to webapp #2 (the SP), which returns a redirect URL, and webapp #1 redirects to it.
The SP gave me a URL to HTTP POST an assertion identifying the user via the "email" attribute, so I produced this:
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" IssueInstant="2021-12-22T16:59:43.999Z" Version="2.0"><saml2:Issuer>http://www.whatever.com</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod><ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform><ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod><ds:DigestValue>...</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>...</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Conditions><saml2:OneTimeUse></saml2:OneTimeUse></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2021-12-22T16:59:44.053Z" SessionIndex="cfb8f9b5-9616-47db-bc92-7588ce18cf62" SessionNotOnOrAfter="2021-12-22T16:59:44.068Z"><saml2:AuthnContext></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute Name="email"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">si#captisintel.com</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion>
The SP responds with a 302 and a Location header that looks like this:
Location: ?SAMLRequest=nVNNj9owEP0rke%2FkS4VtLc...
Decoded:
<?xml version="1.0"?><samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_f848f04c71671a745722" Version="2.0" IssueInstant="2021-12-22T18:36:19.337Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://auth.whatever2.com/saml/callback" Destination=""><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">whatever2</saml:Issuer><samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/><samlp:RequestedAuthnContext xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Comparison="exact"><saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>
When I visit that URL, I am presented with the login page.
So this is not working.
I have 0 visibility over the SP logs to know what's wrong. All I can guess is that I am not posting this correctly. So does this look right, or should I post this differently? I tried posting the Assertion in the body as-is, wrapping it in a "<samlp:Response" envelope, wrapping it plus prefixing it with "SAMLResponse=". I tried each plain and deflated/base64 encoded.
Another clue is that the SP always returns a 302, no matter what I send them. Even if I send "BLAHBLAH" and not an actual SAML payload, they still respond with a 302.
Any advice?
In a IdP initiated flow, the IdP sends the SAML Response containing a Assertion in a POST like you do. If all goes well the SP should now consider the user authenticated.
The SAML response should be sent in input control named SAMLResponse and should be Base64 encoded.
<input type="hidden" name="SAMLResponse" value="<Base64 encoded SAML Response>"/>
I would guess that what happens is that for some reason, the SP does not accept your SAMLResponse and instead starts the normal SP initiated SAML flow by sending a SAML request to the IdP to authenticate the user.
Why your response is not accepted can be many things. Without the SP logs we can mostly guess.
Off the bat I see that you assertion is missing a Bearer subject confirmation which is mandatory.
From the SAML Profiles spec 4.1.4.2
Any assertion issued for consumption using this profile MUST contain a element with at
least one element containing a Method of
urn:oasis:names:tc:SAML:2.0:cm:bearer. Such an assertion is termed a bearer assertion.
Bearer assertions MAY contain additional elements.
There is also more requirements on the assertion in the same chapter
Some other ideas though:
You should have your assertion in a SAML response, but there are several boiler plate elements that need to be set. So ensure it is valid
It is not unusual to see that the response message itself must be signed and not just the assertion.
I would suggest having a look at the SAML profiles spec 4.1.4.2 to understand what assertion and response must contain.
And also, try agian to see if you can get any feedback on whats wrong from the SP to avoid banging your head bloody doing blind try and fail.
SAML is not the most stright forward protocol there is and there is a lot to get right to get it working and get it secure. As I always try to say to people starting out with it: Dont build it your self, there is alot of good opensource alternatives out there for doing SAML that will make your system so much more secure and maintainable.
If you want to get a better understanding of SAML and how to implement it I can recommend my book, SAML 2.0: Designing secure identity federation
Good uck!
You should be sending a SAML response containing a SAML assertion to the SP rather than just a SAML assertion. You also need to ensure this is encoded correctly as per the SAML v2.0 Bindings specification.
You really need the SP to assist with the debugging. Hopefully their logs will provides details as to why they're rejecting your HTTP Post.

In Keycloak, can you use a JWT to get a caller's identity?

We would like to have users authenticate to a Slack app by providing their current Keycloak JWT as a one-time authentication procedure. This would allow us to associate their Slack user ID with their Keycloak user ID.
However, I can't find any endpoint like AWS' GetCallerIdentity within Keycloak. I have combed the docs, and the closest thing I can find is an identity token mentioned here. However, I can't find anything about how to unravel that identity token to securely gain information about its owner.
Can anyone point me in the right direction?
Thank you!
Open ID Connect defines userinfo endpoint, which is similar to AWS GetCallerIdentity endpoint. But that requires to fire request. I would prefer to read user details from the token.
Standard JWT (OIDC) libraries support token decoding. Access/ID token has 3 parts: header, payload, signature. You can use base64 decode on the payload part and you will get json with user details. Of course proper implementation will read also header to get used algorithm and it will validates token signature with used IdP public key and algorithm. Otherwise someone can tamper token.
https://jwt.io/#debugger-io provides nice visual interface, which will help you to understand and also decode token structure:
Keep in mind: what is returned in the userinfo response depends on OIDC client configuration in the Keycloak

How can I pre-fill email for SAML Google IDP?

We're using SAML 2.0 for SSO, and want to improve the UX by allowing a user to enter their email only once (to identify they need SSO). Is it possible to pre-fill the SAML SSO email field when authenticating with Google's SAML IDP?
I know that the AuthnRequest has an optional Subject field that can pass the principal information to the IdP, but so far I haven't managed to have Google's SSO form pre-populate. Either it's not supported from the IdP, or I'm sending the wrong configuration.
The existing configuration I've been trying to use looks like this:
<AuthnRequest xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ID="_cd...." Version="2.0" IssueInstant="2019-01-01T00:00:00Z" Destination="https://accounts.google.com/o/saml2/idp?idpid=...">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">(issuer_name)</saml:Issuer>
<Subject xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">me#example.com</NameID>
</Subject>
</AuthnRequest>
I would expect the Google SSO form to autopopulate me#example.com, but nothing happens.
The Subject element is optional in an authentication request and even when included, it's ignored by most IdPs. Since authentication request can be sent to the identity provider by an anonymous party, performing a UX action like you're thinking about would certainly lead to an easy phishing vector.

What value do I put for SAMLRequest? WSO2 IS Skipping Login.do

My sectoken is authorized but I don't know how to formulate a URL so that I can bypass the WSO2 IS sign-in page (login.do).
I read online it can be passed through a link in this format:
localhost:9443/samlsso?SAMLRequest=[SAMLRequest]&sectoken=[SECTOKEN]
I'm just not sure what to put in for [SAMLRequest].
As for the answer, you may try to use OneLogin PHP module to generate a SAML Request.
Here is an example SAML Authn Request however you may need to change the issuer, destination, AssertionConsumerURL, and issue timestamp.
Please note there's difference when sending SAML Request as GET and POST. GET (Redirect-Binding) uses deflate and encode, signature is a separate request parameter, POST (POST-Binding) uses signed XML and only encoded XML, not deflated.
SAML is great protocol (very well designed and secure when implemented properly), but it may look difficult for people who hasn't use it before, it may require using external libraries to properly create requests and validate responses. That's why you may be as well looking for option which would may make your life simpler, such as using WSO2IS for SSO (single-sign-on) e.g. using simpleSAMLphp or direct OAuth authorization request.

How to ask for user login when using SAML SOAP binding?

I am learning SAML, and regarding SOAP binding, I am not sure how this works.
For redirect binding and post binding, it is very clear that SP can talk to IdP through browser then IdP can display a login screen if necessary.
But for SOAP binding, it doesn't need to go through browser, an SP can simply send an HTTP request which consist of a SOAP request to an IdP, then if IdP find that there is no valid user session, how can he display a login screen for user to input the username and password?
Or am I missing anything?
Authentication is out of scope of the SAML spec. However, what SAML Profile are you looking at? Is this for Web SSO or something else? For Web SSO, SOAP is only used with the HTTP artifact binding which means you would either be resolving the AuthnRequest (IDP calling the SP) or retrieving the Response (SP calling IDP). The Artifact is sent either via POST or Redirect while resolution of the message (AuthnRequest or Response) is done via back-channel SOAP. So, the browser (http client) is always involved with Web SSO so it is simple for the IDP to authenticate the user via some browser-friendly technology (username/password HTML form, 2 factor strong auth, x509 certs, etc etc).
You can find an example in the SAML Bindings
POST /SamlService HTTP/1.1
Host: www.example.com
Content-Type: text/xml
Content-Length: nnn
SOAPAction: http://www.oasis-open.org/committees/security
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”>
<SOAP-ENV:Body>
<samlp:ArtifactResolve xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_2"
Version="2.0"
IssueInstant="2004-12-05T09:22:04Z"
Destination="https://idp.example.org/SAML2/ArtifactResolution">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:Artifact>artifact</samlp:Artifact>
</samlp:ArtifactResolve>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The syntax might not be exact. Just something to give an idea.
How the IdP chooses to authenticate the user is out of scope for SAML. If you're looking for an example, maybe there is a native application that displays a dialog box to the user, asking him to authenticate. Maybe the IdP sends you a text message through an SMS gateway and you have to respond to the text message in a certain way. The sky is the limit.