ASP.Net Security - Test User is Authenticated via 3rd party request parameters - c#

I have an un-ideal application and without going into the ins and outs this is what is needed.
A 3rd party app needs to make a request to a page which will return data. Because I have Forms Authentication enabled this request always ends up being sent to the login page. I have therefore set it so that all users can see this page even though they are not logged in. What I want to do in the Page Load or similar is to check querystring parameters which the 3rd party app can send and validate it against FormsAuthentication.
When this 3rd party app makes its request a user has already logged on so I was wondering is it possible that I can check something against the currently logged in user to see if it matches the 3rd party request?
What I need to also do is send that information from the logged in user to the 3rd party app so that when it makes its request it matches up with the logged in user.

I may get down votes for this, but I'm going to answer anyway because if one of my co-workers asked me this question, I would read them the riot act. (I won't read you the riot act because I'm not responsible for your systems or the security of your data.)
I see from your first sentence that you realize this may not be the best idea because it is an "un-ideal" application.
I know that what I'm about to suggest will result in duplicate code and add to maintenance down the road, but when you balance that against short-circuiting the authentication mechanism or tampering with a well-known and trustworthy mechanism to weaken it so as to allow another application to use a "back door" (which is what you're really talking about doing here - creating a back door for this other application but attempting to use querystring parameters as part of the login mechanism) it is really the lesser of two evils to have more code and more to maintain.
So... Have you considered, and is it a possibility for you to set up another method for this other app to get the data? You say that it is just getting data, so why not have a separate web services project or some other project appropriate. Even another web site application would be a better solution to what you're proposing.
Even if this data is not what you would call "Sensitive" I still think trying to build in a back door is a bad idea. It may not be a critical issue on the current application, but not coding for security is a habit, and once you do it in one area, you're more likely to take unnecessary risks elsewhere.

Related

How to get the URL of the current page in C#?

In the new .NET 7.0 framework, things have changed considerably...
This has been asked a gazillion times before and if the .NET Core framework would not break all kinds of backwards compatibility then I would have an easy answer. Too bad a lot of answers are related to .NET 4.9 and older and they just don't work.
So in my minimal Web API I want to do some simple request logging by sending the complete URL as a string to a database. (With some additional information.) So I have the HttpContext class (NOT the HttpContext class) with the Request property of type HttpRequest and it just does not have any method to get the original URL that was requested. Only the various parts which I have to concatenate and hope it resembles the original uri...
So, a useful method like Request.Url is now totally gone and the DisplayUrl helper() isn't providing me everything. It leaves out the QueryString. I need that QueryString also.
And yes, I can concatenate this again to get the value that it originally received and made hidden. It just feels wrong, though. Plus, this method makes the uri suitable to be returned in a header. Again, I want to store it in a database for logging purposes exactly as it originally was!
So now I have to ask something that has been asked a gazillion times before, simply because the latest .NET update breaks things again.
The application I'm working on is a multi-tenant application running on multiple domain names including wildcard subdomains and is used to analyze the amount of traffic I get for new domains that I've registered. The whole API will just generate 404-errorcodes back to the user, but I want the whole URL to get registered to determine if the domain isn't getting any funny requests. (Like hackers trying to access https://owa.example.com/wp-booking.php or https://forum.example.com/default.aspx?g=rsstopic&pg=0&ft=0 or whatever.) I also log the body of the request, the request method, the IP address of the user and the headers that are passed and it cal be used by me to extend a blacklist of users who seem to have malicious intent.
The domains where I use it are often fresh out of quarantine and are just in a wait-state until development starts. (Or until someone takes it over.) Responding with a 404-error should tell users (and hackers) that the site does not exist any more. Most users will be aware that the site is gone so they stop visiting, but various automated (and hacking) tools might still be running so the information tells me what the user is trying to do.
Anyways, I need the full URL with the query string, domain name, protocol and everything else that the client has passed to my server. But .NET 7 is preventing me from access to the original URL which is dumb. And the whole project is basically a single app.Run() statement which always returns a 404 error after logging the request. And yes, slow is fine for this API.
Sigh... Request.Url.AbsoluteUri was such a useful function, but it's gone, making all answers going back 14 years or so obsolete as Request has no Url...
UriHelper.GetDisplayUrl(source) should do the trick:
app.MapGet("test_uri", (HttpContext context) => context.Request.GetDisplayUrl());
Returns http://localhost:5207/test_uri?query=1&test=2 for this url.
So in my minimal Web API I want to do some simple request logging by sending the complete URL as a string to a database.
Minimal APIs support request logging - docs, example. Potentially you can combine it with some logging library which allows writing to database.

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.

.Net WebApp: Create a Form Signature Class/Methods

I have scoured the web looking for bits and pieces of a more comprehensive solution. I have been unsuccessful in my efforts, so I send up a call for help.
The problem:
I have a .Net/C# WebApp that uses windows integrated authentication. The application is a custom form application that allows users to submit requests. These requests are then routed to supervisors and other parties that will review and approve the requests.
For audit purposes, I must have each supervisor "Sign" the form. The easy solution - use the active browser session information. A user clicks the "approve" button and that information is logged into the database (ID and date/time). But the auditors don't like this solution. They view it as insecure. They want a separate challenge for credentials where users are forced to enter an ID and password (and very soon present a token/PIN combo in lieu of ID/password).
To satisfy this in an infopath version of this form, I used CredUIPromptForCredentials. That code (although written in C#) does not directly port to the new custom WebApplication. I did some digging and uncovered a number of resources on the newer CredUIPromptForWindowsCredentials:
How to show Windows Login Dialog?
Show Authentication dialog in C# for windows Vista/7
How to show authentication dialog in C# .Net 3.5 SP1
Windows Security Custom login validation
This is really in the spirit of what I'm trying to accomplish. With very few modifications to the code in the articles above (and borrowing from some code in my old InfoPath form), I was able to get a working system of prompting and testing.
I would be happy to share the existing code if anyone is interested, but it is VERY similar (nearly verbatim) to the existing code referenced above. The only difference is a separate isAuthenticated method that actually tests the credentials by instantiating a DirectoryEntry object and passing that object to a DirectorySearcher object to test if the credentials worked.
But no so fast. This code, as I said, works, but ONLY when I run in debug mode in Visual Studios 2012. If I visit the site by entering the address and click the button to "sign" the form, the site spins and never shows the security dialog. It's almost as if (and this is just my guess) the IIS settings that allow windows authentication are preventing the applications request to prompt for credentials. This is not the case when I run the site through the debugger.
Once I get past that barrier, I have to actually do some further testing to see if this code will support authentication with a PKI card. I am guessing it will since CredUI passes the prompting to windows to handle.
So here are the questions:
1) What could possibly be preventing the windows security window from popping up when the method is called through the IIS server VS running in Debug (localhost)?
2) Does anyone have any experience with implementing CredUIPromptForWindowsCredentials to work with PKI?
2a) If so, does CredUIPromptForWindowsCredentials actually support PKI without any additional code (assuming that the windows workstations are configured with all of the hardware, drivers, and middleware)?
Thanks in advance for any insight you can lend.
Phil S.
Looking your problem and as an old Auditor, may I recommend an detour to satisfy your auditing team? PKI is not the most safe thing around...
1) Provide a normal LOGIN/PASSWORD form, without any special instruction or Credentials (that could be frauded or stolen "on the fly"). Preferable, utilize HTTPS in this page.
2) Once the guy inform the data, pass a 2-Factor Authentication using SMS (INstant Message). The cost is really irrelevant (see Twilio to get some idea). Obviously, each guy, beyond his login/password, must have his phone within database.
3) This way you can ensure that the Supervisor is really the guy who had approved/sign the page.
It´s the safer mode and, because of it, Facebook, Google Mail and others are utilizing this method.
Sorry, I know I not answered you as you need, but it´s safer than your proposal.
Good luck!

Get the current request in ASP.net

Excuse me for my poor english.
It's possible get all thread requests from an ASP.NET application?
I don't need execute the complete logout of current user if in same time another clients are authenticated with this same username. Perhaps I could query another request threads for know if I need do that.
I will try simplify the question... Can I know all actives requests from ASP.NET application in a IIS server on C# code?
Now I try get the threads of WebDev.WebServer40.EXE process, but don't seems the requests threads.
I think you are approaching this wrong. You cannot log out a user in the middle of a session since http is stateless and the users credentials are always sent as part of the request, be it a cookie, a Bearer token or some value in the Authorization header.
Performing a logout as part of a single request is therefore not really feasible.
To me it sounds like you want to unauthorize the user without necessarily unauthenticating the user. That is, the user id is still connected to the request, but you no longer want to grant the user access to whatever resource, that was available to the user a moment ago.
This decision is made at a unique point in time, so all requests concurrently with the time you made the decision that the user is now unauthorized will behave differently depending on whether the authorization was checked before or after the unauthorization. New requests are sure to be denied though.
A http request should not take longer than milli seconds or sometimes seconds. Are any ressource you are protecting so important that it cannot live with this inconsistency window, you probably shouldn't expose it via http.
But if you want to make this rather (and perhaps unnecessarily) complex mechanism to unauthorize already authorized request, you should make it as a http handler executing as the last part of the aspx pipeline. It should look at the user id and some kind of shared blacklist maintained by the authorization system.
I think you should live with the inconsistency though. But be sure to separate authentication (who) from authorization (what the user can do).
I did look different possibilities. The best option perhaps is use the System.Web.Administration dll and WorkerProcess.GetRequests method. The main problem is that dll only works with IIS7 version o superiors. Exists some way for get something similar in IIS6? For me the most important is get the current request theads managed by server and know the credentials of each thread and internal info.

Limit concurrent logins from different devices in ASMX service

I have webservice which uses ASMX webmethod etc (I know, outdated), it is used to supply mobile devices with data for their apps.
Right now, users can login on any device at any time, as many times as they want. To make this product compatible with a new licensing model, we want to restrict users in logging in to multiple devices.
A user should only be able to be logged in at one device at a time.
I thought of the following solution: save the mobile device identifier last used in a request, and the time of the request in the database. If a user tries to login (within ~10 minutes) from another mobile device identifier -> login fails.
My problem: in which method do I put this code. I want to prevent duplicate code as much as possible.
I have 4 .asmx files with API's, I could put the code in the constructors of all the classes, but I'd rather not. Is there not some "Request_Start" that already has access to GET/POST parameters?
Please refer to:
When the same user ID is trying to log in on multiple devices, how do I kill the session on the other device?
I understand you're asking about ASMX, but I believe this will be a good starting point for you.
I had this same exact requirement, and came up with a pretty slick solution, demonstrated in the link above. In a nutshell, my requirement was to only have one user log-in happening at one time. If that same user ID tried to log in elsewhere, then it killed the session for the first log-in by checking for an existing log-in under a different Session ID (this enabled the user ID to be logged in from multiple instances of their web browser on their computer [same Session ID], which is common, but not from a different computer [different Session ID] (possibly due to someone that stole their credentials, for example)). Through modification of the code you could probably change the behavior of this - i.e., prevent the second log-in attempt instead of killing the first log-in that's already active and in use.
Of course, it may not fit 100% to what you're needing, so feel free to modify it to fit your needs.

Categories