I am trying to add a basic authentication security layer over a REST service that I developed using Spring boot 4.3.
I have essentially did two main things:
Implement UserDetailsService interface to provide user details. Here I read from a text file the usernames and the encoded (via Bcrypt) passwords.
I declare a bean as follows in my #EnableWebSecurity annotated security configuration class:
#Bean
public BCryptPasswordEncoder getPasswordEncoder () {
return new BCryptPasswordEncoder();
}
to return the specific password encoder.
I am testing the authentication using rest clients both ARC (for Chrome) and REST Client of Firefox.
The issue is as follows:
When I enter my credentials for the first time and upon successful authentication, the response is 200 OK. This is true for a bunch of users. In other words, as long as I supply correct pair of credentials I get a 200 response.
But, after a single request with incorrect credentials the authentication process breaks down. Sometimes I get 200 and other times a 401 even for correct credentials. Other users authentication is affected as well, at this point of time.
There is a curious log that appears at step 2:
WARN 6813 BCryptPasswordEncoder : Empty encoded password
To elaborate a bit on the hashing of the passwords, I ran the Bcrypt password encoder utility and encoded a bunch of passwords and saved them manually in a text file for the corresponding user names.
I am unsure where the issue lies: whether the clients caching the credentials or the Spring security context caching the incorrect principal or the user details service breaking down (no such exception in the logs though).
Any help is appreciated. If you need any further specific information, please do let me know.
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).
Consider the following scenario:
On MVC 5 (or higher), you have enabled 3rd party authentication (e.g. Facebook, Google).
As part of the authentication process, we want to perform an additional operation with the 3rd party authentication provider -- e.g. Facebook check if the logging-in user has liked a particular page, or if the user's email address is pre-approved/white-listed somewhere.
The cycle of events seems like it should be:
1. Authenticate user via external service (e.g. get user-id/email and 3rd party uniqueID)
2. Use 3rd party uniqueID (e.g. Facebook Id #) to perform queries to get some information about the user
3. If the user matches some criteria, sign-in user; if not return to login screen
To me, it seems like there should be a method we can override in the the authentication process like this that would do the trick:
(This hypothetical example of what I'm looking for covers checking the property of the user in the normal login-in cycle -- we'll get to doing additional 3rd party querying in a second).
override Boolean BeforeReturnSignedInUser(AppUser user){
if (whitelistedUsers.Email.Contains(user.email)){
return true;
}
else {
return false;
}
Similarly, it seems like there should be a way to access the 3rd party accessToken fairly easily to perform additional logic against the 3rd party social media graph, but it seems like, according to this, not: MVC 5 Web API with Facebook access token to RegisterExternal without need of Cookie
(On the other hand, this is more encouraging: How to access Facebook private information by using ASP.NET Identity (OWIN)? but still requires adding a lot of artifacts for what should be a pretty simple operation)
In any event, neither of these examples seem clean -- seems like adding a lot of complexity to do an additional check that is all of 5 lines of code!
The MVC way to do this is to configure the facebook middleware to grab the info you want in the ConfigureAuth method in Startup.Auth.cs (I'm looking at the MVC5 project template), then add any custom claims you want in IdentityModels.cs (it even has a comment // Add custom user claims here). This avoids clashes that would occur if you try to add claims elsewhere.
For my company, I have to make a POC to check if we can use wsFederation authentication for our project, which has a MVC app, some webapi controllers, and some signalR hubs, all in differents projects.
We'd also like to use the OWIN authentication middleware in both the client apps and the Identity provider app.
I use Thinktecture Identity Server v2 as the Identity provider for a start (but we'll have to develop ou own at some point).
For the MVC app, it's pretty straight forward and it works fine, using a SAML2 token.
But now things get a bit more complicated as I'd like an authenticated user on the web app to be able to call a controller method from the web api app (which is different of the MVC one, remember), using ajax calls.
I've read many things about delegating and actAs tokens, but I'm a bit lost and don't where or how to start this part. Also, i can't find anything about delegation using OWIN authentication.
So my first question is : is it possible to achieve this ?
And then : could someone point me in the right direction?
I followed Vittorio Bertocci's instructions when I was working on it.
http://www.cloudidentity.com/blog/2013/01/09/using-the-jwt-handler-for-implementing-poor-man-s-delegation-actas/
A couple of notes about it, where it says JWTSecurityTokenHandler, it is now JwtSecurityTokenHandler. It is a small typo, but it is a good way to loose 15 minutes if you are not aware of it.
I was also not able to use the X509 FindByThumbprint section either. I think that I did not have my local certificate registered properly. Once I am at work tomorrow I will post what I had to change in order to get it to work.
Dominick Baier (http://leastprivilege.com/) also does a course on pluralsight called WebApi v2 Security that does a great job talking about how to inject into the security pipeline and setting up the web api project to handle this.
As another option, you could replace the TokenValidationHandler class that Vittorio uses with the Microsoft.Owin.Security.Jwt package and implement the following code in the Startup.cs file.
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { ConfigurationSettings.AppSettings["ida:Realm"] },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(
ConfigurationSettings.AppSettings["ida:ValidIssuer"],
ConfigurationSettings.AppSettings["ida:SymmetricKey"])
},
Provider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = context =>
{
var identity = context.Ticket.Identity;
return System.Threading.Tasks.Task.FromResult<object>(null);
}
}
});
I've been reading quite a few questions here on SO about securing web api's using api keys, tokens, hmac ect and haven't found the answer I am looking for.
I'm working on a MVC4 web application project with internet and intranet sites, web api and Android/iOS applications.
The Web API is to be used by my applications and nobody else as it will be accessing sensitive data.
What would be the best way of securing this api so only my apps can use it? Something that seems like such a simple request is extremely difficult to get started on.
I've looked at the post here on SO using HMAC and a few others but none of them sounded like they would fit here, more than likely I am just missing something.
Is HMAC the way to go or would client certificates be more appropriate for this situation?
Should I use SSL and some sort of API key?
I know the question is a bit vague, I've been staring at it for over an hour trying to figure out how to word what I am thinking so I figured I would just post it and update if needed... :(
I would be more than happy to provide more details upon request.
Generate a key for each of your apps and have them pass the key in each request as a token. Your server can then verify the key and authenticate the request.
Take a look at the Basic Authentication module from the ASP.NET site. The sample uses 'basic' as the authorization scheme but you can change it use 'token' instead.
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("token",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
AuthenticateUser(authHeaderVal.Parameter);
}
}
}
Once you have the Basic Auth module in place you can simply decorate any actions or controllers with the Authorize attribute and it will forward the request to the Basic Auth handlers.
namespace webapi.Controllers
{
[Authorize]
public class SensitiveDataController : ApiController
{
...
}
}
As far as over the wire you MUST use SSL when using basic authentication as your key will be transmitted in plain text.
You can use FormsAuthentication. Encrypt the ticket and ensure machineKey is the same in both the config files. See this and this. This will allow the same user credentials to be shared between web app and api. ASP.NET FAM module will establish the identity in this case.
For api key, look at hawk scheme. It uses shared symmetric key. However, Hawk is feature-complete and until it reaches version 1.0 it is likely to change. Nonetheless, it will give you a good idea of implementing HMAC-based security. I have a .NET implementation here for Hawk. And there is one from Pablo as well. In this case, you will need to write a message handler to establish the identity for the consuming application.
In a general case for a high traffic app, all the above answer have a flaw that many attackers can easily exploit:
With a jail broken iPhone, you can break SSL - not to your server, but when they have your app on their phone, they can at least analyse the packages you send.
The best way to avoid that (in my opinion) is using 'on time passwords' - real on time passwords.
How can you generate these one time passwords?
A1. Get a device_identifier for each device (this could also just be any random number, but you should avoid collisions with other devices' identifiers)
A2. Have an api_key, that you will use for hashing
Now if you want to send a package to your api, you do the following:
B1. Construct your normal package, here is the example of some json payload:
var payload = {"hello":"world"}
B2. Hash your var hashed_payload = hash(payload) using your favourite hashing function
B3. Generate the one time password for this package:
var otp = hash(salt & hashed_payload & device_token & api_key)
Now you have everything you need, to send to the server:
In the headers, you need to send the otp,salt and device_token as well!
On the server, you will do the same steps marked as B1-3 and compare your hashing result with the one provided by the client. After that you have to make sure that you 'ban' this salt for this device_token in order to avoid replay attacks.
This method still has one flaw but requires much more work from attackers:
They can find your api_key in you compiled code.
I'm working on a similar project where I assign unique API keys to each user or client application accessing my API. I'm not a security expert, but I'd recommend that you use SSL and generate unique API keys for both your Android and iOS applications. With SSL, data being transmitted to your API will be encrypted and protected.