Exchange IP-STS JWT token for ACS JWT token - security

I have an azure ACS service, which trusts an IP-STS.
For an active scenario, I first get a JWT token from my IP-STS using username, password credentials. There is Oauth2 endpoint and everything works quite well.
Is it possible to "exchange" this IP-STS token for a JWT token issued by my azure ACS ? If so, is there an example of code that does this. (To make things worse, all my code is in JavaScript (actually TypeScript) but that doesn't really matter).
Update :
I'm working on your hint with the ACS OAuth2 draft 13 endpoint.
I proceed as follows : I ask my custom STS (ThinkTecture STS) to give me a JWT token for the "ACS OAuth2 draft 13 endpoint" realm. This requires an oAuth client id and secret which are global in the TT STS and I assume they are irrelevant. In the TT STS management I have a symmetric key configured for this realm : key1. I receive the 3-part JWT token. The signature on the token is indeed made with key1.
I then pass this token to ACS with client id and secret from a service identity and parameters as specified
var form = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "http://oauth.net/grant_type/jwt/1.0/bearer" },
{ "assertion", rawtoken (the header dot body dot signature form TT STS },
{ "scope", "http://localhost"}
});
Unfortunately I now get
{"error":"invalid_client","error_description":"ACS50027: JWT token is invalid. \r\nTrace ID: b107cda5-393b-4b50-b14a-ebaa0ac41913\r\nTimestamp: 2012-12-05 08:58:10Z"}
I understand JWT is in beta and therefore ACS50027 is not yet documented. The hard part is that there is no known way to debug this. Thanks for nay help.

This is definitely possible, but I don't think any of the existing ACS samples do it so you're slightly in uncharted territory.
The approach I would recommend is to use the ACS OAuth2 draft 13 endpoint (as in this sample, but JWT instead of SAML and IdP instead of service identity). The request would be something like:
grant_type=http://oauth.net/grant_type/jwt/1.0/bearer&assertion=(JWT)&scope=(RP realm).
You'll need the issuer of the JWT to match your registered identity provider, along with an associated signing key, plus rules to pass through or change any claims as necessary and the RP to have a token type of JWT.

Ok, I finally found a way to do this. Your hint was crucial for the success. The (very) tricky part is that the IP-STS uses a symmetric key to sign the JWT token. I had to programmatically (using the odata api) insert this key in the ACS backoffice under the Identity provider. (the managament console does not show this key anywhere) Everything is nearly fine. The only trouble is that the ACS copies the audience ("aud") from the original token, while I request a token for a different audience ("scope"). Any ideas there ?

Nope,
You can't Exchange tokens in ACS. The only possibly viable way of doing so, is if you are able to register your IP-STS as an IdP in ACS (you will be able to do so, if your IP-STS supports WS-TRUST protocol). This will throw you on the passive scenario.
The only possible active scenario way is to get JWT token directly from ACS using Username/Password authentication with Service Identities. Well managing service identities in ACS is not as managing ASP.NET Membership provider, but it has a Management API.
The possible ways for authenticating with a Service Identity is Password, Symmetric Key, X.509 Certificate. So, if you twist enough your original IP-STS, to give you a Symmetric Key as a Claim in its JWT token, you will be able to get JWT token from ACS using Service Identity authenticating with that Symmetric Key.
But, if you already have a JWT token, why you need another one from ACS?
UPDATE
Well, the claims transformations are only option in the "Passive" mode. For active mode, the only way (that I know) is to use Service Identities, thus no claims transformations.
The issue with Passive is that because of security reasons, ACS will create a hidden POST form to POST submit transformed token to your Relying Party Application (RP). So there is no way to Actively get a Passive behavior. What you could do just for the sake for trial, and that will fail because of the passive POST in hidden form is the following:
If you are willing to experiment (and I have not tested and I am totally unaware of the result), you may try simulating wsignin1.0 action providing the original JWT token. You can look at the WS-Federation Passive Requestor Profile, section 3.1 on how to construct a Sign-In request. You can also use Fiddler to fully track a Passive scenario chain of events. The one that you shall try reconstruct is the wsignin1.0 request that goes from the registered IdP back to ACS.
At some point you will have the resulted HTML, which contains a FORM element. That form will have two hidden fields - wa with value of wsignin1.0 and wresult which will contain URL encoded <t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">.... This is what you want.
If you succeed in recreating the original SignIn request to ACS from your IdP, than this will work.

Related

Why use an idp issued id_token -- versus a custom session cookie?

I'm struggling to understand when to use a session cookie, or just use the IdP issued token as a bearer token.
Is the primary advantage of using an IdP issued token that you get a standards based mechanism for tokens (including ensuring non-tampering, as the JWT is signed)?
As opposed to using a proprietary vendor mechanism of converting it to a claim identity, and then to a custom session cookie (as per owin middleware)?
Doesn't the custom cookie approach have an advantage that one can add non-ipd issued claims (eg: from a system db)?
What other key advantage does using an idp issued id_token have over a cookie based session approach?
Is it maybe that a bearer token approach would not need caching on the server, so that one can re-use it to call 3rd party services that have a different audience value? Whereas the token would be lost if we used a cookie? (I'm reaching, I know, as I don't yet understand how calling 3rd party services works).
The Id token is meant for your user-facing app as proof of who the user is.
It is then up to your app how you choose to authenticate the user on future requests.
While technically you could just store the Id token and use that, as you mentioned, it cannot be extended since it is digitally signed.
Which for most our projects is no good.
At least in regular Azure AD (not sure about B2C), you cannot use the Id token to get an access token for another API.
In there, you would have to get an authorization code in addition to the Id token at the time of sign in,
and exchange that for an access token (which you then cache server-side).
If you use the Id token as an authentication token for your app, keep in mind that Id tokens issued from the token endpoint (when exchanging an authorization code in normal Azure AD) are not signed (I guess since you receive them as a response to your request + over HTTPS).
Only the Id token you get in the redirect back to your app is signed in normal AAD.
I am not sure if this applies to B2C as well.

Correct Micro Service JWT flow

I am currently building out a micro service architecture and started with the auth server and client. I also wanted to confirm the best flow of authenticating a user with a token.
In the above image. Step 3 is were I start getting confused.
I thought of 2 solutions to the problem.
One every api passes the token to the auth server and waits to get approval that the token stored inside matches the db and it is still valid.
Two is to include a secret phrase in the JWT token and just have the API service parse and check for itself if the token is valid.(The secret phrase would be so that if a hacker tried to fake a token and it parsed to a valid id somehow the phrase would be off without the secret code used to encrypt the token. Which I don't even know if it is possible. If not then I guess 2 would be the best course of action)
A hacker cannot create a valid JWT token if he does not know the the signing key. If he somehow manages to get that signing key it is reasonable to assume that he is able to get your "secret phrase" also.
About the checking: JWT tokens can be checked by the API service as they contain all the information needed (except the signing key that must be known by the API service). The expiration can be checked here also. Anyway, you also need the information stored inside the token, like user ID. You should do this if you want better scalability.
The only reason why you would need to check a JWT token against a third Auth service is to see if it has been invalidated; for this you need a central service although you could replicate the list of invalid tokens to all the API services for better resilience.
You really don't have to forward the request to Auth-server to validate the JWT token. A JWT token is like a bill note, once it's signed it can be validated by anyone who is sharing the key.
I would recommend you to have an edge service in front of all your API-services. The edge service either shares the key by which JWT token is signed by Auth service or has the public key to verify the signature.
Once the signature is verified, the edge service can extract the required information from the token and add it to request header. Your downstream services can consume this information according to their need.
You can use Https to enforce that your request isn't intercepted by anyone over the network. In case, even if someone tries to mess up with the JWT token, the signature won't match and you can detect that. Please go through JWT/KONG: Cannot create JWTs with a shared secret to know more about creating-parsing the JWT token with public-private keys.

Secure API with OpenID Connect - RP trust of OP

Getting to grips with OpenID Connect with a third party IdP ( OP ) and securing APIs. I'm comfortable with the client and user agent component and the OAuth2.0 flows and scopes to get an access token and an id token issued to my client from an IdP
What I'm struggling with is the Resource Provider end and how the secured API trusts the access token that the client passes. I keep equating the trust element to SAML and the initial exchange of static configuration data between the IdP and the SP. That appears to be missing in OpenID Connect so I'm missing the trust element. I'm reading about dynamic discovery but again I'm missing a trick as to the trust between the RP and the IdP. What's to stop me setting up a rogue IdP ? Why should the API provider trust tokens coming from my IdP ?
Final question is on a local representation of the unique identifier in the RP. Does the account ID need to exist ahead of presentation of the access token ? I expect it does ( again using the SAML analogy which requires a local account representation ahead of authentication success ) so account management on the relying party is also a requirement for an end to end authentication to be successful.
Boils down to two questions. How does the API trust the access token presented ? Does the API provider need to have accounts provisioned ahead of successful authentication of those requests for resource ?
Thanks in advance.
Dynamic Client Registration is used exactly in cases where there is no pre-established trust between parties and one wants to allow any OP that has a valid certificate to play.
When you want to restrict the set of OPs, you'd statically register with those in advance, thus doing the same type of bootstrapping to create pre-established trust as in SAML.
A unique identifier can be created by the (<sub>,<iss>) tuple as found in the id_token that the RP receives.
For dynamic registration of the RP with the OP there is no trust metric described. There are two HTTP trust levels that can be enforced.
HTTPS is required with a certificate that chains up to the root of trust certs.
HTTPS has an EV certificate. This required in-proofing as defined by CAB.
I have proposed the use of a trust ecosystem in the IDESG, but that is some ways away.
It would be interesting to see if Kantara has any kind of solution in mind.
From an OpenID Connect perspective you are correct. That does not imply that any relying party code that you construct needs to be insecure. I mentioned two ways that you can verify the OP.
A similar set of security rules could be enforced by the OP, but as others have said, most OPs do not enable dynamic registration for this reason.
The id_token is a JWS signed JWT. It is signed by an OpenID Connect OP (IdP), generally using its private key. You MUST verify the signature so that you're sure you know the JWT/id_token emitter. After that it's up to you to decide if you can trust this emitter for the action the client is willing to achieve.
The id_token contains a claim (at_hash) which is a reference to the access_token, so that you're sure the access token was generated by the same OP.

OpenID Connect ID Token: What's the purpose of audience [aud] field validation

I'm trying to implement OpenID Connect Implicit Flow. The frontend Single Page App passes the ID Token down to the backend server (using Authorization header) where I need to validate it.
The documentation requires me to check that I trust the audience of the token (aud & azp fields). I'm struggling to understand the significance of this validation step and what are the security implications of not doing so. Why should I distrust the token if I'm not the intended recipient?
My reasoning is that if I trust the issuer it doesn't matter who was the token issued for. I would expect the claims to be the same for any clientId (is this wrong?). Ideally when I pass the ID Token around my microservices all they should know is what issuers to trust (and use discovery protocol for figuring out the keys).
What is the attack vector if I skip this validation step?
The issuer could be issuing tokens to different applications and those applications could have different permissions. Not checking the audience would allow an attacker to use a token issued for application A at application B and may lead to permission elevation.
To your suggestion: the claims may indeed differ per Client.
Here's another reason: If you check that aud claim only contains your client, it prevents other apps' stolen tokens from being used on your app. If a user's token gets stolen from another app, nobody will be able to impersonate the user on your app because the aud claim will not be correct.
I'm answering this for posterity.
You should check the issuer and if your client_id is the only one in the audience if you are receiving tokens from an external OpenId Provider. One that could have more than your client.
Claims are not global to the OpenID Provider, they can be per-client. A user can have "Admin" role on app-A, gets a token there, then tries to send app-B (your application) the same token hoping that your are not checking to which client it was issued for (its audience).

Do I need Federation Authentication if I have a custom STS? If so, why?

If I have a custom Secure Token Service that specifically lists out allowed audiences and checks if the token is coming from one of of those audiences and also checks the thumbprint and issuer of the X509 certificate, do I need WSFederation?
Since my STS is checking that the the token already came from a specific application and was routed through my ACS, aren't I verifying all of the things I need to? I know that Application A sent a request to the ACS which sent a request to Application B all from the custom STS, so where does Federated Identity fit in this picture?
Edit for clarity:
Sorry I was a bit unclear in the orignal post. I think the confusion came because I used STS instead of security token handler (Way different things, just a typo).
Application A is a custom login service, which displays the login options for the user, google/facebook/yahoo/etc. Logging in through these service gets the token from the ACS and returns it to application B, the Relying Party. This RP has a custom security token handler which accepts the token and validates that it is has an audience URI matching application A. It also validates that the issuer was the ACS and the thumbprint matches the one of the cert used to sign the token via the ACS.
This means that theoretically application B knows, that application A was used to login (as it came from that audienceURI) and that the ACS sent the token (as it was the issuer and the thumbprint matches). What I am asking is if federated identity is necessary for application B? What exactly do you gain by using it, if you've already proved where the token came from?
your question might need some clarification.
First, you might want to explain specifically what you mean by application A and application B, and how your STS fits in this scenario. Applications don't typically issue tokens, only STSes do. In this sense, ACS doesn't connect applications to each other, it connects relying party applications to third party identity providers.
Second, if you're talking about authentication over the web, and you have a custom identity provider STS that's issuing tokens for ACS, then you're probably already using WS-Federation. If however your token acquisition is not browser based, and you're making back-end HTTP calls to ACS, then WS-Federation is not relevant to the scenario.
Third, from the point of view of the STS, the set of allowed audiences is not about token issuers, it refers to entities that will consume tokens issued by that STS. That is, it's the set of subjects that the STS will issue tokens to. This could be applications themselves, or other intermediary STSes along the federation chain. (ACS for example acts as such an intermediary)
Fourth, when you're validating the issuer's certificate on an incoming token, you must do more than just compare the thumbprint. The thumbprint is not part of the token's cryptographic proof. You must validate the token's digital signature in order to verify that the token issuer owns the private key of the certificate.
I hope this clears things up, but if it doesn't answer your question please let me know.

Resources