ASP.NET Core with optional authentication/authorization - c#

I want to build an ASP.NET Core based WebApi for accessing data from a database. This WebApi could be used in two ways, either as a public WebApi which would need authentication or as a private backend service for a web application. In the latter case there would be no need for authentication since only authenticated users can access the web application and both web application and WebApi will run on the same computer, the WebApi will be hidden to the outside.
Since we need authentication for the first scenario, I will have all public APIs tagged with the Authorize attribute. But for the private scenario I would like to bypass any authentication.
Is there any way I could make authentication optional depending on some flag in the configuration?
Update
speaking of two usage scenarios I mean two completely separate installations! Each one has its own configuration file. The decision whether authentication is needed is to made per installation not per request in a single installation! My goal is to have just one code base and a switch in the configuration.

If you bypass authentication, how do you distinguish internal or public requests for api? This causes security bug. So you shouldn't bypass authentication.
If you use openidconnect authentication in mvc application then you can set SaveTokens=true. It enables you to store access token in cookie. When you call api in mvc action you can send this access_token to api.
Another way using two different authentication middleware, one for internal another for public access(This is hard to implement).
I would go with first approach.
Update
To achieve your goal, a tricky way is coming to my mind but i am not sure it is good way:
Create a filter provider:
public class EncFilterProvider : IFilterProvider
{
public int Order
{
get
{
return -1500;
}
}
public void OnProvidersExecuted(FilterProviderContext context)
{
}
public void OnProvidersExecuting(FilterProviderContext context)
{
// remove authorize filters
var authFilters = context.Results.Where(x =>
x.Descriptor.Filter.GetType() == typeof(AuthorizeFilter)).ToList();
foreach(var f in authFilters)
context.Results.Remove(f);
}
}
Then register it conditionally based on config value
public void ConfigureServices(IServiceCollection services)
{
if(config["servermode"] = "internal")
{
services.AddScoped<IFilterProvider, EncFilterProvider>();
}
}

I would recommend to authenticate both applications: web application and the Web API one. You will have everything secured.
For skipping an authentication that is not a good idea. Simply create an user for your web application (in the Web API application) which will be used to authenticate when getting data from the Web API.

Related

How to write injectable reusable code instead of hardcoding the authentication on every method

I have a webapi which talks with Sharepoint to do tenant level operations, like listing site collections, creating sites, etc etc.
The web api methods works perfect, but however the authentication mechanism might change in the future, now the only way to create a modern site collection is via authenticated user and password, in the future they might enable app only authentication to create modern sites: https://sharepoint.uservoice.com/forums/329220-sharepoint-dev-platform/suggestions/34236700-ability-to-use-app-only-calls-to-create-modern-sit
The problem with my code, its that I have hardcoded the authentication line in every method of the webapi, and I would like to abstract that line in a way outside of the webapi class, that whenever Microsoft implements a different authentication mechanism, that I can easily change that class and not the web api methods one by one.
[HttpPost]
[Route("")]
//[Route("api/SiteCollections/CreateModernSite")]
public async Task<IHttpActionResult> CreateModernSite([FromBody]NewSiteInformation model)
{
if (ModelState.IsValid)
{
var tenant = await TenantHelper.GetTenantAsync();
using (var context = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant("https://xxx.sharepoint.com/sites/tesmmodernsite1", "xxx#xxx.onmicrosoft.com", "xxx"))
{
try
{

IdentityServer4 - Using External Authentication

I am trying to implement an Authorization server using IdentityServer4, using the Hybrid Flow.
let's say url is : auth.company.com
To authenticate users, the company uses a simple .NET MVC login/password form.
url : client.company.com/login.html
My question is : how can i plug the authentication system into the IdentityServer4 ?
I've tried adding this :
Startup.cs / ConfigureServices()
services.AddIdentityServer(SetupIdentityServer)
private static void SetupIdentityServer(IdentityServerOptions options)
{
options.UserInteraction.LoginUrl = #"client.company.com/login.html";
options.UserInteraction.LoginReturnUrlParameter = "referrer";
}
But it resulted in too many redirections error between auth server and authentication server
Thank you
I just replied to another question very similar to this so this is a shameless copy and paste of that:
This will not work as the identity server needs to issue its own cookie once authentication has taken place. This cookie is what allows the authorise endpoint to know who is signed in.
The intention of this model is that authentication takes place on the IDP or it’s negotiated with an external provider via a suitable protocol. Therefore the appropriate approach in this case is to move the login UI into your identity server application. It’s entirely up to you exactly how that is done and where it gets it’s data from but it must be your identityserver4 that issues the cookie.

Add token authentication for webApi controller to existing asp.net MVC 5 application

I currently have a Web API controller added to an existing MVC 5 project (not using .net core) and I was able to successfully create and get data from the controller that I have set up. The purpose of the API is to pass data between it and a mobile application that uses the same data source that the MVC project uses (I will also be calling existing methods in the project from the API so I would prefer the API exist in the MVC project). I am now looking for a way to add token authentication to the API, as I only want logged in users in the mobile application to be allowed to access the API. How can I achieve this?
The simplest solution should be to use the Token Validation Middleware from the IdentityServer 3 suite.Just add the nuget package and configure your application following the doc:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// turn off any default mapping on the JWT handler
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://localhost:44333/core",
RequiredScopes = new[] { "api1" }
});
app.UseWebApi(WebApiConfig.Register());
}
}
It's ok to set app.UseIdentityServerBearerTokenAuthentication() only prior to app.UseCookieAuthentication() and app.UseOpenIdConnectAuthentication() and call GlobalConfiguration.Configure(WebApiConfig.Register) in Global.asaxSuch approach allows to combine token and cookie-based auth in one MVC application.The only problem for today is that IdentityServer 3 family tools are frozen and support System.IdentityModel 4 and OWIN 3 only, so
update:
The preferred solution for ASP.NET 4.6+ becomes IdentityServer3.Contrib.AccessTokenValidation -- a fork, refactored according to the recent framework changes.

Stateless authentication with NancyFx, OWIN and JWT

I have a OWIN self-hosted application which has a front-end where users can sign up. Nancyfx does the logic for routing and Models, and in the documentation I saw that Nancyfx comes with 3 types of authentication.
Forms (Nancy.Authentication.Forms)
Basic (Nancy.Authentication.Basic)
Stateless (Nancy.Authentication.Stateless)
I've settled on the Stateless Authentication, and following this example I tried to set up a basic form of authentication.
I wanted to expand further on this, using JWT to have some basic info handy and as a form of basic authentication (e.g. client has token so he's verified.), but this is where I run into a few problems.
The way I authenticate Home -> login -> redirect upon success causes my Response.Header.Authorization to be cleared, not allowing me to catch the token in my custom Bootstrapper.
Code:
protected override void RequestStartup(TinyIoCContainer requestContainer, IPipelines pipelines, NancyContext context)
{
AllowAccessToConsumingSite(pipelines);
StatelessAuthentication.Enable(pipelines, requestContainer.Resolve<IStatelessAuthConfigurationFactory>().Config());
}
//Returns ClaimsPrincipal or Null;
public StatelessAuthenticationConfiguration Config()
{
if(_stat == null)
{
_stat = new StatelessAuthenticationConfiguration(VerifyToken);
}
return _stat;
}
Since my authorization header disappears every request, I would need to persist the JWT. I figure it's possible using OWIN environment or Nancy context, but would this be advisable + what would the effect be for a multi-user environment regarding security.
OWIN has it's own authentication Manager that I could use, I've experimented with it, but it tends to provide a cookie upon successful sign in, which it doesn't seem to revoke on Logout. I just ran into a few issues overall with it, so I settled on NancyFx authentication. (not really a problem as a more general remark I suppose)
Thanks in advance for any help!
Regarding (1), if you roll your own redirection after a successful login, consider setting the Authorization header during the redirect, e.g.
return Response.AsRedirect("/").WithHeader("Authorization", token);
It's actually the responsibility of the client to hold the valid JWT token after authentication. Returning it as a cookie (and deleting it upon logout) could make things easier in terms of client-side implementation and avoid the token persistence issue.
Regarding (2), not really, it's not necessary. JWT tokens are self-contained, and that's why they're useful in stateless auth scenarios.

.NET Core Identity Server 4 Authentication VS Identity Authentication

I'm trying to understand the proper way to do authentication in ASP.NET Core. I've looked at several Resource (Most of which are out dated).
Simple-Implementation-Of-Microsoft-Identity
Introduction to Authentication with ASP.Core
MSDNs Introduction to Identity
Some people provide altenative solutions stating to use a cloud based solution such as Azure AD, or to Use IdentityServer4 and host my own Token Server.
In Older version Of .Net one of the simpler forms of authentication would be to create an Custom Iprinciple and store additional authentication user data inside.
public interface ICustomPrincipal : System.Security.Principal.IPrincipal
{
string FirstName { get; set; }
string LastName { get; set; }
}
public class CustomPrincipal : ICustomPrincipal
{
public IIdentity Identity { get; private set; }
public CustomPrincipal(string username)
{
this.Identity = new GenericIdentity(username);
}
public bool IsInRole(string role)
{
return Identity != null && Identity.IsAuthenticated &&
!string.IsNullOrWhiteSpace(role) && Roles.IsUserInRole(Identity.Name, role);
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
}
public class CustomPrincipalSerializedModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then you would Serialize your data into a cookie and return it back to the client.
public void CreateAuthenticationTicket(string username) {
var authUser = Repository.Find(u => u.Username == username);
CustomPrincipalSerializedModel serializeModel = new CustomPrincipalSerializedModel();
serializeModel.FirstName = authUser.FirstName;
serializeModel.LastName = authUser.LastName;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(serializeModel);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,username,DateTime.Now,DateTime.Now.AddHours(8),false,userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
}
My questions are:
How can I authenticate similar to the way done in previous version's of .Net does the old way still work or is there a newer version.
What are the pros and cons of using your own token server verses creating your own custom principle?
When using a cloud based solution or a separate Token server how would you Integrate that with your current application, would I would still need a users table in my application how would you associate the two?
Being that there are so many different solutions how can I create an enterprise application, to allow Login through Gmail/Facebook while still being able to expand to other SSO's
What are some simple implementations of these technologies?
TL;DR
IdentityServer = token encryption and validation services via OAuth 2.0/OpenId-Connect
ASP.NET Identity = current Identity Management strategy in ASP.NET
How can I authenticate similar to the way done in previous version's of .Net does the old way still work or is there a newer version.
I see no reason why you couldn't achieve the old way in ASP.NET Core, but in general, that strategy was replaced with ASP.NET Identity, and ASP.NET Identity is alive and well in ASP.NET Core.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity
ASP.NET Identity uses a backing store like SQL Server to hold user information like username, password (hashed), email, phone and easily be extended to hold FirstName, LastName or whatever else. So, there really no reason to encrypt user information into a cookie and pass it back and forth from client to server. It supports notions like user claims, user tokens, user roles, and external logins. Here are the entities in ASP.NET Identity:
AspNetUsers
AspNetUserRoles
AspNetUserClaims
AspNetUserLogins (for linking external identity providers, like Google, AAD)
AspNetUserTokens (for storing things like access_tokens and refresh_tokens amassed by the user)
What are the pros and cons of using your own token server verses creating your own custom principle?
A token server would be a system that generates a simple data structure containing Authorization and/or Authentication information. Authorization usually takes the for of a token named access_token. This would be the "keys to the house", so to speak, letting you through the doorway and into the residence of a protected resource, usually a web api. For Authentication, the id_token contains a unique identifier for a user/person. While it is common to put such an identifier in the access_token, there is now a dedicated protocol for doing that: OpenID-Connect.
The reason to have your own Security Token Service (STS), would to be to safeguard your information assets, via cryptography, and control which clients (applications) can access those resources. Furthermore, the standards for identity controls now exist in OpenID-Connect specifications. IdentityServer is an example of a OAuth 2.0 Authorization Server combined with an OpenID-Connect Authentication server.
But none of this is necessary if you just want a user table in your application. You don't need a token server- just use ASP.NET Identity. ASP.NET Identity maps your User to a ClaimsIdentity object on the server- no need for a custom IPrincipal class.
When using a cloud based solution or a separate Token server how would you Integrate that with your current application, would I would still need a users table in my application how would you associate the two?
See these tutorials for integrating separate identity solutions with an application:
https://identityserver4.readthedocs.io/en/latest/quickstarts/0_overview.html
https://auth0.com/docs/quickstart/webapp/aspnet-core
At a minimum you would need a two column table mapping the username to the external provider's user identifier. This is what the AspNetUserLogins table does in ASP.NET Identity. The rows in that table however are dependent on the being a User record in AspNetUsers.
ASP.NET Identity supports external providers like Google, Microsoft, Facebook, any OpenID-Connect provider, Azure AD are already there. (Google and Microsoft have already implemented the OpenID-Connect protocol so you don't need their custom integration packages either, like this one, for example). Also, ADFS is not yet available on ASP.NET Core Identity.
See this doc to get started with external providers in ASP.NET Identity:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/
Being that there are so many different solutions how can I create an enterprise application, to allow Login through Gmail/Facebook while still being able to expand to other SSO's
As explained above, ASP.NET Identity already does this. It's fairly easy to create an "External Providers" table and data drive your external login process. So when a new "SSO" comes along, just add a new row with the properties like the provider's url, the client id and secret they give you. ASP.NET Identity already has the UI built in there Visual Studio templates, but see Social Login for cooler buttons.
Summary
If you just need a users table with password sign in capabilities and a user profile, then ASP.NET Identity is perfect. No need to involve external authorities. But, if have many applications needing to access many apis, then an independent authority to secure and validate identity and access tokens makes sense. IdentityServer is a good fit, or see openiddict-core, or Auth0 for a cloud solution.
My apologies is this isn't hitting the mark or if it is too introductory. Please feel free to interact to get to the bulls-eye you are looking for.
Addendum: Cookie Authentication
To do bare bones authentication with cookies, follow these steps. But, to my knowledge a custom claims principal is not supported. To achieve the same effect, utilize the Claims list of the ClaimPrincipal object.
Create a new ASP.NET Core 1.1 Web Application in Visual Studio 2015/2017 choosing "No Authentication" in the dialog. Then add package:
Microsoft.AspNetCore.Authentication.Cookies
Under the Configure method in Startup.cs place this (before app.UseMvc):
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "MyCookieMiddlewareInstance",
LoginPath = new PathString("/Controller/Login/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
Then build a login ui and post the html Form to an Action Method like this:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(String username, String password, String returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// check user's password hash in database
// retrieve user info
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username),
new Claim("FirstName", "Alice"),
new Claim("LastName", "Smith")
};
var identity = new ClaimsIdentity(claims, "Password");
var principal = new ClaimsPrincipal(identity);
await HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal);
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError(String.Empty, "Invalid login attempt.");
return View();
}
The HttpContext.User object should have your custom claims and are easily retrievable the List collection of the ClaimPrincipal.
I hope this suffices, as a full Solution/Project seems a bit much for a StackOverflow post.
TL;DR
I would really like to Show A Full posting on how to properly implement IdentityServer4 but I tried to fit All of the Text in but it was beyond the limit of what StackOverflow Accepts so instead I will right some tips and things I've learned.
What are the Benefits of using a Token Server Vs ASP Identity?
A token server, has a lot of benefit's but it isn't right for everyone. If you are implementing an enterprise like solution, where you want multiple client to be able to login, Token server is your best bet, but if you just making a simple website that want to support External Logins, You can get Away With ASP Identity and some Middleware.
Identity Server 4 Tips
Identity server 4 is pretty well documented compared to a lot of other frameworks I've seen but it's hard to start from scratch and see the whole picture.
My first mistak was trying to use OAuth as authentication, Yes, there are ways to do so but OAuth is for Authorization not authentication, if you want to Authenticate use OpenIdConnect (OIDC)
In my case I wanted to create A javascript client, who connects to a web api.
I looked at a lot of the solutions, but initially I tried to use the the webapi to call the Authenticate against Identity Server and was just going to have that token persist because it was verified against the server. That flow potentially can work but It has a lot of flaws.
Finally the proper flow when I found the Javascript Client sample I got the right flow. You Client logs in, and sets a token. Then you have your web api consume the OIdc Client, which will verify your access token against IdentityServer.
Connecting to Stores and Migrations
I had a lot of a few misconceptions with migrations at first. I was under the impression that running a migration Generated the SQL from the dll internally, instead of using you're configured Context to figure out how to create the SQL.
There are two syntaxes for Migrations knowing which one your computer uses is important:
dotnet ef migrations add InitialIdentityServerMigration -c ApplicationDbContext
Add-Migration InitialIdentityServerDbMigration -c ApplicationDbContext
I think the parameter after the Migration is the name, why you need a name I'm not sure, the ApplicationDbContext is a Code-First DbContext in which you want to create.
Migrations use some auto-magic to find you're Connection string from how your start up is configured, I just assumed it used a connection from the Server Explorer.
If you have multiple projects make sure you have the project with the ApplicationDbContext set as your start up.
There is a lot of moving parts when Implementing Authorization and Authentication, Hopefully, this post helps someone. The easiest way to full understand authentications is to pick apart their examples to piece everything together and make sure your read the documentation
ASP.NET Identity - this is the build in a way to authenticate your application whether it is Bearer or Basic Authentication, It gives us the readymade code to perform User registration, login, change the password and all.
Now consider we have 10 different applications and it is not feasible to do the same thing in all 10 apps. that very fragile and very bad practice.
to resolve this issue what we can able to do is centralize our Authentication and authorization so whenever any change with this will not affect all our 10 apps.
The identity server provides you the capability to do the same. we can create one sample web app which just used as Identity service and it will validate your user and provide s some JWT access token.
I have always used the built in ASP.NET Identity (and previously Membership) authorisation/authentication, I have implemented Auth0 recently (https://auth0.com) and recommend this as something else to try.
Social logins are not hard to implement with Identity, but there is some initial setup involved and sometimes the steps you find online in the docs are not identical, usually you can find help for that under the developers section of the platform you are trying to setup the social logins for. Identity is the replacement of the old membership functionality found in legacy versions of the .net framework.What I have found surprising is that edge use cases, like passing a jwt token you already have to a web api are not covered anywhere in the examples online even on pluralsight, I am sure you don't need your own token authority to do this but I have not found a single example on how to pass data in a get or post that isn't dealing with a self-hosted server.

Categories