Securing API using OIDC Resoource server - asp.net-core

I have 2 .NET solutions: a webapp, an API.
When user browses the webapp he needs to be authenticated and thus facing this:
return builder.AddOpenIdConnect("contonso", options =>
{
options.Authority = configuration["Contonso:Oidc:Authority"];
options.ClientId = configuration["Contonso:Oidc:ClientId"];
options.ClientSecret = configuration["Contonso:Oidc:ClientSecret"];
options.ResponseType = OpenIdConnectResponseType.Code;
options.ProtocolValidator.RequireState = true;
options.UsePkce = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
}
Which works finely as I get all infos : code, token, id_token once user authenticated.
I copied code above into my API and changed clientId/clientSecret to point to my resource server.
From my webapp I call the API adding an Authorization : Bearer token (received previously).
However in API solution, I get redirected each time to the login page, whatever I pass in my authorization header.
Do I need to change something in my API code in order to make the token "transit" to the resource server and just validate token received?
Cheers,

APIs behave differently to web back ends. The API should never redirect the client and should just validate JWT access tokens instead:
Return a 200 error when the JWT is valid
Return a 401 error when it is not
You use different .Net middleware in the API, by calling AddJwtBearer. Here is a Curity code example that does this.
The main thing is to implement the standards based behaviour, which will then work with any programming language and Authorization Server.
API CODE
There are two main approaches to API JWT validation, and you are using the first type:
Use a JWT framework (such as ASP.Net Core)
Use a JWT library
When you are new to securing APIs using OAuth, it can be useful to understand what code looks like for the library approach, as in this class of mine, which shows the steps an API should use:
Download the token signing public key from the Authorization Server
Give the public key to a library, which will then cryptographically validate the JWT
Also check the issuer, audience and algorithm are as expected
.Net Core will do this for you automatically though, so use the Curity code example approach, since you will write less code.

As always RTFM was the good way. I needed to call the introspection endpoint to validate my token. Explained here also : https://connect2id.com/products/server/docs/api/token-introspection
I then used a Nuget package doing that and it works fine.
Anyways thanks for your help and lightning Gary :)

Related

Using Google OAuth to secure web services in aspnet core

I'm getting lost in OAuth and OpenIDConnect and aspnet core middleware. Any help on this would be appreciated.
I have multiple UIs (web, native apps) that use the same set of web services, and I'd like to ensure only authenticated users can access the web services. My organization uses Google accounts, so I'd like to use Google authentication restricted to the organization domain.
The web site is properly requiring authentication, following this sample. What I need now is to have the web site (AngularJS 4) invoke my back end web services with an auth token that I can verify with Google.
The back end services are written with aspnet core. I've tried using these approaches: Google middleware and Google OpenIDConnect but these still 1) assume there is a UI that can prompt an unauthorized user to log in, and 2) appear to be cookie-based, and I won't have cookies for the web service calls.
I don't want to prompt the user to log in, since the "user" in this case is a software client. Either they're authenticated or not already. I just need to get the authentication token, validate it, and carry on.
This appears to be the same question, which hasn't been answered yet, either.
Any suggestions are appreciated. Also, suggestions or tips on having native apps do the same!
Got it working. As mentioned, I was getting lost, and the OpenIDConnect, though referenced in several areas as a solution, was a red herring for the web services. Here's what is working for me now, with as complete steps as I can provide (some cleanup required):
Add authentication to the UI following these directions
Obtain the JWT token as shown in the first segment here
On each web service call, include the JWT token in the headers:
Name: Authentication
Value: Bearer {token value}
Install the JwtBearer NuGet package
In the ConfigureServices method of Startup in the web service, after you AddMvc():
services.AddAuthorization(options =>
{ // this policy needed only if you want to restrict to accounts within your domain. otherwise, don't use options. or use whatever options work for you.
options.AddPolicy("hd",
policy => policy.RequireAssertion(context =>
context.User.HasClaim(c =>
c.Type == "hd" &&
("https://accounts.google.com".Equals(c.Issuer) ||
"accounts.google.com".Equals(c.Issuer, StringComparison.CurrentCultureIgnoreCase)) &&
c.Value == "yourdomain.com"
)));
});
In the Configure method, before you UseMvc():
JwtBearerOptions jwtOptions = new JwtBearerOptions();
jwtOptions.Audience = "{the OAuth 2.0 client ID credential from google api developer console}";
jwtOptions.Authority = "https://accounts.google.com";
jwtOptions.TokenValidationParameters = new TokenValidationParameters();
jwtOptions.TokenValidationParameters.ValidIssuers = new List<string>()
{
"https://accounts.google.com",
"accounts.google.com"
};
app.UseJwtBearerAuthentication(jwtOptions);
Perhaps there is a more appropriate way to do this...if there is, I'm interested in trying it out. For now, this is working.
I will try to help.
First you need to look at OpenID Connect (which is built on top of OAuth 2.0) remembering that OAuth 2.0 NOT an Authentication protocol.
1) assume there is a UI
No UI is required for login assuming you are using Google services. You only need to check for the existence of and validate the Access Token, Identity Token (and perhaps the refresh token). If there is no Token, assume the user is NOT Authenticated and redirect them to the Authentication Server with a Authorization Request.
If there is a valid Access Token and Refresh Token, then you can assume the user is Authenticated.
You can also inspect the Access Token for proper "Scopes" to determine if they are Authorized for your specific application.
If you are using Google for Authorization Server, you can validate the the hd parameter within Identity Token has the desired Domain.
BTW: No cookies involved.
Hope that helps.

Dotnet core security oauth and bearer

I'm trying to secure a small dot net core mvc and api application and I've gotten turned around and need a little direction.
I've got to use ADFS 3.0 Server2012 R2 as the source of login/password.
I have to use versioning in the API. (Microsft.aspnetcore.mvc.versioning)
I don't want to send a login/password to API, just a bearer token.
I configured cookieauthentication and OAuth against the ADFS endpoint and it works fine for the mvc ui, but I don't know how/what to do to get the API to work with httpclient from the mvc ui controller to the API.
Long ago I used IdentityServer 1 or maybe 2 and used bearer tokens but I couldn't figure out how to create a token in the OnCreatingTicket in the OAuth event and not sure where to store it. I tried a claim, but it didn't work so it might be malformed or simply wrong.
I am unsure if my issue warrants using something like IdentityServer since the site is small and i don't need a user store, everything is in LDAP / ADFS.
Can I register three middleware peices, build a token from the oauth authentication, store it somewhere like a claim and pass it through the httpclient where its verified?
app.UseCookieAuthentication(option);
app.UseJwtBearerAuthentication(bearer); //api
app.UseOAuthAuthentication(adfsOption); //mvc ui
inside the adfsOption build a token...
Everything I try gets
Message "A security error occurred"
The answer to my question is yes, its very straight forward. I'll post a gist later. My primary problem which was high jacking me was the httpclient didn't like my dev cert for ssl.
I'm still unsure if putting the token in a claim is ok. The cookie and oauth invalidate it every 15 minutes and refresh it, but randomly getting a refresh token would be very difficult.
adding this very bad code allowed it to check my token and it worked as expected.
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };

How to set up cookie based authentication with NancyFx and IdentityServer3 (non-API website)

We have an environment with the following:
Standalone IdentityServer3 instance (issues reference tokens, not jwt)
ASP.NET WebAPI resource server
.NET client applications that authenticate against IdSvr (via resource owner flow)
...and now we'd like to start adding an OWIN-hosted web app that will use NancyFx to serve server-rendered pages as well as a couple AngularJS SPAs. This Nancy website will NOT host any APIs, but may consume data from our existing API. I'd like to add authentication in the OWIN pipeline to help secure our Angular applications from being sent down to users who don't have access.
This would be in contrast to sending down the SPA code, and having Angular determine if the user should see anything. In that case we've already exposed the javascript code base, and this we want to avoid.
I'm trying to understand how I should configure this Nancy site to authenticate users against IdentityServer using the implicit flow. I have implemented this authentication scheme in standalone SPAs before (where all authentication was handled by AngularJS code and tokens were stored in HTML5 local storage), but I'm a bit lost on how to properly tackle this within the OWIN pipeline.
I'm thinking that the OWIN cookie authentication middle-ware is the answer, but does that mean the following?
I need to redirect the user to IdentityServer (using the proper url arguments for implicit flow)?
IdentityServer will redirect the user back to my site on a successful login, so is that where I hook into the OWIN Authorization manager to set the appropriate cookie?
...or am I thinking about this all wrong?
For reference, I've read through the following posts, and they're very helpful but I'm not quite seeing the big picture with OWIN. I'm going to experiment with the UseOpenIdConnectAuthentication middle-ware next, but I would appreciate any guidance SO might have here.
http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/
https://github.com/IdentityServer/IdentityServer3/issues/487
Fundamentally, implementing OpenID Connect authentication in a Nancy app hosted via OWIN is really not different from implementing it in any MVC/Katana app (the Thinktecture team has a sample for this scenario: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/Clients/MVC%20OWIN%20Client)
You basically need 3 things: the cookie middleware, the OpenID Connect middleware and the Nancy middleware:
public class Startup {
public void Configuration(IAppBuilder app) {
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
// Set the address of your OpenID Connect server:
Authority = "http://localhost:54541/"
// Set your client identifier here:
ClientId = "myClient",
// Set the redirect_uri and post_logout_redirect_uri
// corresponding to your application:
RedirectUri = "http://localhost:56765/oidc",
PostLogoutRedirectUri = "http://localhost:56765/"
});
app.UseNancy(options => options.PerformPassThrough = context => context.Response.StatusCode == HttpStatusCode.NotFound);
}
}
If you're looking for a functional demo, you can take a look at https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy/Nancy.Client (note: it doesn't use IdentityServer3 for the OIDC server part but it shouldn't make any difference for the client app).

What are the correct authentication settings for an on-premise ADFS flow?

I've been reading Vittorio Bertocci's blog to try to get up to speed on using ADFS to manage authentication and claims in either an MVC app or WebApi service. It looks like it's getting to be very approachable.
I am now trying to build out a POC using ADFS to do common claims resolution for internal sites/services in our enterprise. Our users would be on the internal network along with our endpoints. Right now we use Windows Integrated auth by default and each site does the work of looking up a user’s name, email, and other AD details and inspecting the claims principal for roles via IsInRole. The claims we get with integrated auth includes just a SamIdentifier and a bunch of group SIDs. I’d like ADFS to do that work for us but still give our users a challenge-free experience. Long term, we will likely add support for non-domain-joined devices on some sites/services, so that is another motivation to explore ADFS.
So I've set up a simple sample app in VS2013 using Organizational Accounts (On Premise) that will dump out a current user's claims, configured the metadata endpoint and audience uri, communicated that info along with the claims I'd like mapped to my ADFS admin (2012, btw), and deployed my site to a development server. So my host is still IIS, though I hope to use Owin middleware to set up authentication rather than web.config (WIF-style).
Given that IIS is my host, how do I configure authentication for my site: anonymous? And my web.config should specify "None" for the authentication mode and deny="?" for authorization, correct?
The other question I have that Vittorio didn't get into in his post about on-premise adfs was the nature of the bearer token and whether or not we need to explicitly configure the middleware to use cookies. My startup config looks like this right now:
public void ConfigureAuth(IAppBuilder app)
{
app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
MetadataEndpoint = ConfigurationManager.AppSettings["ida:AdfsMetadataEndpoint"],
TokenValidationParameters = new TokenValidationParameters() { ValidAudience = ConfigurationManager.AppSettings["ida:Audience"] }
});
}
It looks like this middleware is expecting JWT tokens (given that there is a JwtSecurityTokenHandler on the class). Is there any configuration we need to do on the ADFS side to issue JWT tokens? My understanding is that I'll receive a SAML token by default.
And should we expect to use the CookieAuthentication middleware to manage the token or will the browser just keep including it for the life of the session?
Thanks, all!
UPDATE:
So based on Vittorio's help below and some further research, I now have a simple website with just one page protected with an [Authorize] attribute. My startup class's ConfigureAuth method now looks like this:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
MetadataEndpoint = ConfigurationManager.AppSettings["ida:AdfsMetadataEndpoint"],
TokenValidationParameters = new TokenValidationParameters() { ValidAudience = ConfigurationManager.AppSettings["ida:Audience"] }
});
}
We've added my website as a relying party trust in ADFS and created a half dozen claims rules. Everything seems correct so far, but I'm still struggling. I hit the protected "claims" page and get a 401 response with a WWW-Authenticate:Bearer header. So far, so good.
But that's it. How does the browser know where to get authenticated and receive a token? If I was proving out the separate client scenario, my client would be configured with the location of the token authority, but in this simple website scenario, I'm clearly missing something.
UPDATE 2:
I wonder if the implementation for on-premise ADFS just isn't ready yet? Or perhaps the documentation just isn't there yet - or both...
I pulled out all the Owin packages and reverted to using the WSFederationAuthenticationModule and SessionAuthenticationModule, along with all the web.config settings in system.identityModel and system-identityModel.services that have been around a while. Basically, I made the solution look like the one you get from VS2013 when you selected Organizational Accounts --> On Premise. Everything works beautifully and I have all my configured claims coming from ADFS. I see the initial 302 redirect to ADFS, the challenge-response, and ultimately have a SAML token serialized into a secure session cookie. On the website, I echo back the claims like so:
var user = User as ClaimsPrincipal;
ViewBag.Claims = user.Claims;
return View();
This is why I suspect the middleware is incomplete: when you use that new template in VS2013, the wizard goes to the federation metadata endpoint you specify and builds out all the web.config settings by reading that xml and, in addition, sets some intelligent defaults. That's sort of what I expected to happen in the Owin middleware - it should have everything it needs to know since I pass in the same metadata endpoint. I was hoping that "magic" would replace using the FAM/SAM modules and all the accompanying config.
1) If you are configuring a web UX app, that is something meant to be consumed through browser redirects, you want to use http://www.cloudidentity.com/blog/2014/04/29/use-the-owin-security-components-in-asp-net-to-implement-web-sign-on-with-adfs/. You'll see that the cookie middleware does come into play in that case.
2) If you are configuring a web API, as in something that is consumed by a rich client or another server, or in general anything that is not a browser roundtripping, see http://www.cloudidentity.com/blog/2013/10/25/securing-a-web-api-with-adfs-on-ws2012-r2-got-even-easier/. In that case you do not need cookies, given that there is no session -every single call must carry the token.
HTH
V.
As Vittorio said you need to differentiate if you create a web page with web api or web api only. Follow his blog posts they are great!!
If you host a webapi only project in an IIS you need to set the authentication to "forms authentication".
This works also if your web api is covered behind a web application proxy. make sure that you configure your endpoint (published web application) not to preauthenticate. the value for "preauthenticate" should be "pass through".
bg Andrej

Call WCF Resfull methods with using OAUTH 2.0

I am looking for any article or forum thread, where I could find information how to make oauth 2.0 authentication. Especially I have MVC 3 application and WCF Restfull API. And I have to call API methods from web app with using oauth 2.0 protocol authentication. But I could not find any information about it. After googling I see only results how to develop clients for facebook, linkedin, google etc.. Any help would be helpful. Thank you.
You could have a look at DotNetOpenAuth. It has a client library which you can easily install from NuGet here.
Using DotNetOpenAuth all the OAuth plumbing is handled behind the scenes.
DotNetOpenAuth:
When you install the NuGet Package: https://www.nuget.org/packages/DotNetOpenAuth.Ultimate/4.3.3.13295
You can setup an OAuth client like this:
var authorizationServerDescription = new AuthorizationServerDescription
{
ProtocolVersion = ProtocolVersion.V20,
TokenEndpoint = new Uri("https://yourUrl/token"),
AuthorizationEndpoint = new Uri("https://yourUrl/authorize")
};
var client = new WebServerClient(authorizationServerDescription, "ClientIdentifier", "ClientSecret");
Then you can request a IAuthorizationState like this:
// Resource Owner Password Flow
client.ExchangeUserCredentialForToken("userName", "password");
// Client Credential Flow
client.GetClientAccessToken();
The IAuthorizationState contains the AccessToken you can use to Authorize against your Api. If a RefreshToken is provided you can also refresh your authorization using:
client.RefreshAuthorization(AuthorizationState);
ThinkTecture:
Alternatively you could use Thinktecture.IdentityModel. If you chose to use Thinktectures IdentityModel be sure to check out this post: Introducing OAuth2 Code Flow and Refresh Token Support in Thinktecture IdentityServer. Which not only explains how to set up an OAuth Token Server using Thinktecture, but how to use the client as well including a code sample. Ofcourse you can use this client to validate against another OAuth 2.0 server as long as the parameters are implemented according to the OAuth specifications.
OAuth 2.0 Playground
If you want to have a better look at the OAuth 2.0 flow, be sure to check out Google's OAuth 2.0 Playground. I think that a lot of people don't know that it is possible to test your own server with it. Just push the 'settings' icon in the top right and set:
OAuth endpoints: Custom
And you're good to go.