I have an angular application using the authorization code grant, with the oidc library I added a custom parameter. I am able to get it value with IIdentityServerInteractionService in the controller (customerId = 123).
I am trying to add some claims based in the customerId in the Profile service, but I am not able to get that custom parameter in the ProfileDataRequest,
Does anyone know if I am missing something or has any direction.
I am working with an MVC5 application which is secured by the WsFederationAuthentication and CookieAuthentication OWIN components. As part of the login process, I inject some additional claims into the ClaimsIdentity returned from the SAML provider (ADFS in this case) during the OnResponseSignIn delegate of a CookieAuthenticationProvider supplied when I set CookieAuthenticationOptions during Startup. That allows me to manipulate the ClaimsIdentity in the OwinContext before it's used to generate the ticket. In practice, this works great for what I've needed to do in the past (mostly add custom claims depending upon values found in a database matched with data supplied from the incoming claim).
However, dependent upon circumstances that arise when OnResponseSignIn is executed, I now need to be able to reject the login in such a way that I can display an error to the user indicating why it's not possible for them to log in. This is proving to be much trickier than I had imagined.
These are the two main approaches I've tried:
Throw an exception in CookieAuthenticationProvider.OnResponseSignIn:
This works in that the authentication cookie is never set and my global error handler catches the exception and displays it to the user. However, I can't determine a way to effectively reject the identity before throwing the exception. So, my global error handler believes that the HttpContext is authenticated and renders the error view with elements that should not be rendered if the user is not authenticated. Nulling the OwinContext.Identity inside OnResponseSignIn does not have an effect as all I'm doing is clearing a value inside the OnResponseSignInContext which has no effect on the overall pipeline. So far as I'm aware, I can't mark the actual ClaimsIdentity itself as not authenticated as IsAuthenticated is set to true when you set the authentication type in the ClaimsIdentity ctor and can't be modified after that.
Add an "error" claim in CookieAuthenticationProvider.OnResponseSignIn as a bread crumb and then look for it in CookieAuthenticationProvider.OnValidateIdentity and throw the exception there.
This approach has the benefit of being able to clear the login (a benefit afforded by OnValidateIdentityContext.RejectIdentity()). So, now my error view renders correctly for an unauthenticated user. However, the problem here is that I can't figure out a way to prevent the authentication cookie created after OnResponseSignIn from being emitted to the client and set in the browser. The tools I have available in either of these delegates allow me to append and delete cookies from the OwinContext, but somehow this cookie is not one that I can do that with. It appears to be actually added to the response stream later in the pipeline where I can't change it. So, if I let OnResponseSignIn complete and then look for the cookie during the execution of OnResponseSignedIn, I don't see it there. Really not sure why that is -- looking at the source of CookieAuthenticationHandler, it looks as thought I should see it as it's added in between the execution of those two CookieAuthenticationProvider delegates. I also can't prevent the cookie from being generated in the first place as the CookieAuthenticationHandler will throw an exception if the ticket can't be serialized.
So, I either can get no cookie set and an as-if-authenticated error view or get an unauthenticated error view, but have a cookie set that effectively prevents the user from trying to sign in again.
Ultimately, I'm rolling around in the mud of the framework enough at this point that I feel like I must be approaching the problem incorrectly. What I'm looking for is an answer to this question:
How can I reject an otherwise valid WsFederation authentication postback and display an error to a user that explains what happened without emitting an AuthenticationTicket to the client?
I'm guessing there must be another point in the process (perhaps not in CookieAuthenticationProvider) where this can be done before the pipeline decides that authentication has succeeded.
Probably you use something like this in your Startup code:
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions())
The class WsFederationAuthenticationOptions provides the possibility to hook into the wsfed authentication (like the CookieAuthenticationProvider for the cookie authentication). You can set the Notifications property to a new instance of WsFederationAuthenticationNotifications. I recommend to use the SecurityTokenValidated property and set it to your implementation i.e. a new method matching the required Func<> definition. This is the point after the token passed validation and a ClaimsIdentity has been generated. Then you can do your additional checks and set the AuthenticationTicket of the methods parameter SecurityTokenValidatedNotification to null and modify the HttpResponse. Than the CookieAuthenticationHandler should not be triggered.
I'm responsible for the API side of our product. We have several different clients, from browsers to iPads to Chromebooks. Right now, all our authentication is done directly from the client to our API, with username & password.
I've inherited some code that does authentication using OAuth, with the usual username/password setup. So inside my OwinAuthConfig class, I have:
var oAuthAuthorizationOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Authenticate"),
Provider = new MyAuthorizationProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthAuthorizationOptions);
Then, through some dark magic, this connects up with my MyAuthorizationProvider class (which inherits OAuthAuthorizationServerProvider), and on login, this invokes the method:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{ ... }
where context contains the important stuff (Username and Password) which I can then use to authenticate the user, build his claims, create an AuthenticationTicket and this information then magically gets returned to the client with the access token etc.
All well and good.
Now I have a new requirement - to allow 3rd party authentication from Google. In this case, the client app (iOS/Android/whatever) does the authentication with Google, and they should just pass the token (and any other required info) to me on the API side. On my side I then need to re-authenticate the Google token, and get all the user info from Google (email, name, etc.), from which I should then again link that to our User table, build up the claims etc. and return a new token to the client, which will be used in all subsequent calls.
Being kinda new to the whole OWIN pipeline thing, I'm not sure exactly how to go about this. I could write a new GoogleAuthController, that just acts like any other controller, and have an API that accepts the Google token, and returns the new token and other info in the same format that the username/password authentication API does it. But 2 things are nagging at me:
I have this awkward feeling like this is the noobie way of doing things, reinventing the wheel, and really there's a super-cool magical way of hooking things together that I should rather be using; and
In MyAuthorizationProvider.GrantResourceOwnerCredentials(), I've got access to an OAuthGrantResourceOwnerCredentialsContext object, which allows me to validate my new AuthenticationTicket. If I'm doing this inside a plain vanilla controller, I have no idea how I would mark that ticket as validated.
Any clues, please?
EDIT I've seen the Google auth flow as described here. I'm still confused by how best to manage the process from the API side. The client will be obtaining the authorization code, and then calling the API with that auth code. I get that then I've got to take that auth code and convert it to a token by calling the Google API. (Or maybe that should be the client's responsibility?) Either way, I then need to use that token to go back to the Google API and get the user's name, email and avatar image, then I need to match up that email with my own database to identify the user and build up their claims. Then I need to return a new token that the client can use to connect to me going forward.
Let me be more specific about my questions, before my question is closed as "too broad":
When the client has completed authentication with the Google API, it gets back a "code". That code still needs to be converted into a token. Whose responsibility should that be - the client or the API? (I'm leaning towards making it the client's responsibility, if just for the reason of distributing the workload better.)
Whether the client is passing through a code or a token, I need to be able to receive it in the API. Should I just use a plain vanilla Controller to receive it, with an endpoint returning an object of type AuthenticationProperties, or is there some special OWIN way of doing this?
If I'm using a plain vanilla Controller, how do I validate my token? In other words, how do I get access to the OWIN context so that I can mark the AuthenticationTicket as validated?
How do I write an automated test that simulates the client side of the process? AFAICT, the authentication wants to have a user physically click on the "Allow" button to grant my app access to their identity stuff, before it will generate the auth code. In an automated test, I would want to pass username/password etc. all from code. How do you do that?
So I found a solution of my own. It's only slightly kludgy, doesn't require referencing any Google OWIN libraries, and best of all, reuses the code from my username/password authentication.
Firstly, I get the app to call the same Authenticate endpoint as I do for username/password, only with dummy credentials, and add in a "GoogleToken" header, containing the token.
In my authentication code, I check for the GoogleToken header, and if it exists, follow that code path to validate on the Google servers, get an email address, and link to my own User table. Then the rest of the process for building claims and returning a new API token follows the original path.
start here : https://developers.google.com/identity/protocols/OAuth2#basicsteps
This explains how oAuth2 works. So you receive a Google token, now you call Google and request the user's details. you will receive their email which is enough to authenticate them. You could store the token as they are valid for a while and you can keep reusing it for whatever you need until it expires or it is invalidated.
Check this discussion on the same subject :
How can I verify a Google authentication API access token?
if you need more info on how OAuth2 works I can point you to one of my own articles : https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
There's a lot to take in, but it sounds like you need to understand how these things work together. Hope this helps.
Update:
I don't have full access to your setup, but I hope that the following code might help you with using Google as ID provider. Please add the following code to your startup.auth.cs file.
var googleAuthOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "ef4ob24ttbgmt2o8eikgg.apps.googleusercontent.com",
ClientSecret = "DAK0qzDasdfasasdfsadwerhNjb-",
Scope = { "openid", "profile", "email" },
Provider = new GoogleOAuth2AuthenticationProvider
{
OnAuthenticated = async ctx =>
{
//You can get the claims like this and add them to authentication
var tokenClaim = new Claim("GoogleAccessToken", ctx.AccessToken);
var emailClaim = new Claim("email", ctx.Email);
var claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(tokenClaim);
claimsIdentity.AddClaim(emailClaim);
HttpContext.Current
.GetOwinContext()
.Authentication
.SignIn(claimsIdentity);
await Task.CompletedTask;
}
},
AuthenticationType = "Google"
};
app.UseGoogleAuthentication(googleAuthOptions);
This allows the Google to act as ID Provider and the OnAuthenticated gets called when the authentication is successful. You can get the claims out of it and use them to signin. Please let me know if this worked, if not give me more details about your setup (what kind of framework, client setup and may be more details about your setup in startup file).
Thank you.
Please see this link for details on how we can use Google as ID Provider. I am sure you might have looked at this link, but in case you missed it. If none of these links work for you please include specific details on where you are deviating from what is mentioned in the links.
I assume you have a different requirement than what is specified in those links. Hence, I will try to answer your questions individually. Please let me know if you have any further questions.
When the client has completed authentication with the Google API, it gets back a "code". That code still needs to be converted into a token. Whose responsibility should that be - the client or the API? (I'm leaning towards making it the client's responsibility, if just for the reason of distributing the workload better.)
Exchanging the code for access token is definitely the responsibility of the API as the token exchange involves sending the ClientId and Client Secret along with the code. Client secret is supposed to be saved on the server side (API) but not on the client
Whether the client is passing through a code or a token, I need to be able to receive it in the API. Should I just use a plain vanilla Controller to receive it, with an endpoint returning an object of type AuthenticationProperties, or is there some special OWIN way of doing this?
This should work seamlessly if you are using the Google provider as mentioned in the above links. If not, the endpoint should be an anonymous endpoint accepting the code and making a request to Google (may be by using HttpClient) to get the access token along with the profile object for user related information.
If I'm using a plain vanilla Controller, how do I validate my token? In other words, how do I get access to the OWIN context so that I can mark the AuthenticationTicket as validated?
You have to implement OnGrantAuthorizationCode as part of your MyAuthorizationProvider class. This gives access to the context to set validated to true.
How do I write an automated test that simulates the client side of the process? AFAICT, the authentication wants to have a user physically click on the "Allow" button to grant my app access to their identity stuff, before it will generate the auth code. In an automated test, I would want to pass username/password etc. all from code. How do you do that?
This can be achieved partially, but, with that partial test you can be sure of good test coverage against your code. So, you have to mock the call to the Google API and assume that you have retrieved a valid response (hard code the response you received from a valid manual test). Now test your code on how it behaves with the valid response. Mock the Google API cal for an invalid response and do the same. This is how we are testing our API now. This assumes that Google API is working fine and tests my code for both valid/ in-valid responses.
Thank you,
Soma.
Having gone through something like this recently, I'll try to answer at least some of your questions:
The client should be getting a token from Google, which you can pass unaltered through to the API:
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var idToken = googleUser.getAuthResponse().id_token;
}
A plain vanilla Controller should do it. The client can subsequently post an object in there, containing at least that token plus the client id (might be useful to know where the request comes from) and even the providerUserId;
Unfortunately I'm not that familiar with the Owin stack
Fully end-to-end integration testing might be tricky, although you might achieve something through tools like Selenium, or some mocking tool. The API however should be testable just by posting some fake data to that vanilla controller, although you might have to rely on some sort of mock implementation when you get to validating that token through Google (although you could also validate it manually on the server, provided you get the Google public api key).
I have created an authentication server that implements OAuth 2 for authorization and it also provides local password authentication using the resource owner flow.
At the moment I always return a refresh token along with the access token which was an acceptable thing to do when I first implemented the feature. However now I need to implement a remember me feature in the client that uses the server. I could always just save the refresh token in the client when the user ticks the remember me checkbox but the token would still exist on the server and be usable even though the user didn't want it to.
What I want to do is simply pass a parameter along with the request that tells me whether I should create a refresh token or not.
So my question is. Is there some standard or recommended way of doing this using the fields provided in the spec or is it acceptable to simply add a parameter to the request to handle this use case?
AFAIK, there is no standardized way to choose whether to issue a refresh token or not.
I am using WIF 4.5 to authenticate my user and need to use the Security Token from the WIF 4.5 authentication to call a REST API.
Here is the code I am using to get the IMS Security Token for the currently logged in user.
BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
var myToken = bootstrapContext.SecurityToken;
So, far, so good. The token exists and has the Id, ValidFrom, and ValidTo values. The Security Keys count is zero, but I am not sure if that is relevant.
Now, I need to know how to use this token to then call the REST API.
It seems like I am supposed to use the JWT Handler for this:
https://blogs.msdn.microsoft.com/vbertocci/2012/11/20/introducing-the-developer-preview-of-the-json-web-token-handler-for-the-microsoft-net-framework-4-5/
But, I am having problems getting this to work. The code on the linked to page above actually does not compile as is. Some of the properties have been changed/renamed.