I've got a IDP implemented in IdentityServer 4. My web app client(implemented in Mvc 5) authenticates with the IDP but now I need to get the access token from the request.
A way to do that in .Net Core is to use the Microsoft.AspNetCore.Authentication.AuthenticationTokenExtensions like so:
HttpContext.Authentication.GetTokenAsync("acccess_token")
I would like to be able to do the same in my .net Mvc5 web app client but I can't find any nuget package or namespace that has a similar implementation. It is important to be able to do this in MVC5 and not .net Core. Anyone came across this before?
PS- Also worth to mention that I'm using OpenIdConnect
The recently released 4.1.0 version of Katana now supports the SaveTokens property (backported from ASP.NET Core).
In order to get the access token:
Update the Microsoft.Owin.Security.OpenIdConnect package to 4.1.0 (or newer)
Configure SaveTokens in your Startup class:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
// Other options removed for readability
SaveTokens = true,
// Required for the authorization code flow to exchange for tokens automatically
RedeemCode = true
});
Read the access token in your Controller:
var result = await Request.GetOwinContext().Authentication.AuthenticateAsync("Cookies");
string token = result.Properties.Dictionary["access_token"];
In your controller you can get the token using this code:
var token = ActionContext.Request.Headers.Authorization.Parameter;
I spent some type before I understood, we need to send a string as an argument of AuthenticateAsync which is used in AuthenticationType and SignInAsAuthenticationType.
I hilly recond to use CookieAuthenticationDefaults.AuthenticationType because it will save you from typos.
Related
I would like to share an authentication cookie provided by the ASP.NET Framework app and use it in ASP.NET Core app. To encrypt cookie I am using Data Protection, which is a default in .NET Core and requires package Microsoft.AspNetCore.DataProtection.SystemWeb for .NET Framework.
When .NET Core generates and protects cookie authentication works for .NET Core app. When .NET Framework generates and protects cookie .NET Core app doesn't use it.
According to https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/replacing-machinekey?view=aspnetcore-3.1 properly protected cookie should start with "CfDJ8", which is the base64 representation of the magic "09 F0 C9 F0" header that identifies a payload protected by the data protection system. The cookie generated by .NET Core starts with "CfDJ8" but cookie generated by .NET Framework starts with "09F0C9F0".
It seems that cookie is correctly generated and protected but .NET Core uses base64 to encode cookie and .NET Framework uses hexadecimal strings.
The question is, how to set up common cookie encoding for an authentication cookie encrypted by ASP.NET Core Data Protection?
I followed the guide here to share cookie between as .NET framework Webforms application and a newer aspnetcore 5 application.
https://learn.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-5.0
In my case, the webforms app authenticates and issues the cookie. I see that the cookie is generated and set correctly with the encrypted header text indicating the Data Protection system is in effect (see the screenshot below).
The webforms app works fine, however the aspnetcore app does not use this cookie! Any action with [Authorize] attribute is taken back to the login page. Is there anything else that needs to be done on the aspnet core side to make this work?
I followed the guide at https://github.com/blowdart/idunno.CookieSharing and it worked perfectly. The guide is far more in depth than this answer. As a summary, you want to use DataProtector in both apps, with Microsoft.Owin.Security.Interop.DataProtectorShim enabling DataProtector to work in the .Net Framework App and Microsoft.Owin.Security.Interop.AspNetTicketDataFormat providing the ticket format for the .Net Framework App :
.NET Core
Use Data Protection (OP is already doing so)
For consistency (and to ensure implementations match), set your TicketDataFormat explicitly
So, something like this:
var protectionProvider = DataProtectionProvider.Create(
new DirectoryInfo("c:\keyring"));
var dataProtector = protectionProvider.CreateProtector(
"CookieAuthenticationMiddleware","Cookie","v2");
var ticketFormat = new TicketDataFormat(dataProtector);
services.ConfigureApplicationCookie(options =>
{
options.TicketDataFormat = ticketFormat;
//...
});
.Net Framework
Use Data Protection
For consistency (and to ensure implementations
match), set your TicketDataFormat explicitly.
Add the Microsoft.Owin.Security.Interop nuget package. You'll need it to wrap your DataProtector in a DataProtectorShim (and explicitly use the AspNetTicketDataFormat interop class).
var cookieOptions = new CookieAuthenticationOptions
{
TicketDataFormat = ticketFormat,
//...
};
var protectionProvider = DataProtectionProvider.Create(
new DirectoryInfo("c:\keyring"));
var dataProtector = protectionProvider.CreateProtector(
"CookieAuthenticationMiddleware", "Cookie", "v2");
var ticketFormat = new AspNetTicketDataFormat(
new DataProtectorShim(dataProtector));
You should use data protection API in classic asp.net. To achieve this you can refer to below steps or direct check this
Document
To share authentication cookies between two different ASP.NET 5 applications, configure each application that should share cookies as follows.
Install the package Microsoft.AspNet.Authentication.Cookies.Shareable into each of your ASP.NET 5 applications.
In Startup.cs, locate the call to UseIdentity, which will generally look like the following.
// Add cookie-based authentication to the request pipeline.
app.UseIdentity();
Remove the call to UseIdentity, replacing it with four separate calls to UseCookieAuthentication. (UseIdentity calls these four methods under the covers.) In the call to UseCookieAuthentication that sets up the application cookie, provide an instance of a DataProtectionProvider that has been initialized to a key storage location.
// Add cookie-based authentication to the request pipeline.
// NOTE: Need to decompose this into its constituent components
// app.UseIdentity();
app.UseCookieAuthentication(null, IdentityOptions.ExternalCookieAuthenticationScheme);
app.UseCookieAuthentication(null, IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme);
app.UseCookieAuthentication(null, IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme);
app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationScheme,
dataProtectionProvider: new DataProtectionProvider(
new DirectoryInfo(#"c:\shared-auth-ticket-keys\")));
Caution: When used in this manner, the DirectoryInfo should point to a key storage location specifically set aside for authentication cookies. The application name is ignored (intentionally so, since you’re trying to get multiple applications to share payloads). You should consider configuring the DataProtectionProvider such that keys are encrypted at rest, as in the below example.
app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationScheme,
dataProtectionProvider: new DataProtectionProvider(
new DirectoryInfo(#"c:\shared-auth-ticket-keys\"),
configure =>
{
configure.ProtectKeysWithCertificate("thumbprint");
}));
The cookie authentication middleware will use the explicitly provided implementation of the DataProtectionProvider, which due to taking an explicit directory in its constructor is isolated from the data protection system used by other parts of the application.
Asp.net will use dataprotection which is injected by DI to encrypt cookies, in that case you need to enable owin auth in your classic asp.net application.
I have ASP.NET 4.5 service with OWIN pipeline that issues OAuth access_token in exchange for username/password. This service is called from ng-app and once it gets a token, stores in the browsers local storage. Then it calls resource api that consumes this token, API is also written in asp.net 4.5 and uses owin. This being OAuth token issued with OWIN it's encrypted/signed to machineKey secrets - so far so good and is happily consumed by the resource API. All this made possible by OAuthAuthorizationServerMiddleware.
Now I need to consume these tokens sent from the same ng-app to asp.net core 2.1 services, nothing fancy, just verify/decode it and get claims inside the token.
This OAuthAuthorizationServerMiddleware was never ported to asp.net core so I am stuck. (OAuth Authorization Service in ASP.NET Core does not help it talks about the full-fledged oidc server I just need to consume them w/o changing the issuing code)
In ConfigureServices() tacked on to service.AddAuthentication():
Tried.AddJwtBearer - but this makes no sense - these are not Jwt tokens really
Tried.AddOAuth but this does not make sense either b/c I am not dealing with full OAuth flow with redirects to obtain a token, I also don't deal with ClientId/ClientSecret/etc, I just receive "Bearer token-here" in the HTTP header from ng app so I need something in the pipeline to decode this and set ClaimsIdentity but this "something in the pipeline" also needs to have access to machinery-like data that is the same as it is in asp.net 4.5 OWIN service
Any ideas?
You could set the OAuthValidation AccessTokenFormat to use a MachineKey DataProtectionProvider and DataProtector which will protect and unprotect your bearer tokens. You will need to implement the MachineKey DataProtector. This guy already did it https://github.com/daixinkai/AspNetCore.Owin/blob/master/src/DataProtection/src/AspNetCore.DataProtection.MachineKey/MachineKeyDataProtectionProvider.cs.
public void ConfigureServices(IServiceCollection services){
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
ConfigureAuth(services);
string machineKey = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<machineKey decryption=""Auto"" decryptionKey =""DEC_KEY"" validation=""HMACSHA256"" validationKey=""VAL_KEY"" />";
var machineKeyConfig = new XmlMachineKeyConfig(machineKey);
MachineKeyDataProtectionOptions machinekeyOptions = new MachineKeyDataProtectionOptions();
machinekeyOptions.MachineKey = new MachineKey(machineKeyConfig);
MachineKeyDataProtectionProvider machineKeyDataProtectionProvider = new MachineKeyDataProtectionProvider(machinekeyOptions);
MachineKeyDataProtector machineKeyDataProtector = new MachineKeyDataProtector(machinekeyOptions.MachineKey);
//purposes from owin middleware
IDataProtector dataProtector =
machineKeyDataProtector.CreateProtector("Microsoft.Owin.Security.OAuth",
"Access_Token", "v1");
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddOAuthValidation(option=> {
option.AccessTokenFormat = new OwinTicketDataFormat(new OwinTicketSerializer(), dataProtector); })
It's important to keep the same DataProtector "purposes" Owin uses in the OAuthAuthorizationServerMiddleware so the data is encrypted/decrypted correctly. Those are "Microsoft.Owin.Security.OAuth", "Access_Token" and "v1". (see https://stackoverflow.com/a/29454816/2734166).
And finally you will have to migrate the Owin TicketSerializer (and maybe the TicketFormat too) since the one in NetCore is slightly different. You can grab it from here:
https://github.com/aspnet/AspNetKatana/blob/e2b18ec84ceab7ffa29d80d89429c9988ab40144/src/Microsoft.Owin.Security/DataHandler/Serializer/TicketSerializer.cs
I got this working recently. Basically authenticating to a .NET 4.5 Owin API and running a resource API in NET Core using the same token. I'll try to share the code in github as soon as I clean it up.
As far as I know it's not recommended to keep the old machine key data protector, but to migrate to the new ones from NET Core. Sometimes this is not possible. In my case I have too many APIs already in production, so I'm trying some new NET Core APIs to work with the legacy ones.
You should try this Owin.Token.AspNetCore nuget package instead. By following the code example provided in the README file I'm able to decode legacy tokens using the machine keys on .NET Core 3.1. Note: there's also an option to specify encryption method and validation method if the defaults are not working for you.
I have a project that hosts the IdentityServer4 and I am attempting to also host in the same project a Web API, which accepts the access-token.
My question is, is possible that a single project contains the IdentityServer and an Web API that consume the same IdentityServer?
EDIT: The API must be secured with the Authorize attribute
I have an identity server 4 project, in the same project there is an API for CIUD of the clients. (Lets call it developer console api).
I then have a side project with is an asp .net core project that contains the actual razor pages for the Developer console it access the API within the Identity server project.
The reason i did it this way is that only one project should be updateing the database. So to update the database owned by the identity server it was decided the the API for accessing it should also be within the same project.
Yes you can have a web api from within your Identity server 4 project.
Configure service
services.AddAuthentication(IdentityServerConstants.DefaultCookieAuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
// base-address of your identityserver
options.Authority = settingsSetup.Settings.Authority;
// name of the API resource
options.ApiName = "testapi";
options.RequireHttpsMetadata = false;
});
Configure
I think it needs to have both of these.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseAuthentication();
app.UseIdentityServer();
Endpoints
Because the requests are sent using the access token as a bearer token then the authorize for each of the API calls needs to include the authencationScheme. I havent exactly figured out why but without this it doesnt work.
[HttpGet("Client/List")]
[Authorize(AuthenticationSchemes = "Bearer")]
public ActionResult ClientList()
{
}
While #DaImTo's answer is correct and working and it's developed by IdentityServer team, it uses Introspection Endpoint which means for every request AddIdentityServerAuthentication will create a http request and send it to your server, which is the same app.
I developed a library called IdentityServer4.Contrib.LocalAccessTokenValidation which do the exact same thing but without using Introspection Endpoint. It will authenticate the token directly from TokenStore which is configured in Services. You can use it if you are interested.
nuget link : https://www.nuget.org/packages/IdentityServer4.Contrib.LocalAccessTokenValidation
github link : https://github.com/Kahbazi/IdentityServer4.Contrib.LocalAccessTokenValidation
I'm currently working on a RESTful project built upon ASP.NET Core 1.0 which connects to an Identity Server 3. I set a global [Authorize] Filter for all Controllers in the ConfigureServices method in Startup.cs.
I now try to validate my Bearer Token from an AJAX Request against my Identity Server 3 in the Startup.cs of the CORE 1.0 project and thus Authorize my controller resources.
It seems so much changed in ASP.NET CORE 1.0 compared to (classic) ASP.NET 4.5.
Do you have some ideas how to achieve this? How to validate my token in ASP.NET Core 1.0?
Many Thanks!
UPDATE
In Asp.net 4.5 I was able to use app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions(){...}) but this doesn't exist in ASP.NET Core 1.0.
Instead I try to use the following :
var connectOptions = new OpenIdConnectOptions
{
Authority = Configuration["IdentityServerSettings:CoreUrl"],
ClientId = Configuration["IdentityServerSettings:ClientId"],
ClientSecret = Configuration["IdentityServerSettings:ClientSecret"],
PostLogoutRedirectUri = Configuration["IdentityServerSettings:PostLogoutRedirectUri"],
ResponseType = OpenIdConnectResponseType.Code
};
app.UseOpenIdConnectAuthentication(connectOptions);
Unfortunately all I get is a HTTP 302...
It's possible to use IdentityServer4.AccessTokenValidation to solve this issue :)
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions()
{
ScopeName = Configuration["IdentityServerSettings:ApiScopes"],
Authority = Configuration["IdentityServerSettings:CoreUrl"]
});
I think what you are asking for is is you want to use a Bearer Token Authentication middleware.
The package that you're looking for is"Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0"
I have to figure out how to use OAuth 2 in order to use Deviantart api.
I got the client_id and client_secret part
Here the information they give
Endpoints
The only information you need to authenticate with us using OAuth 2.0 are the client_id and client_secret values for your app, as well as the endpoint shown below.
OAuth 2.0 draft 10:
https://www.deviantart.com/oauth2/draft10/authorize
https://www.deviantart.com/oauth2/draft10/token
OAuth 2.0 draft 15:
https://www.deviantart.com/oauth2/draft15/authorize
https://www.deviantart.com/oauth2/draft15/token
Placebo call
The first API call relying on OAuth 2.0 authentication is the placebo call.
It's useful for checking that an access token is still valid before making a real API call that might be long, like a file upload.
You call it with one of the following endpoints (an access token must be provided):
https://www.deviantart.com/api/draft10/placebo
https://www.deviantart.com/api/draft15/placebo
You need to use the endpoint that corresponds to the OAuth 2.0 draft you've obtained your token with.
It always returns the following JSON: {status: "success"}
I have searched the web and found this awesome library.
DotNetOpenAuth v4.0.1
http://www.dotnetopenauth.net/
Added it as reference but have no idea what to do next. Even a very small example would be really useful about how to use OAuth 2
using DotNetOpenAuth;
using DotNetOpenAuth.OAuth2;
Here the page where deviantart gives the information
http://www.deviantart.com/developers/oauth2
Ok here what i got so far but not working
public static WebServerClient CreateClient() {
var desc = GetAuthServerDescription();
var client = new WebServerClient(desc, clientIdentifier: "myid");
client.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter("mysecret");
return client;
}
public static AuthorizationServerDescription GetAuthServerDescription() {
var authServerDescription = new AuthorizationServerDescription();
authServerDescription.AuthorizationEndpoint = new Uri(#"https://www.deviantart.com/oauth2/draft15/authorize");
authServerDescription.TokenEndpoint = new Uri(#"https://www.deviantart.com/oauth2/draft15/token");
authServerDescription.ProtocolVersion = ProtocolVersion.V20;
return authServerDescription;
}
Easiest thing to do now is get Visual Studio 2013 and create a new ASP.NET Web Application choosing "Individual User Accounts" as your authentication type. There's a working OAuth 2 implementation out of the box in there (configured at App_Start\Startup.Auth.cs) which you can slice out and then adapt to your needs.
In the ASP.NET Core Security Project there is now a ready to use solution:
Nuget Package: AspNet.Security.OAuth.DeviantArt