Faking authentication during development - .net-core

In my current asp.net MVC core application we use OpenId Connect to authenticate with our corporation's identity provider.
However during local development we cannot reach the the provider.
Also we would like to easily change claim values for development and unit testing purposes.
I tried swapping my service binding for IHttpContextAccessor to a DevelopmentHttpContextAccessor that fills up the HttpContext's Identity with the desired claims.
This is a bit of a roundabout way and it also doesn't work as the claims are emptied when I check them in my Service.
What is the standard way of handling this during development and unit testing? What am I missing?

The answer was not faking IHttpContextAccessor, but setting a custom ClaimsPrincipal to the identity property.
In your Startup.Configure you can add a middleware step:
app.Use((httpContext, nextMiddleware) => {
var claims = new[] {
// Your claims here
};
var claimsIdentity = new ClaimsIdentity(claims);
var user = new ClaimsPrincipal(claimsIdentity);
httpContext.User = user;
return nextMiddleware();
});

Related

IdentityServer4 Update Claim Value from API Project

I've got a pretty simple simple question I'd appreciate if you can provide a solution.
I have two projects:
An IdentityServer4 project.
An API project.
The API project is being protected using IdentityServer4 like the following:
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "TestAPI";
options.ApiSecret = "Password"
});
Up to this point everything is working as expected.
My question is from the API project how can I make update operations on IdentityServer4 like updating a users claim value ?
If I have understood your question correct - you want to change the claims, inside an API, that is protected by the IDS, that has issued the claims.
In general - this is not possible and not right.
Why not possible?
The ClaimsPrincipal class, and its Claims property is readonly (it has only getter, but no setter):
public virtual IEnumerable<Claim> Claims { get; }
Why it is not right?
Usually the claims are holding some authentication info (roles, username, some user profile information etc). This data is supposed to be issued by the authentication provider (in your case the IDS) and it is not supposed to be changed by someone/something, whose authorization depends on this authentication data.
PS: Out of curiosity - what claims exactly do you want to change, or this was just a general question?

Token-based authentication for Web API in an application which uses SimpleMembershipProvider

I have an ASP.NET Web API MVC 5.0 application. I've configured an ASP.NET Web API as part of this application (contained in the same project).
I'm currently attempting to add token-based authentication to my Web API. The guide I've been using however has been coding everything using Microsoft.AspNet.Identity with Owin.
However, my MVC project is still using the System.Web.Security SimpleMembershipProvider - so initialising the membership tables and managing accounts is performed using the WebSecurity class.
So, it looks like I have two options to move forward here:
Update my MVC application to switch to use Microsoft.AspNet.Identity so that it will work with my Web API token authentication.
Change my Web API authentication code to work with SimpleMembershipProvider
Firstly, is it even practically possible to make my Web API authentication work with SimpleMembershipProvider?
If I update my project to use Microsoft.Asp.Identity, it will involve a bit of work I'm sure. I'm game for doing that but just want to make sure it's not totally trivial to make my Web API token authentication work with SimpleMembershipProvider. Will there be any additional advantages to migrating to use Microsoft.Asp.Identity?
Just to give an example of what I have for my Web API authentication:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
return;
}
var oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);
var cookiesIdentity = await user.GenerateUserIdentityAsync(userManager, CookieAuthenticationDefaults.AuthenticationType);
var properties = CreateProperties(user.UserName);
var authenticationTicket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(authenticationTicket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
My existing MVC authentication code just uses the WebSecurity methods for managing accounts.
Thank you.
In the end up, I switched over from using the SimpleMembershipProvider to use the Asp.Net.Identity provider. The migration was actually fairly simple.
On my Entity Framework database context, I simply inherited the 'IdentityDbContext' class, e.g.
public class DataContext : IdentityDbContext<ApplicationUser>
And added this to my OnModelCreating override:
base.OnModelCreating(modelBuilder);
In my service which manages accounts, I added code which gets a reference to the new 'ApplicationSignInManager' and 'ApplicationUserManager', e.g.
public ApplicationSignInManager SignInManager
{
get => _signInManager ?? HttpContext.Current.GetOwinContext().Get<ApplicationSignInManager>();
private set => _signInManager = value;
}
public ApplicationUserManager UserManager
{
get => _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
private set => _userManager = value;
}
And then each time my code referenced the 'WebSecurity' class I simply replaced those calls with the relevant calls using my UserManager or SignInManager.
ASP.NET Identity also offers some advantages:
Supports Web Forms, MVC, Web API, SignalR and web pages. Don't need to have different implementations of a membership system.
Claims based authentication is now an option alongside role-based authentication.
Easy to enable social logons with Facebook, Google, Twitter or Microsoft Live.
Supports OWIN.
No need to code in functionality for account confirmation, password resets and so on - these are out of the box features of Asp.Net Identity.

Using ASP.NET Core MVC cookie based authentication with custom user tables in database

I have my own tables for Authentication:
Users
Roles
UserRoles
I am am trying to figure out what the best way to implement custom authentication with ASP.NET Core MVC would be. I do not want to use the built in UserManager, RoleManager, etc. I prefer creating my own. Can I somehow still tap into the cookie based authentication and use all of the ASP.NET Authorization helper tags without using asp.net identity?
Correct me if I am wrong, but I believe I want something like this:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/cookie
I have been trying to figure out ASP.NET Identity for years and I am
sick of not understanding every single part of it. I would rather
implement my own auth just like the good old days. It is most likely
my problem for not being able to read the documentation and pick up on
it, but I cant stand Entity Framework / ASP.NET Identity. I am aware
that ASP.NET Identity can be used without EF but just seems like a
pain.
Well, if you decided to go that route, you can use Cookie Authentication Middleware.
There are too many moving pieces, so I created a sample project in GitHub.
You can replace this LDAP Authentication with your own Authentication mechanism. Here is actual implementation.
The main reason I did not use ASP.NET Identity in some of my projects is we already have Active Directory in our organization.
Startup.cs
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
Events = new CookieAuthenticationEvents
{
OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
return TaskCache.CompletedTask;
}
},
ExpireTimeSpan = TimeSpan.FromMinutes(Int32.Parse(Configuration.GetSection(
"AppSettings:CookieAuthentication:ExpireMinutes").Value)),
AuthenticationScheme = Constants.AuthenticationScheme,
LoginPath = new PathString("/Account/Login"),
AccessDeniedPath = new PathString("/Common/AccessDenied"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});

MVC 5 and use of claims default authentication

I have a question regarding the claims in MVC 5.
So basically imagine I have a registered user in DB, now the user is going to log in, like so:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Add more custom claims here if you want. Eg HomeTown can be a claim for the User
var homeclaim = new Claim(ClaimTypes.Country, user.HomeTown);
identity.AddClaim(homeclaim);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
So in this case i add a new claim to the identity and then i sign in this identity.
Now my questions are:
What is the use of setting this claim? (because i can also get this from the db if i need it, what is the point in this case of claim)
And how do i use it later on in the code?
Setting the Claim against the identity makes your application security more efficient and saves hitting your database each time.
The method above can be known as a Claims Transformation which often involves reading in data that is transformed into claims after authentication succeeds.
In order to read it later you can do this:
//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
//Get the country from the claims
var country = identity.Claims.Where(c => c.Type == ClaimTypes.Country).Select(c => c.Value);
Update
Just to provide some further information to the answer as discussed in the comments below.
With a Claims based approach you also benefit from being able to use a claims authorization manager which can provide a centralized/finely grained access control to resources and actions. 
If you've not used claims before it's best to think of actions against resources rather than role based permissions. That way you can drill right down and control access to each resource/action individually rather than having a multitude of roles for each one. 
I personally like to use a mixture but store the roles as claims too. 
That way I can use the standard authorization tags in mvc with roles, which read the claims and use thinktecture's attributes/ClaimsAuthorization to make the claims authorization manager pickup the more complicated rules.
A good link on implementing claims based authentication in MVC 4 is available here:
http://dotnetcodr.com/2013/02/25/claims-based-authentication-in-mvc4-with-net4-5-c-part-1-claims-transformation/

Session maintenance in cloud application ASP.Net MVC

I am developing a web application on ASP.Net MVC 4 with razor syntax. I have to deploy it on cloud, probably on Azure.
I am quiet confused about the login scheme of MVC. We have to work on multiple schemas so thats why we aren't using the membership provided by ASP.Net.
I know session maintenance and i used it in web forms but session have some serious issues with cloud.
What would be the best method to save usernames and session data?
I would avoid using the Session State to store user information or even session data, because this makes your application less scalable.
If you want to store a username, displayname, email address, ... I would suggest Claims Based authentication. Brock Allen wrote a great introduction article to get you started: Replacing forms authentication with WIF’s session authentication module (SAM) to enable claims aware identity.
The main idea is that you hand out a cookie (just like with Forms Authentication):
Claim[] claims = LoadClaimsForUser(username);
var id = new ClaimsIdentity(claims, "Forms");
var cp = new ClaimsPrincipal(id);
var token = new SessionSecurityToken(cp);
var sam = FederatedAuthentication.SessionAuthenticationModule;
sam.WriteSessionTokenToCookie(token);
And this cookie represents a ClaimIdentity which can contain one or more claims like email address etc...
private Claim[] LoadClaimsForUser(string username) {
var claims = new Claim[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Email, "username#company.com"),
new Claim(ClaimTypes.Role, "RoleA"),
new Claim(ClaimTypes.Role, "RoleB"),
new Claim(OfficeLocationClaimType, "5W-A1"),
};
return claims; }
In terms of session data you might want to consider Windows Azure In-Role Caching or the Windows Azure Caching Service. There's even a Session State Provider which can store the session state in cache: http://msdn.microsoft.com/en-us/library/windowsazure/gg185668.aspx.
But you can easily do this yourself without using the session state by playing with the cache keys, like this:
myCache.Put(user.Id + "_Friends", friendsList);

Resources