Use Windows Authentication in combination with a IUserClaimsPrincipalFactory - c#

I want to create a .NET 7 MVC Web Application.
For authentication I want to use Windows and/or Active Directory. There should be no login and passwords. This method should only be used to identify/authenticate a user.
In the next step I want to use a IUserClaimsPrincipalFactory to read all relevant data for the logged in user and store them in Claims.
The IUserClaimsPrincipalFactory should read the data from my database (preferably via Dapper).
One of the things I added in my startup is the following, but it's not even noted during execution.
builder.Services.AddScoped<IUserClaimsPrincipalFactory, MyClaimPrincipalFactory>();
In my iisSettings I have windowsAuthentication set to true and anonymousAuthentication set to false.
I have already looked at some examples of this and implemented them myself.
For example, a new empty MVC project with "Individual Authentication".
Each of them uses a login form with name and password.
There the use of the IUserClaimsPrincipalFactory works. However, I want to avoid the use of passwords. Among other things, I also considered using IClaimsTransformation. However, it seems that these options do not work when using Windows authentication.
Other configurations I have added.
builder.Services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddClaimsPrincipalFactory<MyClaimsFactory>();
builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);
builder.Services.AddAuthentication(IISDefaults.Ntlm);
Can you tell me if this is even possible or am I missing an important part in the configuration? Has anyone already implemented it and can give me an explanation?

Related

Login via API (outside app) and create a cookie for access

Ok so I think I've settled on choosing BLAZOR for my upcoming project. But first I need to do something that is seemingly very basic.
For context, Blazor Server side will be how I interface with my SQL Server dB, I want "individual accounts" mode to be the way users authenticate. I'm using net 6.0,almost all tutorials out there seem to be net 5 since they all still have startup.cs files. Ok, but I also am creating a parallel app that is NOT a website, but I want it to grab data from the same database via routes after authenticating.
For example, website.com/api/data?variablestograb as a GET would send me some json data.
OK that being said, how do I login programmatically from an outside app? If you must know, the outside app is part of Unity C#. But that doesn't matter so much, what itll do is use a post call to login in via the api routes. Something like
Website.com/api/login?un=blah&pw=haha
This will generate a cookie and I can grab it with the session data and I'll use this with every get call hence.
Just using the basic templates, Blazor server net 6.0 with individual auth, how do I set up such a route? Looking at the files, I'm at a complete loss on how the login pages are actually passing data around.
Thanks!
Update: the specific ask is exactly how do I modify the Blazor Server Net 6 Individual Accounts template to allow me to authenticate a user via an external access api? My thought would be to reference the route above for /login/ but that might not even be the best practice. But even if it is, how exactly and where would I update the template to make this happen?
(I have a feeling it's pretty basic to do, but I've been reading tutorials for weeks now and they're all just talking about internal authentication and verification within each Blazor component. I basically want an external program to also be able to "drive the car" remotely, but first it must authenticate.)
If you're building an API for this from scratch, then it seems like you have the right idea, no matter what happens, you're going to send the cookie to be website every request or at least a session id which contains all the information provided. From a database perspective maybe create a session table which then contains all the info you want and also can be easily found. That's a way for you to create a cookie for client server communication, however this is from my limited knowledge and may not be the best way.
I'd recommend hiding information like keys in the header to prevent exposure, looking at other APIs like the Spotify API you can see they set the authorisation bearer.
Exposing all the information for the credentials in the URL for what could be sensitive database behaviour may not be the best. You can hide the information in the header for every request you make.
Maybe have a default controller that obtains the user information before handling any specific requests and making it accessible to your other methods/requests?
The basic process for any external authentication is:
Redirect to the external log in page.
External Provider does it business.
External provider posts to a page on your site with the authentication information included - normally security info in the header or a cookie.
The Blazor app reads the authentication information with the AuthenticationStateProvider.
Normally you just need to write a customer AuthenticationStateProvider and code to redirect if the user is not authorized. This may be a manual button in the top bar, a you aren't logged in page with a button to log in, or an automatic redirect to the provider. The return for the provider is either your landing page or some other page to tell them they logged in successfully.
The custom AuthenticationStateProvider replaces the standard one in DI services and provides the security information to the Authorization components.
Search for "blazor custom authentication provider" will get you lots of good resources.

ASP.NET Single Sign On

We have two servers that run on the same machine under the same domain.
Both written in ASP.NET and uses the Identity framework.
I need to implement Single Sign-On (and single sign out) between them.
Actual sign-in is done in AJAX (I POST the username and password, the server authenticate the user and sets the session, then sends the redirect data URL to the client).
I found overwhelming amount of information about OWIN, the Identity framework, Claims, etc.
I found tutorials explaining how to create projects using just about any modal dialog and any Wizard there is in Visual Studio, which I tried to understand but really is useless to me, as I already have authentication system up and running.
I even found some demos claiming to implement SSO in all kinds of ways, and some Stackoverflow questions that said to simply put this and that values in the web.config and you're done, which seemed strange to me and I figured out I'm missing some basic understanding of how it works.
Still, I can't understand how SSO works in ASP.NET Identity.
Can someone please explain it to me in a simple manner, or refer me to some kind of such explanation?
Again: I have two authentication systems up and running. What code and/or configuration changes I need to make to get Single Sign-On working?
First, if you want them to share authentication, they need to be working on the same user store. In other words, you should factor out the Identity initialization code (ApplicationUser, ApplicationDbContext, ApplicationUserManager, and ApplicationSignInManager) into a class library that both applications share. Trying to mantain and share two separate databases with user data is going to be an impossible and insurmountable task.
Then, you need only ensure that both applications utilize the same machine key. The auth cookie is encrypted, and since the encryption is based on the machine key, both applications need to use the same key to encrypt/decrypt that cookie.
Since you've already stated that they will both be hosted on the same domain, that's all there is to it.

Which security should I use?

I am making an intranet mvc app for in-house use. Only other guy in the shop is the server tech. I am told we have a domain controller and we use AD, every user is in groups. I'm pretty sure we use windows authentication (based on we have to log in to our workstation.
I'm not sure if I should be using the UserPrincipal in Directory Services, or the Current.User stuff in HTTPContext, or something else, for authenticating users. Only people in certain AD groups should be able to open the app.
Obviously I know nothing about app security stuff. I plan to hit the books, as soon as I figure out which "technology" I should be using. I also need to check users against specific groups. I almost had that figured out, but I am getting false when I know it should be true.
if (HttpContext.Current.User.IsInRole("MyADGroup"))
{
IsAdmin = true; //keeps returning false.
}
So what should I be looking into?
You can use this example to help you get started with Active Directory Roles.
Since the application is in-house, you don't want to stray far from Windows Authentication, but I do recommend looking into LDAP.
Connecting to an LDAP Server
Good luck!
You can hook up the internal application to use users and groups from AD by using the ActiveDirectoryMembershipProvider. Then simply authenticate against the provider instances (Membership.ValidateUser). This allows you to use AD as a backing store but isolates your application from an explicit dependence on it. This will also populate the UserPrincipal on the HttpContext.
I would recommend using this with a standard login form, though IIS will allow you to configure Windows authentication for the entire site. Using a standard login form along with AD-backed authentication allows you to maintain the decoupling and also expose some parts of the site as public pages by allowing anonymous access. This can be useful for things like application help and FAQs which might be useful to someone trying to log on but either disallowed by permission or using the incorrect credentials. Provides a better user experience as well.

Toggle MVC user login method: Forms + AD Account

What if I am creating an intranet web application using MVC and in the administration's access panel I need to provide a way for users to login either via AD accounts or simple windows forms login-password combination.
The only way I see to accomplish that is to somehow switch on-the-fly the web-config file, allowing or disallowing the anonymous login and hence either or not to check inferred windows account name.
Two questions actually here: is there any more right way of doint it, and if not, what is the best way to change web.config file on-the-fly and is it really appropriate for accomplishing my goal?
The only way I see to accomplish that is to somehow switch on-the-fly the web-config file
Oh no, you are really very far from the truth.
Your scenario is actually very common. You could externalize the authentication to a separate service using WIF (Windows Identity Foundation). Here are some introductory slides. The idea is to federate authentication through a single sign on provider. And here's a similar question to yours.

FormsAuthentication.SetAuthCookie stores data in which place

In the following code where the creating user accounts(userid, password) stores in?
FormsAuthentication.SetAuthCookie(RegisterUser.UserName, false /* createPersistentCookie */);
Sameway, When LogIn, how it works?..(i.e)How the values are retrieved and compared to the data we are typing in the login page(userid, password)..Please explain the process..I am having doubt whether it is storted in ASPNETDB.MDF - > aspnet_Membership..If the values are stored here, then how application works when retrieving values from here to compare the data we typed in the form..Here the application I mean is Sample Application present in .NET4.0(Visual Studio 2010)..Pls help..
UPDATE: 24/12/2012
Below answer is out of date. The venerable FormsAuthentication.Authenticate is now marked as obsolete in ASP.NET 4 MVC 4.
MVC 4 ships with the new brand spanking WebSecurity authentication system which solves a lot of problems of the old system. Please look in to it unless your project is still using MVC 3 or below.
Short Answer is "It works very carefully."
Long answer...
User account details are (by default) stored in a SQL CE database (which is in the ASPNETDB.MDF file)
ASP.NET has a built-in Membership and Role Provider system to assist with authentication. This is an abstraction that ASP.NET uses to enable built-in support for accounts. By default, when you create an application, your web.config file is configured so your application uses a built-in implementation of this Membership Provider to allow your application to do the magic of reading and writing to the database, hashing or encrypting passwords, validating users .etc.
The code sample you got, is a part of Forms Authentication
FormsAuthentication.SetAuthCookie(RegisterUser.UserName, false /* createPersistentCookie */);
It is the component that manages Authentication by default. When you perform the above call, ASP.NET Forms authentication system encrypts the username and a session data and stores it in a cookie on your user's browser. (This cookie is removed when you call FormsAutentication.SignOut() )
This cookie is transmitted to your server for every request. So, for each request, FormsAuthentication checks and validates this (decrypts it, check who the user is, validates the session is not expired, and set some properties in the application so your code can know which use is making the request).
If the /* createPersistentCookie */ parameter is set, the cookie is set as persistent, which means the cookie doesn't get deleted when you close and re-open the browser while logged in. This is same as you logging into, say Facebook, and tick the 'Remember Me' check box, and the default implementation of the project created by Visual Studio does exactly this on your log in page.
Hopefully now you have a better understanding about what's happening in the login process. Because of the way these are implemented in ASP.NET, you can easily configure, extend or replace the functionality with your own implementation if you like.
To better understand how things work, follow this article on how to implement a custom Membership Provider http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx
I should tell you that if you're new to ASP.NET, reading on how Membership and Authentication works may be overwhelming. (I personally spent the last couple of days trying to understand and write a custom Membership provider to match my requirements. It was a bit frustrating so I took a break to answer you and refresh my mind with the basics.)
If you're happy with how the existing system works, just use it. It doesn't hurt to implement a custom provider to understand how it works. But the built-in system has went through a lot of testing for the last decade and proven to be working. So why not use it ? I've seen multiple custom implementations on different sites that try to replace the existing Membership system, just because they don't fully understand it. Most of these implementations end up re-writing what is already available, and falls short when it comes to extensibility and security. Just like a wise man once said "Don't fix it, if it ain't broken".

Categories