How to decrypt asp.net owin token in asp.net core manually? - asp.net-core

I have an existing application which generates owin identity token with machine key approach. The same token is used to authenticate various application. One of the application is now in asp.net core. Is there any way to use same owin generated identity token in asp.net core?
or we can decode that token manually in asp.net core

You cannot share anything between ASP.NET and ASP.NET Core when using machine keys. The only way to be able to decrypt something in ASP.NET Core set by an ASP.NET app is if 1) the ASP.NET app(s) utilize the data protection provider 2) the data protection provider key ring is persisted to filesystem or network location accessible by all the apps (ASP.NET and ASP.NET Core alike) and all the apps utilize the same application name.
The docs go into great detail on this.

You can decrypt the Access Token returned from the authorization code flow directly by using IDataProtector. we implement the IDataProtector interface and use the System.Web.Security.MachineKey.Unprotect method.
To Make helper Method to decrypt the OWIN ticket
private class MachineKeyProtector : IDataProtector
{
private readonly string[] _purpose =
{
typeof(OAuthAuthorizationServerMiddleware).Namespace,
"Access_Token",
"v1"
};
public byte[] Protect(byte[] userData)
{
//throw new NotImplementedException();
}
public byte[] Unprotect(byte[] protectedData)
{
return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);
}
}
To get ClaimsIdentity and a Dictionary of Properties. we just create an instance and pass in the Token to get the decrypted Ticket
var secureDataFormat = new TicketDataFormat(new MachineKeyProtector());
AuthenticationTicket ticket = secureDataFormat.Unprotect(accessToken);
Above AuthenticationTicket itself contains the ClaimsIdentity and a Dictionary of Properties.
refer IDataProtector Interface

Related

HubConnectionContext.User property not populated for SignalR / Blazor WASM / IdentityServer hubs

I followed the tutorial Use ASP.NET Core SignalR with a hosted Blazor WebAssembly app and Authentication and authorization in ASP.NET Core SignalR to create an authenticated SignalR hub.
However I can't get the logged in user from the hub Context.User.Identity.Name object.
Upon user creation I have added a claim:
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, Input.Email));
In Startup.cs I have registered this IUserIdProvider and setting a breakpoint confirms it gets called during runtime but it returns null.
public class EmailBasedUserIdProvider : IUserIdProvider
{
public virtual string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
}
}
In the hub, I have set the [Authorize] attribute but the Context.User.Identity object is null for the Name property and if I look in the Claims collection, the SQLServer user Id is present but nothing else.
I suspect the problem is in the EmailBasedUserIdProvider which is unable to find the Email claim because it is not there on the connection.User object. What needs to be done to make this available?
Thanks

Convert use of Membership to something that will work in .NET Core for WCF service calls

I have some legacy framework code that calls a service that I need to replicate in a .NET Core 3.1 solution. The code uses a client built by adding a web reference (ImageService). The code authenticates the user using Membership and sets an authentication cookie that is used by the execution of client methods.
The method below is what I need to replicate in the Core solution. I've created a client in the .NET Core solution also using the WCF web reference. What do I need to do/use to replicate the functionality of the code below?
private static void setImageService(string host, string userId, string password) {
ImageService.ImageService _imageServiceSoapClient = new ImageService.ImageService();
((ClientFormsAuthenticationMembershipProvider) Membership.Provider).ServiceUri = string.Format("https://{0}/ImageService/Authentication_JSON_AppService.axd", host);
((ClientRoleProvider) Roles.Provider).ServiceUri = string.Format("https://{0}/ImageService/Role_JSON_AppService.axd", host);
bool validateUser = Membership.ValidateUser(userId, password);
if (validateUser) {
AppDomain.CurrentDomain.SetThreadPrincipal(Thread.CurrentPrincipal);
} else {
throw new InvalidCredentialException(string.Format("User {0} not authenticated", userId));
}
_imageServiceSoapClient.CookieContainer = ((ClientFormsIdentity) Thread.CurrentPrincipal.Identity).AuthenticationCookies;
}

How can I use Asp.Net Core 2.0's in-memory TestServer class for Integration Tests when my API requires an Authorization Token?

I am working on an ASP.NET Core 2.0 Web API and I want to do some integration tests using ASP.NET Core's TestServer class. I am using xUnit as my testing framework so I have created a TestServerFixture class that creates the in-memory TestServer instance and then use the TestServer's .CreateClient() to create the HTTPClient instance.
My Web API requires an OAuth2.0 Access Token from my Azure AD. I set this up using this code in my Startup.cs, ConfigureServices method:
// Add Azure AD OAUTH2.0 Authentication Services
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));
and in my controllers, I have the [Authorize] attribute on the class.
So for my Integration Tests setup, I have a method in my TestServerFixture that obtains a valid token from Azure AD and I add it to my client request header as follows;
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await _testServerFixture.GetAccessToken());
When I debug my integration test, I can see that the request does contain a valid access token but I am still getting a 401 Unauthorized from the API when I run my Integration Test.
After doing some digging I found several resources that talk about a similar issue with TestServer, but related to Authentication rather than Authorization, as I am experiencing. Here are links to these resources;
https://medium.com/#zbartl/authentication-and-asp-net-core-integration-testing-using-testserver-15d47b03045a
How do I integration test a ASP 5/Core Web API with [Authorize] Attributes
http://geeklearning.io/how-to-deal-with-identity-when-testing-an-asp-net-core-application/
These all talk about assigning a ClaimsPrincipal to the context.user using custom middleware. Since this is based upon Authentication rather than Authorization, I am not sure if I can do something similar for my Access Token.
I do know that in my API, I can access the HTTPContext.User and pull out the AppId value, which is part of the Access Token so it would seem that Authentication and Authorization both use the Context.User.
So, before I burn time building up my own custom middleware for this purpose, I wanted to see if anyone has already addressed this issue or perhaps are aware of a NuGet that does what I need.
EDIT - SOLUTION
I am showing this in case anyone else runs into this issue.
I ended up building the middleware that Zach Bartlett presented in his blog , but making the following changes.
public class AuthenticatedTestRequestMiddleware
{
#region Class Variables
private const string TestingAccessTokenAuthentication = "TestingAccessTokenAuthentication";
private readonly RequestDelegate _next;
#endregion Class Variables
#region Constructor(s)
public AuthenticatedTestRequestMiddleware(RequestDelegate next)
{
_next = next;
}
#endregion Constructor(s)
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains("X-Integration-Testing"))
{
if (context.Request.Headers.Keys.Contains("Authorization"))
{
var token = context.Request.Headers["Authorization"].First();
var claimsIdentity = new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Authentication, token)
}, TestingAccessTokenAuthentication);
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
context.User = claimsPrincipal;
}
}
await _next(context);
}
}
There were one interesting "Gotcha".
In Zach's blog he had the code;
public const string TestingHeader = "X-Integration-Testing";
at the top of his middleware and then references the TestingHeader in the test for the key in the header collection like this;
if (context.Request.Headers.Keys.Contains(TestingHeader)
Doing it this way was failing for me until I put the string literal instead of the variable into the .Contains() clause.
Now, my integration test is passing with a 200 OK response. :)
I was able to find a solution following Zach Bartlett's blog post, and making some small changes to make it pertain to the Authentication header. The code is shown as an edit in my original post above.

How to get the CurrentPrincipal Identity on ASP.Net Core 2 Web Application?

I created a Azure AD B2C Tenant to use with an Azure Function. I used this and it is working:
Thread.CurrentPrincipal.Identity.IsAuthenticated
Now I am trying to get the User logged in, with this same call this in ASP Net Core 2 Web Site Razor Page Index.cshtml.cs
public void OnGet()
{
var isAuth = Thread.CurrentPrincipal.Identity.IsAuthenticated;
ClaimsPrincipal cp = (ClaimsPrincipal)Thread.CurrentPrincipal;
}
But
Thread.CurrentPrincipal is returning null on ASP Net Core 2
In ConfigureServices method on Startup.cs I added
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//services.AddAuthentication();
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.Audience = Configuration["Authentication:AzureAd:ClientId"];
//options.Events = new JwtBearerEvents
//{
// OnAuthenticationFailed = AuthenticationFailed
//};
var authorityBase = string.Format("https://login.microsoftonline.com/tfp/{0}/", "empresateste123.onmicrosoft.com"/*Configuration["Authentication:AzureAd:Tenant"]*/);
options.Authority = string.Format("{0}{1}/v2.0/", authorityBase, "B2C_1_policysignin " /*Configuration["Authentication:AzureAd:Policy"]*/);
});
}
In Configure method on Startup.cs I added
app.UseAuthentication();
When I publish and go to the URL, this Exception happens on that line:
An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
If I use
public void OnGet()
{
//var isAuth = Thread.CurrentPrincipal.Identity.IsAuthenticated;
//ClaimsPrincipal cp = (ClaimsPrincipal)Thread.CurrentPrincipal;
var u = this.User;
var uc = u.Claims.ToList();
}
now it comes, but the Claims.Count = 0, no user information
What else do I need to add to make it work?
Use PageModel.User which returns a ClaimsPrincipal object that represents the current web-application user. Thread.CurrentPrincipal should not be used to get the current web-application user because Thread.CurrentPrincipal concerns thread security managed by .NET (and possibly the Operating System).
ASP.NET, all the way back from its early days in 2001 (ab)used this feature of .NET by overwriting Thread.CurrentPrincipal with the current ASP.NET "User" - this had practical benefits when it's used in the context of Identity Impersonation with Windows Authentication, allowing web-applications to access security-restricted files, network resources and operating-system features when it would otherwise be unable to.
This article from 2004 gives a good explanation (ignore the references to the now obsolete FormsAuthentication module): https://www.hanselman.com/blog/SystemThreadingThreadCurrentPrincipalVsSystemWebHttpContextCurrentUserOrWhyFormsAuthenticationCanBeSubtle.aspx - the article also explains why Thread.CurrentPrincipal may be null, for example when application code is called before HttpApplication.OnThreadEnter() (which sets the CurrentPrincipal property) is called.
I'm not too familiar with the lifecycle of Razor-Pages (a new feature in ASP.NET Core since late 2017) or how the security system changes in an Azure Functions and Azure AppService (f.k.a. Azure Websites) context.
In any event, the fix is to always use the User property in ASP.NET instead of Thread.CurrentPrincipal.
In ASP.NET Web Forms, use System.Web.HttpContext::User (or System.Web.UI.Page::User)
In ASP.NET MVC, use System.Web.Mvc.Controller::User
ASP.NET MVC (when using .aspx Views) can use System.Web.Mvc.ViewPage::User
ASP.NET MVC using Razor Views can access #this.User (or just #User) directly in Razor code (inherited from System.Web.WebPages.WebPageRenderingBase::User)
In ASP.NET Core MVC, use Microsoft.AspNetCore.Mvc.ControllerBase::User inside an Action.
In ASP.NET Razor-Pages, use Microsoft.AspNetCore.Mvc.RazorPages.PageModel::User.

Validating a user in WCF using ASP.net Identity 2.0 Framework

I have built a custom Identity.Models framework by simply extending the new asp.net identity framework 2.0 so that I can store the username and other relevant user data in my custom database instead of the default entity database which gets generated and it is working fine.
Now I am building a WCF service from where I would like to authenticate these users and leverage the asp.net identity 2.0 functionalities , but unable to do so.
In my WCF service I made a new Validator class extending UsernamePasswordValidator but it is not working as expected.
public class IdentityValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
using (var context = new MyIdentityDbContext())
{
using (var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context)))
{
var user = userManager.Find(userName, password);
if (user == null)
{
var msg = String.Format("Unknown Username {0} or incorrect password {1}", userName, password);
Trace.TraceWarning(msg);
throw new FaultException(msg);
}
}
}
}
}
Any suggestions would be highly appreciated.
You are almost there, however, you need one more step to tell the WCF service to be well behaved through introducing service behavior, generally in config. For more details, please read
Authentication and Authorization with ASP.NET Identity 2.0 for WCF Services