Where to keep data about an authenticated user? - authentication

I am still pretty new to ASP.NET Web API. I am currently working on the authentication part of a new application based on Web API, which is developed using some libraries/kinda framework of the company.
There is already some MVC application - they are using forms based authentication and they are not using the IPrincipal to store information about the user, rather a unity based approach, keeping data in a custom IUser object (basically kept on the session).
The Web API application is going to be stateless (no session), just that I am going to add some user related information in the authentication cookie (retrieved per request in the Application_PostAuthenticateRequest).
I am a bit undecided to keep this user related data in a custom implementation of IPrincipal (as I noticed to be a practice) or use the current approach of other applications in the company utilizing an IUser - served by Unity, using a per request lifetime manager.
Which do you consider to be the better approach?

If you're keeping track of Users per session, try using Singleton classes, if you're about to make a log of the users that entered the session, write it down in a textfile like a whitelist.

Related

What is the best way to implement different User Roles/Permissions depending on "Project"?

Our current API leverages ASP.Net Identity and Policy Based permissions for Authorization. It uses User Roles as claims for this. These claims are intercepted by a ClaimsTransformer class and the user permissions are read from a database containing the user mappings (cached). This all works fine.
The problem I'm having is with the API's scope expanding to include different "Projects", such that for instance, a User can be a Creator in one project but a Consumer in another. Is there a way to reconcile these requirements with .NET Core's Role/Policy based Authorization? Or is the best approach here to query the Database for these permissions upon each request?
Authorization is hard and a good starting point is to watch this video:
Implementing authorization in web applications and APIs.
Then using the policies and requirements is how I would approach this and this resource is a good reference:
Custom authorisation policies and requirements in ASP.NET Core
The picture below shows how the concept of requirements work in ASP.Net Core where you can define a requirement and then have one or many handlers independently "vote" if the user is approved or not.

Unifying auth between a Blazor Server UI and an (effectively external) API

I've a situation where I'm creating a Blazor Server front end for an API, and that API may also be used directly by some other systems. Essentially some smaller customers might use the UI, others (perhaps larger with their own dev team) build their own UI and use the API. We control both sets of code (for the Blazor and the API).
Auth in the api is done (at the moment) by sending a userid and a password and getting a JWT Bearer token that is added to all subsequent requests.
Auth on the BS app is (at the moment) done using Azure AD B2C; the templating in VS makes it an easy setup and then no really specialist knowledge is needed to maintain and add new users
There isn't any special link between the two for now; both are in dev and the BS app just has a hard coded u/p for a single dev user inthe API side. At some point that needs to change so the API serves more than one customer via the UI
It seems I have a couple of routes I could go down:
Make the BS app use the API for auth; in my mind this looks like setting up something similar to what you get when you make a new BS app with "Individual Accounts" auth, except it doesn't use EF on a database with tables for tracking identity - it would probably use a custom store and usermanager that asks the API for auth instead of some DB, and then some (hopefully simple) mechanism of getting the returned token from the API into every httpclient that ends up being used to poke the API (they're abstracted away into proxies built by NSwag but it's easy enough to address because NSwag code calls a particular overridable method to setup the headers.. finding a way to have the httpclientfactory do it might be even easier)
Make the BS app and the API use AD B2C for auth. As a workflow I genuinely have no idea how that's done or what it looks like.
Of the two I'd prefer the latter because it hands off some additional responsibility to AD, such as maybe in future we want to have UI customers also do 2FA but I'm not really sure how to go about researching it. How do we go about sharing auth between the two systems?
I'm not looking for code; some rudimentary instructions on how to share the authenticated identity between the BS app and the API is really what I need. If it's not an achievable goal, what alternative mechanism for Blazor Server do I have that would allow easy sharing of a retrieved bearer across a everything the user might do in a "session" (I don't mind if they lose SignalR connection and have to log in again)?
If either of the approaches above look like I'm just making life hard work, and it should be done another way, an outline of the steps required to make it go would be ideal

How should I implement user authentication/roles for an Electron desktop app?

I'm designing the architecture for a college project and I don't know how to deal with the user authentication and authorization part of it. The project is a desktop Electron app which would need two types (hence the roles) of users. They both need to be authenticated in order to use the app, and depending on their identity, they will have different authorizations. Since the project is meant to be used by teachers and students as part of a laboratory class after it is done, I don't think more than 30 people will be using it at the same time.
My first thought was using a PostrgeSQL database in AWS for this and implementing the authentication myself, but this means that users will have to sign up and create a new profile, which means remembering yet another <username/email, password>. Trying to avoid this, I read a bit about OAuth 2.0 and OIDC, and how it can be used to authenticate and authorize users without implementing either of those tasks oneself, but rather delegating the task to OIDC. I created a free account with Auth0 and thought about using it for the OIDC integration but after reading about 40 pages of an "OIDC integration handbook" they offer for free, I could not know if I would be able to distinguish my user base through these roles or tags as I mentioned. I just followed the steps in the tutorial handbook and tried to understand how the auth flow worked, but that didn't give me any information on my question.
So all in all what I want to know is: is it possible to implement this with Auth0 (free account) without having to use a third-party database solution (such as PostgreSQL with AWS)? If not, what would you recommend me to look into? Preferrably a solution that will let me discriminate between the two types of users BUT at the same time taking advantage of the OIDC implementation of Google for example.
There are 2 separate solutions here:
DESKTOP AUTHENTICATION
The 2 standard requirements are:
Use Authorization Code Flow (PKCE)
Login via System Browser
You listen for a login response via one of these mechanisms (I prefer the latter):
Loopback web server
Private URI scheme OS notification
My blog has some tutorials + code samples that use Electron. You can run both of the above listening options and see what you prefer.
API AUTHORIZATION WITH ROLES
You need to make roles available to the API via claims. This can be done by either of these mechanisms (I prefer the latter):
Including roles in access tokens via Auth0
Get the API to read user roles from its own database
My Authorization blog post discusses building up a claims object in an easy to extend way. The main objective is usually for API OAuth processing to result in an object something like this:
class UserPrincipal {
// The technical user id from the access token
string sub;
// The user id from your own database
string userId;
// The user's roles
string[] roles;
}
Given that object you can do things like this:
Use role based authorization when needed
Serve up user resources after login from your application data
TO SUMMARISE
Auth0 will meet some of your requirements and may be all you need in the early days. You will probably need to manage non OAuth user data in your API at some point though.
Happy to answer any follow up questions ..

Associating clients with users

I'm attempting to build an ASP.NET Core API with authentication/authorization handled by IdentityServer4. IdentityServer4 is being backed by both Identity and Entity Framework Core. My goal is a fairly standard and familiar set up, where users can login into a API developer portal where they can add "applications" (clients) and have a client id and client secret generated that they can then use to access the API, similar to how Facebook, Google, etc. handle API access.
My mental block is coming with the way IdentityServer handles Entity Framework integration. Their entities are attached to two different contexts, ConfigurationDbContext and PersistedGrantDbContext. I'm at a loss for a good way to associate one or more Client entities from IdentityServer4.EntityFramework with one or more ApplicationUser entities from my Identity context.
This seems like it would be a fairly common usage scenario, but the documentation is strangely silent on it. I've also been unable to find anything online after various and sundry searches. I'm hoping someone else has needed this same setup and can give me some advice on how to proceed.
There is no association between users and clients. IdentityServer authenticates users regardless of which client they are trying to access.
If you want to implement something like "which user is allowed to use which client" semantics, that is beyond authentication. This is typically implemented in the application itself since this is application specific logic.
https://leastprivilege.com/2017/07/10/authorization-is-hard-slides-and-video-from-ndc-oslo-2017/

ASP Net MVC Core - Load User Data From Active Directory when User browses Any Page

Here is my development environment:
Intranet Website
Active Directory Authentication/Authorization
Asp Net Core
I am trying to get the data stored in Active Directory attributes when a user enters firstly to any page in our application. All users rights and permissions, employeeid, studentid, etc.... are stored in AD Attributes and Security Groups. Some Attributes need to be displayed on the website too.
Let's say my website got the following urls...
http://mysite/Home/Index
http://mysite/Student/Index
http://mysite/Student/MyJobs
http://mysite/Staff/Applications
etc....
Any users can go onto some areas/urls of the website freely from other Intranet portals and I don't know where should I write the code to fulfill that criteria. The problem is that, there is no specific entry point to the application like http://mysite/Login or Authenticate, etc. If there is, I could load all users details and rights from AD on that single entry point.
In MVC5 era, I used Custom Global Authorize Attribute and put it on the BaseController is inherited from all other controllers to load that AD data. I put the AD's data into Session on the first hit and use the Static Class to display on Views and use in Controllers. But when I did some research in MVC Core, some say that it's outdated and I should use the Authorize Policy instead of custom Authorize Attributes.
Getting the data from Active Directory is already achieved by using my old webservices and we don't need to worry about .Net core not supporting AD yet.
I looked at the tutorials about Policy and saw something about Claims and Custom User Managers. I couldn't decide which one I should use to load data from Active Directory to the object (probably Scoped Object DI) which lasts for the whole user's session.
Should I load the data onto claims attributes
Eg...
var claims = new List<Claim>();
claims.Add(new Claim("UserName", "John.Smith", ClaimValueTypes.String, Issuer));
claims.Add(new Claim("RefNo", "02343001", ClaimValueTypes.String, Issuer));
claims.Add(new Claim("Email", "MyEmail#email.com", ClaimValueTypes.String, Issuer));
Or Should I write customized SignInManager and IdentityUser?
Eg...
public class ApplicationUser : IdentityUser
{
public string RefNo { get; set; }
public string Email { get; set; }
}
Is there anywhere I could put my code to check AD and load data?
And should I store the data in that Claimed Object rather than using Session Data?
Could you guys please advise me? Feel free to criticize if I miss anything and my idea is not working.
You're right in saying there's no System.DirectoryServices yet (it's on the backlog, I promise) so there are a couple of places to do this.
If you're already using Integrated Authentication you have SIDs for group membership, which are resolved when you call IsInRole(), so you can use role based membership (rather than Claims based) to solve basic authentication problems.
However if you want to support a forms based mechanism then you should look at using the cookie middleware, raw, to at least give you a simple login, calling your web service to validate your login. You could query your API in the controller code, and write an identity cookie. This cookie automatically encrypted and signed, so it can't be tampered with.
The problem comes when you want roles, and attributes. If you head down the cookie route you might be tempted to put all of those as claims in the identity before writing the identity out as a cookie. This might work, provided there are not too many - cookies have a maximum size (browser dependent, but under 4k usually). You can used chunked cookies, but there's a performance impact here. Instead you might use a reference cookie, where you put in a reference to another store where the actual fully populated identity is stored, be it session, redis or something else.
Then in the claims transformation middleware you can pull the reference out, go to your store, and rehydrate the identity.
I'd honestly avoid trying to merge all of this into ASP.NET Identity. That's mean to be the sole source for user information in an application, and in your case that's not true. Your sole source should be AD.
There's also a port of Novell's ldap library to core, which should stand in nicely for DirectoryServices should you want to avoid your web services approach.