I have an ASP.NET web application (running on .NET 4.5). It's currently doing forms authentication. We've set up an ADFS 3 server with multiple federations, some internal, some external (customer STSs), and we'd like to configure the web application to use an active authentication model. If I understand it correctly, that means that we will continue to use the login form in my web application, and it will gather credentials from the users, then send a security token request to our ADFS server. The token request would presumably tell ADFS which federation to send the request to. If everything is successful, then I get a token back from ADFS, validate it, and construct a ClaimsPrinciple and go from there.
Now, with that background, the problem I'm running into is how to send the token request to ADFS in .NET 4.5. Every example I've seen, despite being labeled as applicable to .NET 4.5 uses the old UserNameWSTrustBinding class from WIF. This is deprecated and not present in 4.5. Web searches for "UsernameWSTrustBinding 4.5 equivalent" have been fruitless. I've seen one guy construct his own class to duplicate the functionality, but I can't believe this is necessary. I've got a hunch that there is a class here somewhere that I'm supposed to be using for the binding in the WSTrustChannelFactory, but I can't find it. Or, perhaps the entire WSTrustChannelFactory pattern is outdated as well (but then why would it have been included in .NET 4.5)?
Can anyone provide a snippet of code or even shed some light on how you're supposed to go about active authentication in .NET 4.5?
So far my best idea has been to check username in the users cookie (if it exists) or from regular login form when the cookie didn't exist. With that info, I can determine whether it needs to be sent to the IdP or not. In the case that it needs to be sent to the IdP, I can just build a request URL and redirect.
WSFederationAuthenticationModule instance = FederatedAuthentication.WSFederationAuthenticationModule;
SignInRequestMessage request = instance.CreateSignInRequest(Guid.NewGuid().ToString(), instance.Realm, true);
request.AuthenticationType = "urn:federation:authentication:windows";
Response.Redirect(request.WriteQueryString());
Of course, I can tweak that request with the appropriate .HomeRealm value or .AuthenticationType in order to skip the HRD process, and then after that, they'll be sent back to the app authenticated and with a proper claimsidentity.
One reason that this isn't the perfect answer for me is that if the user has never logged in before, or has cookies disabled, and depending on the federation, there's potential for them to have to login twice. That is, once to the app's login form, and once to the ADFS form. That's why I was hoping to be able to send a request programmatically somehow instead of redirecting. That way I could presumably send the username & password that were already collected by the app without having to collect them again at ADFS.
For that reason, I won't mark this as the answer. I'd like to hold out for better.
Related
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.
I'm working on a .net Core 5.0 MVC project that the user logs in using Windows Authentication.
So there is no Login controller. The browser itself asks for username and password and redirects the user to my controllers.
And I want to do some logging right after the user logs in. I want to log to the database some information regarding the User + Date + IP.
If I understood correctly, if I use .net core middleware (if I create my own middleware and place on Startup.cs), I will be logging on every request. And that's not what I want. I want just the first login of each user.
Is there a way to do that? I've tried to search SO and MS docs, but couldn't find an answer.
Is there any interceptor that happens only after Windows Auth login?
Thanks!
The only way I can think of doing this is by hanging off something you store somewhere. There isn't anything out of the box that I can think of.
A cookie would work but is too volatile. The only safe and consistent way I can think of is to hang off a value stored somewhere in your user store (database) that is a booleon flag that once you have done your first login stuff, you set to true and can check on subsequent requests.
Much like you are probably doing with email confirmation if you are using the standard ASP.NET Identity and demanding verified email addresses.
I have searched all over for an answer to this, and not found anything that seems to answer my question. Which feels like it should be an easy one (but clearly isn't).
I have an API which authenticates using a token. This token I generate from my application - more specifically, I have a new Token Generation web call that will return a token. Currently, I pass in a cookie with the user and password information, and it uses this to identify who I am and what I should be allowed to do. This is all working absolutely fine and hunky-dory.
I am achieving this process by making the Token Generation use OWIN Cookie Authentication, which means that the cookie is read and the Identity is set. I am then able to use this identity to confirm whether the user is allowed to access the system.
What I now want to do is replace this Cookie Authentication process by authenticating against a Windows User (everything is windows based, and this will be an option so non-windows users can still use the cookie authentication route). But I cannot discover how to straightforwardly do this.
Note that I don't actually need to validate that the user is genuine or refer back to the AD at all. If you provide a windows user that matches a user in the system, you can log in.
So how can I - easily - get the requesting user into the Identity Name? Or is this not possible?
If you are looking for information on the current user accessing your program, assuming the program is running on the user's machine and is windows based, you can simply query windows for the user's username or any other publicly available information about the user.
Refer to https://learn.microsoft.com/en-us/dotnet/api/system.environment?view=netframework-4.8 for information on the Enviroment class and what it's features are.
If you could provide some code or further clarity I could help you further.
I currently have a .net core application that uses Identity Server 4 to authenticate users. We have two different applications; an MVC portion of our site that users can login to, and a SPA that users have to login to as well. Is it possible to make it so that anytime the user logs out of one of those areas, that it logs out of both?
This is the main idea of Single Sign-On. Not only single login, but also single logout. Identity Server 4 fully support this, but you just need to configure both your clients (the MVC app and SPA) with their proper configurations. This is the official documentation about signing out. It works.
EDIT
PS: Have in mind that Identity Server does not invalidate the access token, once you are logged out. In other words - if you, by any chance, still have the access token, you will be able to use it, as long as it is valid (its validity period has not expired). This is why usually the access token is set to have a shorter lifetime.
There are 2 front channel ways to acheive this and I'd recommend using both.
1) Front channel log out which uses an endpoint registered against each client. When you sign out of IDS4 (assuming it's implemented properly) it will make a request to the registered endpoint for each app that was signed into during the current session. http://openid.net/specs/openid-connect-frontchannel-1_0.html
2) The session monitoring spec which uses a bit of javascript and cross-domain iframe magic to notify the client app when the user's session changes on the IDP. Using this you can immediately respond to changes and do any cleanup you need to. http://openid.net/specs/openid-connect-session-1_0.html
As mentioned in m3n7alsnak3's answer this will not invalidate any JWT access tokens (you can use the revocation endpoint to revoke refresh or reference tokens however). Therefore I'd recommend having the client applications to the best job they can of clearing up any state they can, i.e. clearing all cookies, session/local storage etc.
I am using HttpContext.Current.User.Identity.Name to get the user name of the logged in user. I would like to know how this is working (using NTLM v2 / Kerberos) and how secure is it? Can the user try to mimic he is someone else?
Basically, from a security point of view, is there something I should be worried about, or how should I improve it?
If you are authenticating using Windows authentication (which, given your mention of NTLM/Kerberos it appears you are) then what happens is (roughly) as follows
IE sends a request with no authentication header to your web server.
IIS refuses the request with a 401 response code and tells the browser the authentication scheme it wants (in this case Negotiate, which tries Kerberos first, and then falls back to NTLM)
The kerb handshake takes place over multiple connections, and the ticket is validated against AD
IIS passes the ticket down to ASP.NET which, in the process of building the Request object populates the principal on the thread assigned to the request with the identity details from the ticket.
When you access HttpContext.User you see the principal for the current thread.
It's secure. It's basically the same authentication type used when you connect to a Windows server via file shares or anything else that is using kerberos. It's actually IIS and Windows itself doing the vast majority of the work, ASP.NET is just giving you a nice way to query the results.