I'd like to provide two ways to authenticate in my application, one is basic auth (users), and the other is some kind of token based (technical users). I understand that I need a custom ReactiveAuthenticationManager but I can't find clues on the big picture. (Actually, there are a very few insights for MVC, and none for WebFlux.)
1) How do I populate the Authentication's name and credentials in the token based approach? If I configure Spring Security to use httpBasic it's already populated. Some kind of filter needed?
2) How do I distinguish in the authentication manager where the credentials are coming from? Do I have to lookup in the userRepository and (if not found) in the technicalUserRepository too?
3) Do I have to override the SecurityContextRepository? All the tutorials do it but I don't see any reason to do so. What is it exactly? This source states that "SecurityContextRepository is similar to userDetailsService provided in regular spring security that compares the username and password of the user." but I think he means ReactiveUserDetailsService (neither UserDetailsService nor ReactiveUserDetailsService does that by the way, it's just for user lookup).
Since i am decent at Webflux and i have worked a lot with oauth2 i'll try and answer some of your questions.
1) How do I populate the Authentication's name and credentials in the
token based approach? If I configure Spring Security to use httpBasic
it's already populated. Some kind of filter needed?
A token never contains credentials. A token is something you get issued after an authentication has been done. So usually you authenticate against an issuing service. After you have authenticated yourself against that service you will be issued a token.
If its an oauth2 token the token itself is just a random string. It contains no data about the user itself. When this token is sent (using the appropriate header) to a service using spring security. Spring security has a token filter that will basically check that the token is valid, usually by sending the token to the issuer and asking "is this token valid?".
If using a jwt, its different, the jwt must contain some information like issuer, scopes, subject etc. etc. but its basically the same thing, there is a built in filter that will validate the jwt by sending it to the issuer (or using a jwk that the service fetches from the issuer so it can verify the integrity of the jwt without doing an extra request).
2) How do I distinguish in the authentication manager where the credentials are coming from? Do I have to lookup in the userRepository and (if not found) in the technicalUserRepository too?
You don't You usually define multiple SecurityWebFilterChains for different url paths. I have not done this in Webflux Spring Security, but thats how you do it in regular Spring Applications, and i don't see any difference here. Unless you are doing something crazy custom.
3) Do I have to override the SecurityContextRepository? All the tutorials do it but I don't see any reason to do so. What is it exactly? This source states that "SecurityContextRepository is similar to userDetailsService provided in regular spring security that compares the username and password of the user." but I think he means ReactiveUserDetailsService (neither UserDetailsService nor ReactiveUserDetailsService does that by the way, it's just for user lookup).
The answer here is probably no. You see Spring security 4 had very bad support for oauth2 and especially JWT. So people got accustomed to writing their own JWT parsers. When spring Security 5 came, Spring implemented a jwt filter that you can configure and use built in. But there are a lot of outdated Spring Security tutorials out there and foremost there are a lot of developers that don't read the official documentation.
They mostly google tutorials and get the wrong information and then work on that.
But easy explained:
SecurityContextRepository
If you have session based authentication (server establishes a session with a client) it will store the SecurityContext (session) in ThreadLocal during a request. But as soon as the request ends, the session will go lost unless we store it somewhere. The SecurityContextPersistenceFilter will use the SecurityContextRepository to extract the session from ThreadLocal and store it, most common is to store it in the HttpSession.
AuthenticationManager
Override this if you want to do a custom authentication process. Example if you want to validate something, call a custom LDAP, database, etc etc. It\s here you perform you authentication. But remember, most standard logins (like ldap, sql-servers, basic login etc.) already have prebuilt configurable managers implemented, when you select what login type like .httpBasic() you will get a pre-implemented AuthenticationManager.
UserDetailsManager
You override this when you want create a custom UserDetails object (also usually called Principal) In the UserDetailsManager you do you database lookup and fetch the user and then build and return a UserDetails object.
Those two interfaces are the most regular custom implementations, and are used if you need to to basic authentication/session based authentication.
If you wish to do token, you have to think about, who is the token issuer? usually the issuer is separate and all services just get tokens and validate them against the issuer.
I hope this explains some of the questions. I have written this on the bus so some things are probably wrong and not 100% correct etc. etc.
Question
If you would use a similar setup as the following examples:
Simple WebAPI
Javascript OIDCClient and usermanager
Would it be possible to protect other clientside files from being accessed? Say for example i have a directory with certain files which you need a certain role to be able to access them.
Would it be possible to protect my SPA from being accessed before logging in?
Or is there a better solution which would have you end up with a protected api, folders/files on a server, SPA and a silent renew mechanism like there is in the OIDCClient?
#dmccaffery helped me out by answering my question, here is his answer for those of you who are interested.
To summarize using the OIDCClient for an SPA is certainly the way to go. Exposing stuff which needs authorization should be done by using an API. Protecting parts of your Angular App can be done using a Route guard.
The way it works is as follows:
The access token is either a JWT or a bearer token (usually) and is
added by the oidc client to every HTTP request in an authorization
header — when a web API receives a reques, the bearer token
authorization middleware will parse this HTTP header and will call the
token introspection endpoint (and potentially the user info endpoint)
to have the token validated and the users claims retrieved… if the
token was manipulated by the client, it will not be valid, and an HTTP
error will be returned (usually a 403). If the token was valid, a
claims identity is created and assigned to the http request context.
The API will now have a thread with an identity already assigned to it
that represents that user.
Also he pointed out 2 pluralsight courses which would probably be useful:
https://www.pluralsight.com/courses/building-securing-restful-api-aspdotnet
https://www.pluralsight.com/courses/oauth2-openid-connect-angular-aspdotnet
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 built a simple Spring Boot application that acts as an OAuth 2.0 client using the #EnableOAuth2Client annotation. My application is creating an OAuth2RestTemplate and the OAuth dance succeeds nicely.
The problem is that when I access my application e.g. at http://localhost:8080/someRequest (where the method serving this resource uses the OAuth2RestTemplate#getObject method to retrieve some remote resources, I end up with sth. like http://localhost:8080/someRequest?code=ABC&state=DEF in my browser.
Is there a way to get rid of these parameters using some Spring configuration magic or do I have to do that myself? I saw that the sample Tonr application suffers from the same problem.
The issue is that you have to handle the callback url that u have registered with OAuth2 provider. when you transfer code and state parameter to the provider Server for access token and refresh token, the provider sends request back to ur callback URL with access token. In callback URL u now have to check if access token is available, you redirect to the original request(u need to save original request before OAuth2 dance).
I know this stuff theoretically, but didnot find Spring-Security-OAuth2 example for handling the callback URL.
I asked same question, but didnot get any answer.
OAuth2 Dance With Spring Security
However without using spring security, i found one link which shows handling callback url manually.It will help u in understanding the flow.
Google Handle callback URl
If u found any example of spring secrity handling callback url , Share with me.
I found this as an issue with spring security oAuth2. Check this JIRA Issue
I'm trying to find the simplest way of implementing token based authentication for a number of ASP.NET MVC actions.
The Api controllers sit alongside a web app, so I need to be able to specify which actions/controllers are subject to Api authentication.
I already have a membership provider that is used for forms authentication so I'd like to reuse this to validate the user and build the returned token.
I've read several articles on implementing OAuth, but most seem really complex. I've seen several examples of using an API key, but I want to request a token and then pass it back as a parameter not necessarily as a value in the HTTP header.
Essentially process needs to be:
User requests token from auth action passing in username and
password.
Service returns enc token
User passes enc token to future calls as a parameter to auth
What's the typical way this is done, does the client (say ajax call) need to compute a hash of the user name/pass in 1)? or plain text ok over TLS/SSL?
Any advice appreciated.
What are you concerned about with what you described?
The process you described seems viable. Typically systems will have an expiration on how long the token will be valid for, after which they need to get a new token. There are many variations for expiration though (fixed time, sliding time, etc..).
To your question regarding the username / password, the client shouldn't hash them. Just make sure they are transmitted via a secure method (SSL).