CookiePolicyOptions or CookieAuthenticationOptions? - authentication

I'm just starting to get my mind wrapped around some of the .NetCore Identity stuff. However, there are a few things that I'm still a bit confused on. In some examples I've seen things like this:
services.AddAuthentication("mycookie")
.AddCookie("mycookie", options =>
{
options.Cookie.HttpOnly = true,
...
});
services.Configure<CookiePolicyOptions>(options =>
{
options.HttpOnly = true;
...
});
Is CookiePolicyOptions configuring the defaults and the CookieAuthorizationOptions of AddCookie overriding the default for that particular cookie?
Also, does the CookiePolicy configuration in the previous example services.Configure<CookiePolicyOptions> have any effect if there is no Cookie Middleware added in Configure? (i.e. app.UseCookiePolicy();)
Lastly, if you set up a Cookie Authentication Scheme (as shown in the code snippet), do you need both app.UseCookiePolicy() and app.UseAuthentication() middleware?

The use of cookie authentication in .net core is not itself the Identity membership system, rather a component that could be used as a standalone Authentication means or set up as part of a broader Identity configuration.
Identity -> Namespace: Microsoft.AspNetCore.Identity
CookieAuthentication -> Microsoft.AspNetCore.Authentication.Cookies
Identity: CookieConfiguration in Identity is an extension config method of the service Collection
CookieAuth: CookiePolicyOptions provides programmatic configuration for the CookiePolicyMiddleware.
services.Configure<CookiePolicyOptions>(options =>
{
options.HttpOnly = true;
...
});
This part is a set up of the Cookie policy in terms of privacy, GDPR(for Europe) and other policies.
The other part provides means to set up cookies in terms of authorization policy of your application:
services.AddAuthentication("mycookie")
.AddCookie("mycookie", options =>
{
options.Cookie.HttpOnly = true,
...
});
Unfortunately this is all I have as information. I hope more people can add some deeper understanding of the topic.
EDIT - 2022:
A more comprehensive article : https://www.reddit.com/r/dotnet/comments/we9qx8/a_comprehensive_overview_of_authentication_in/

Related

Can we have both OAuth and Certificate authentication in ASP .NET Core 5?

Currently, we have a working OAuth authentication for our ASP.NET Core 5 Web API. We would like to add a certificate authentication as well to be double sure of our caller. Is there a way to have both of them? I tried the below code but it overrides one over the other.
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
.AddAzureADBearer(options =>
{
options.Instance = aADInstance;
options.ClientId = clientIdWithScope;
options.Domain = aADDomain;
options.TenantId = aADTenantId;
}
)
services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate();
Changing default policy
// Add authentication schemes before, we already did this, so I would skip this part
// Change default Authorization policy
services.AddAuthorization(cfg =>
cfg.DefaultPolicy =
new AuthorizationPolicyBuilder(CertificateAuthenticationDefaults.AuthenticationScheme,
AzureADDefaults.JwtBearerAuthenticationScheme).RequireAuthenticatedUser().Build());
[Authorize] attribute now would require all http request to satisfied both CertificateAuthenticationDefaults.AuthenticationScheme and AzureADDefaults.JwtBearerAuthenticationScheme, that might be not the behavior we want for all of our endpoint, so, be careful with this approach.
Add our own policy
// Add authentication schemes before, we already did this, so I would skip this part
// Adding our own policy
services.AddAuthorization(options =>
{
options.AddPolicy("ComposedPolicy", p =>
{
p.AuthenticationSchemes = new List<string>
{CertificateAuthenticationDefaults.AuthenticationScheme, AzureADDefaults.JwtBearerAuthenticationScheme};
p.RequireAuthenticatedUser();
p.Build();
});
});
[Authorize] attribute behavior now would be untouch, but whenever we want to use our custom policy, we must specify them by [Authorize(Policy = "ComposedPolicy")].
Just choose the approach that suit the best.

Implementing roles with custom storage provider for Identity

Recently, I was able to successfully implement authentication (SSO with ADFS using WS-Federation) for an app. Now, I am trying to understand and get authorization working, so this question may be unclear.
I'm using this topic to implement roles with custom storage provider for Identity without entity framework.
I've got custom User and Role models set up, along with the custom UserStore and RoleStore that implement the appropriate interfaces. There's also tables for roles ready to be used.
I run into issues when trying to access either an [Authorized] or [Authorized(Roles = "RoleName")]. As expected, the actions require me to authenticate with ADFS, but when I submit correct credentials the login loops a few times and displays the ADFS error page. This problem with ADFS is not present without the role implementation. UserStore and RoleStore does not implement code yet, but the app never tries uses any of their methods.
I tried implementing different options in Startup.cs, some of which I have commented out, and reordering services. Inserting dummy code into the RoleStore didn't help either. Basically, I just want to be able to add role checks from custom storage using Identity. I can get the username of the user at any time after they log in to find their role.
Startup.cs ConfigureServices method is where it's most unclear for me, and probably the most likely place where something is set up incorrectly.
Startup.cs ConfigureServices():
public void ConfigureServices(IServiceCollection services)
{
// Add identity types
services.AddIdentity<User, Role>()
//.AddUserManager<UserManager<User>>() // some other settings I've tried ...
//.AddRoleManager<RoleManager<Role>>()
//.AddUserStore<UserStore>()
//.AddRoleStore<RoleStore>()
//.AddRoles<Role>()
.AddDefaultTokenProviders();
// Identity Services
services.AddTransient<IUserStore<User>, UserStore>();
services.AddTransient<IRoleStore<Role>, RoleStore>();
//for SQL connection, I'll be using a different one (not the one from the link to topic)
//dependency injection
services.AddScoped<ISomeService, SomeService>();
services.AddAuthentication(sharedOptions =>
{
// authentication options...
})
.AddWsFederation(options =>
{
// wsfed options...
})
.AddCookie(options =>
{
options.Cookie.Name = "NameOfCookie";
//options.LoginPath = "/Access/Login"; //app function the same without this
options.LogoutPath = "/Access/Logout";
options.AccessDeniedPath = "/Access/AccessDenied";
options.ExpireTimeSpan = TimeSpan.FromMinutes(120);
options.SlidingExpiration = true;
});
services.AddControllersWithViews();
}
Another way of doing this is to add a custom attribute store to ADFS.
Then the roles etc. that you require from the custom attribute store can be configured as claims.

Require all policies by default in Api Controllers

I don't know if this may sound stupid, but I'm a bit worried about how authorization is done in Controllers.
Right now I'm using [Authorize] attribute to secure my end points. But, I'm a bit worried I forget to add a policy and anyone could access the end point.
Is there any way to apply all policies by default and just add an attribute forthe ones you want to allow?
In Asp.Net Core 2.x you can use a filter to set a global Authorization Attribute:
services.AddMvc(options =>
{
// This requires an authenticated user for all controllers/actions,
// except when at controller/action the [AllowAnonymous] attribute is set.
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
// In the same way you can set a global AntiforgeryToken
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
In Asp.Net core 3.x endpoint routing is introduced. When enabled you can set this per endpoint, as described in the migration documentation:
services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
with possible endpoint configuration:
app.UseEndpoints(endpoints =>
{
// equivalent of [Authorize] attribute on each controller:
endpoints.MapDefaultControllerRoute().RequireAuthorization();
});
Not asked, but recommended: Automatically validate antiforgery tokens for unsafe HTTP methods only.

AspNetCore use cookie and bearer together, and make Authorize attribute to use both by default

I have application where its using Cookie and Bearer token. Since i dont want update each Authorize by providing a schemas I did rewrite default schemas:
services
.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(OAuthValidationDefaults.AuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme,
"Identity.Application")
.RequireAuthenticatedUser()
.Build();
});
services.AddAuthentication()
.AddExternalAuthProviders(Configuration)
.AddFlymarkOpenIdConnectServer()
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = "/Identity/Account/LogIn";
options.SlidingExpiration = true;
options.Events.OnRedirectToLogin = OnRedirectToLogin;
})
.AddOAuthValidation(OAuthValidationDefaults.AuthenticationScheme,
o=>o.Events.OnCreateTicket = OnCreateTicket);
services.ConfigureApplicationCookie(config =>
{
config.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = OnRedirectToLogin
};
});
I thought that if I add CookieAuthenticationDefaults.AuthenticationScheme then it will work but cookies are not working untill I add Identity.Application
So my question is why its not working or where is constant to use instead of hardcoded string
ASP.NET Core Identity uses its own instances of the cookie authentication handler, magically registered for you when you call services.AddIdentity().
As you figured out, these instances don't use the default scheme name but a name that starts with the Identity. prefix.
In your code, you're basically registering a new cookie handler instance with the default scheme name. But since nothing in your code uses it to issue cookies, it can't validate anything and will always return unauthenticated tickets, which is why it doesn't work until you add the magical Identity.Application, which corresponds to the main cookie handler instance used by ASP.NET Core Identity.
The constant you're looking for is in IdentityConstants.
Note: be extremely careful before adding a default policy that accepts both authentication cookies and bearer tokens, as your app might be vulnerable to CSRF if it doesn't use antiforgery (which is normally the case when developing an API).

JWT Bearer Token Flow

What I want is a method of JWT Generation and JWT Consumption in ASP.NET Core.
No OAuth2 flow, I do have the IdentityServerv3 working with OAuth2 but it is just overkill for a single app accessing an API when I own both sides.
The main source of difficulty I am having is finding out the equivalent of Microsoft.Owin.Security.Jwt in ASP.NET Core. Nothing in this list https://www.myget.org/gallery/aspnetvnext seems to relate. Or is that package actually to stay relevant in with ASP.NET Core?
If you're looking for a (simple) way to generate your own JWT tokens, you should directly use the JwtSecurityTokenHandler. You can find it in the System.IdentityModel.Tokens package on the MyGet repository you mentioned (but the version is a bit old now) or directly on the Azure AD repository, in the System.IdentityModel.Tokens.Jwt package: https://www.myget.org/gallery/azureadwebstacknightly
Of course, using a standard protocol to issue and retrieve your JWT tokens is more than recommended and OAuth2 and OpenID Connect are probably the best candidates for that.
Note that IdentityServer is not the only server that works on ASP.NET 5. I'm personally working on an advanced fork of the OAuth2 authorization server middleware that comes with Katana 3 and that offers a different approach: https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server
app.UseOAuthBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Audience = "http://localhost:54540/",
Authority = "http://localhost:54540/"
});
app.UseOpenIdConnectServer(options =>
{
options.Provider = new AuthorizationProvider();
});
To learn more about this project, I'd recommend reading http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-introduction/.
Feel free to ping me on https://jabbr.net/#/rooms/AspNetCore if you need more information.
I've started using OpenIddict and I think it is exactly what you need.
This is essentially all the configuration I needed:
ConfigureServices:
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddOpenIddictCore<Application>(config => config.UseEntityFramework());
Configure
app.UseOpenIddictCore(builder =>
{
// tell openiddict you're wanting to use jwt tokens
builder.Options.UseJwtTokens();
// NOTE: for dev consumption only! for live, this is not encouraged!
builder.Options.AllowInsecureHttp = true;
builder.Options.ApplicationCanDisplayErrors = true;
});
// use jwt bearer authentication
app.UseJwtBearerAuthentication(options =>
{
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.RequireHttpsMetadata = false;
options.Audience = "http://localhost:58292/";
options.Authority = "http://localhost:58292/";
});
There are one or two other minor things, such as your DbContext needs to derive from OpenIddictContext<ApplicationUser, Application, ApplicationRole, string>.
You can see a full length explanation (including links to the github repo) on this blog post of mine:
http://capesean.co.za/blog/asp-net-5-jwt-tokens/