Allow unauthenticated access while keeping IIS Windows authentication and occasional impersonation - asp.net-mvc

I have several intranet-only web sites written in ASP.NET MVC 5 and hosted on IIS7.
For these I want to enable impersonation when accessing the database.
I don't want the complete impersonation that lasts for the whole request - because I don't need it and because it is not supported in the integrated mode and requires suppressing the error.
The important note is that impersonation here is not related to security. I don't want to prevent anyone from accessing the web site (if they are on the company's network, that is already a granted permission).
Rather, I need to store the Windows user name in the database against certain actions for logging purposes only. If no Windows user name is available for logging, that is fine and the user must be able to proceed.
The code I'm going to be using will be
var identity = User.Identity as System.Security.Principal.WindowsIdentity;
if (identity != null && !identity.IsAnonymous)
{
using (var context = identity.Impersonate())
{
// access SQL Server who will get the user name from SUSER_SNAME()
}
}
The problem is that in order for IIS to pick up the Windows credentials, the anonymous access must be disabled, otherwise IIS will not even try to request credentials in some way or another.
This is a problem, because I want to keep the anonymous access.
Is it possible to somehow configure IIS or the application to let anonymous users in too?
Ideally this should be happening transparently, but if that is not possible, I will probably be happy with the browser displaying the username/password dialog, which the user would dismiss by clicking OK, which would provide blank username/password to IIS, which would allow them and map them to the anonymous situation (ish).
It is, however, not okay to request credentials from users whose browsers can provide Windows credentials automatically (IE does that by default, Firefox does that after changing a setting).
I have seen this .NET v1.1 era hack that involves reflection on private fields and this question on writing a custom HttpModule - but it is said to be called after IIS completes its authentication business, which is too late, and I have no idea how to initiate an NTLM handshake from such a custom handler.

Related

How to make Windows Authentication with specific users and roles that can access the application? (ASP.NET CORE MVC)

I have an intranet application with Windows Authentication. And I want to have a database table that contains the allowed users that can access the application.
I want to get the username after someone try to log into (successfully, thinking about the user existence into domain), to check if it is present into database to allow the access, besides that, redirect to a static HTML saying he can't access the application.
How can I achieve something like that?
And about the [Authorize], User Roles that ASP.NET Identity provides can be used in Windows Authentication mode to solve this problem?

Identity Impersonation with ASP.NET 4 MVC not working as expected

I am in the process of building a Intranet MVC 4 application for our analysts. The goal is to allow internal users access to this application without having to sign on given they are part of our internal network. When they access the application I want to be able to capture their windows user name and check against the active directory using LDAP and retrieve the department they belong to and display the relevant details on the screen. Based on the advice from different fora, I have chosen Windows Authentication for this application and I was able to test the app successfully running from Visual Studio. The trouble I am having is when I deploy this to our UAT server running IIS 7.5.
<authentication mode="Windows">
</authentication>
<identity impersonate="false" />
This is the current state of my Web.config file. Irrespective of whether impersonate is true or false, the application seems to not capture the windows username of the browser from which the application is accessed. Is
impersonate = true
required for this at all? In the Welcome message on the homepage, I always see the windows user name of the computer where the application is hosted/IIS is running. I have tried a wide variety of ways to capture the Windows User name of the incoming user request.
string name = System.Web.HttpContext.Current.User.Identity.Name;
string name = System.Web.HttpContext.Current.Request.LogonUserIdentity.Name;
string name = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
string name = System.Web.HttpContext.Current.Request.ServerVariables["LOGON_USER"].Name;
etc. I also looked into several other posts here like this. But I am unable to get it to work. I am afraid that I am trying to achieve this by accident rather than really understanding what is going on? Could someone please guide me in the right direction?
No, you misunderstand the purpose of impersonation.
First, Impersonation is no longer supported in IIS 7 or greater running in integrated mode.
Second, the purpose of impersonation is to change the "user" the worker process runs under at runtime, specifically to allow access to filesystem or database resources as that user. It has nothing to do with authentication in general, and is not particularly useful for most web applications.
You want to use Windows Authentication, however you should know that this will only work with Internet Explorer. It will also only work with servers that are joined to your domain, and do not have any intermediary Kerberos authentication issues. (these are often known as "double hop" problems). Other browsers do not, by default, provide Active Directory account information automatically, although some may be configured to allow it to do so, others do not.
If you are using a properly configured server with Windows Authentication, and you are using a browser that supports ActiveDirectory Kerberos ticket passthrough, and there are no network issues that would cause problems with this passthrough, then you can use HttpContext.Current.User.Identity.Name to get the users name.
Don't use LogonName or anything like that, as those will just give you the worker process, not the authenticated users name.

ASP.NET MVC 2 and authentication using WIF (Windows Identity Foundation)

Are there any decent examples of the following available:
Looking through the WIF SDK, there are examples of using WIF in conjunction with ASP.NET using the WSFederationAuthenticationModule (FAM) to redirect to an ASP.NET site thin skin on top of a Security Token Service (STS) that user uses to authenticate (via supplying a username and password).
If I understand WIF and claims-based access correctly, I would like my application to provide its own login screen where users provide their username and password and let this delegate to an STS for authentication, sending the login details to an endpoint via a security standard (WS-*), and expecting a SAML token to be returned. Ideally, the SessionAuthenticationModule would work as per the examples using FAM in conjunction with SessionAuthenticationModule i.e. be responsible for reconstructing the IClaimsPrincipal from the session security chunked cookie and redirecting to my application login page when the security session expires.
Is what I describe possible using FAM and SessionAuthenticationModule with appropriate web.config settings, or do I need to think about writing a HttpModule myself to handle this? Alternatively, is redirecting to a thin web site STS where users log in the de facto approach in a passive requestor scenario?
An example of WIF + MVC is available in this chapter of the "Claims Identity Guide":
http://msdn.microsoft.com/en-us/library/ff359105.aspx
I do suggest reading the first couple chapters to understand all underlying principles. This blog post covers the specifics of MVC + WIF:
Link
Controlling the login experience is perfectly fine. You should just deploy your own STS (in your domain, with your look & feel, etc). Your apps would simply rely on it for AuthN (that's why a app is usually called a "relying party").
The advantage of the architecture is that authN is delegated to 1 component (the STS) and not spread out throughout many apps. But the other (huge) advantage is that you can enable more sophisticated scenarios very easily. For example you can now federate with other organization's identity providers.
Hope it helps
Eugenio
#RisingStar:
The token (containing the claims) can be optionally encrypted (otherwise they will be in clear text). That's why SSL is always recommended for interactions between the browser and the STS.
Notice that even though they are in clear text, tampering is not possible because the token is digitally signed.
That's an interesting question you've asked. I know that for whatever reason, Microsoft put out this "Windows Identity Foundation" framework without much documentation. I know this because I've been tasked with figuring out how to use it with a new project and integrating it with existing infrastructure. I've been searching the web for months looking for good information.
I've taken a somewhat different angle to solving the problem you describe.
I took an existing log-on application and integrated Microsoft's WIF plumbing into it. By that, I mean that I have an application where a user logs in. The log-on application submits the credentials supplied by the user to another server which returns the users identity (or indicates log-on failure).
Looking at some of Microsoft's examples, I see that they do the following:
Construct a SignInRequestMessage from a querystring (generated by a relying party application), construct a security token service from a custom class, and finally call FederatedSecurityTokenServiceOperations.ProcessSignInresponse with the current httpcontext.response. Unfortunately, I can't really explain it well here; you really need to look at the code samples.
Some of my code is very similar to the code sample. Where you're going to be interested in implementing a lot of your own logic is in the GetOutputClaimsIdentity. This is the function that constructs the claims-identity that describes the logged-in user.
Now, here's what I think you're really interested in knowing. This is what Microsoft doesn't tell you in their documentation, AFAIK.
Once the user logs in, they are redirected back to the relying party application. Regardless of how the log-on application works, the WIF classes will send a response to the user's browser that contains a "hidden" HTML input that contains the token signing certificate and the user's claims. (The claims will be in clear text). At the end of this response is a redirect to your relying-party website. I only know about this action because I captured it with "Fiddler"
Once back at the relying party web site, the WIF classes will handle the response (before any of your code is run). The certificate will be validated. By default, if you've set up your relying party web site with FedUtil.exe (by clicking "Add STS Reference in your relying party application from Visual Studio), Microsoft's class will verify the certificate thumbprint.
Finally, the WIF framework sets cookies in the user's browser (In my experience, the cookie names start out with "FedAuth") that contain the users claims. The cookies are not human readable.
Once that happens, you may optionally perform operations on the user's claims within the relying party website using the ClaimsAuthenticationClass. This is where your code is running again.
I know this is different from what you describe, but I have this setup working. I hope this helps!
ps. Please check out the other questions I've asked about Windows Identity Foundation.
UPDATE: To answer question in comment below:
One thing that I left out is that redirection to the STS log-on application happens by way of a redirect with a query-string containing the URL of the application the user is logging in to. This redirect happens automatically the first time a user tries to access a page that requires authentication. Alternatively, I believe that you could do the redirect manually with the WSFederationAuthentication module.
I've never tried to do this, but if you want to use a log-on page within the application itself, I believe the framework should allow you to use the following:
1) Encapsulate your STS code within a library.
2) Reference the library from your application.
3) Create a log-on page within your application. Make sure that such page does not require authentication.
4) Set the issuer property of the wsFederation element within the Microsoft.IdentityModel section of your web.config to the login page.
What you want to do is an active signin. WIF includes WSTrustChannel(Factory) which allows you to communicate directly with the STS and obtain a security token. If you want your login form to work this way, you can follow the "WSTrustChannel" sample from the WIF 4.0 SDK. Once you have obtained the token, the following code will take that token and call the WIF handler to create a session token and set the appropriate cookie:
public void EstablishAuthSession(GenericXmlSecurityToken genericToken)
{
var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader(
new StringReader(genericToken.TokenXml.OuterXml)));
var identity = handlers.ValidateToken(token).First();
// create session token
var sessionToken = new SessionSecurityToken(
ClaimsPrincipal.CreateFromIdentity(identity));
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
}
Once you have done this, your site ought to behave the same as if passive signing had occurred.
You could use the FederatedPassiveSignIn Control.
Setting your cookie like this:
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
Doens't work for SSO to other domains.
To cookie should be set by the STS not at the RP.

DB access denied with ASP.Net MVC application after switching to windows authentication mode

I have a MVC application that I am now trying to add authentication and authorization to.
I want to allow users to get to the site and be automatically authenticated. So I set authentication mode="Windows" in the web.config, and enabled NTLM in the project options. The site now shows my domain name in the top right when I run it, but when I hit a action than needs DB access, it tells me access is denied for my user-name?
What step am I missing?
This is not necessarily an IIS or Windows Authentication issue. I would assume that your connection string looks something like this
Data Source=myServerAddress;Initial Catalog=myDataBase;Integrated Security=SSPI;
Now that you are using Windows authentication, the Domain\username is being passed to SQL to authenticate to the database. If you do not have the entire domain (or at least the subset logging into your application) as valid users in SQL, then you will get an unauthorized exception. You will need to a) pass a username/password to SQL in the conneciton string as below or b) add the users of your application to the security users of the database or c) use the impersonate attribute in the web.config file to impersonate a user that has access to both the application files on the web server and the database
SQL connection string with username/password
Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;
This is the subtle difference between authentication and authorization.
Authentication is the act of identifying who the user is (And you've done this bit)
Authorisation is the act of determining who is allowed to do what (You need to apply the appropriate access permissions to the database, for each of your users/roles)
The subject of database access permissions is a little to complicated for sensible coverage on this forum, so i suggest that you do a bit of research via Google, etc

Managing security rights based on User.Current.Name in ASP.NET MVC

I am using ASP.NET MVC to build a web application.
In the main screen of logged-in user, I am using User.Current.Name to determine logged-in user identity, this is mapped to ID of a domain model data that is related to the current user. No one else should be able to see or edit this information (say his profile).
I am using membership and roles to ensure that only logged in users in particular role are able to invoke this action (Home action of UserController in this case)
There is going to be no HTTPS for this application when it is deployed.
Is this approach considered a safe approach?
Is there any chance for malicious user to fake his identity to ensure that User.Current.Name returns a different name?
Is there any additional configuration required to ensure that no one can "steal" the authentication cookie of another user?
EDIT: Standard Forms authentication is used.
OK so, setting HTTP sniffing aside because you won't be using SSL, the main problem point is the authentication cookie.
The forms authentication/roles cookie isn't encrypted by default, it is only signed against tampering. You can encrypt it using
<forms protection="All" ... />
This will use the machine key specified in machine.config or web.config to encrypt - so if you want the cookies to live across app recycles you will need to set a specific machine key.
You should also look at not persisting cookies (i.e. no "Remember me" option) and ensure that secure pages that require authenticated access are placed in subdirectories/controllers that separate from the anonymously accessible pages.
You may also want to reduced the cookie lifetime, which can reduce the amount of time a stolen cookie lives for.
<forms
timeout="10"
slidingExpiration="true"... />
You should also be encoding all your output to web pages to stop Cross Site Scripting, as this is the major way of cookie stealing. The ASP.NET cookie is HTTP-Only, which means it should not be served up via javascript, however not all browsers implement this (Safari doesn't).
As long as you have set the machineKey property in web.conrfig, the cookie is encrypted on the server side, and no one can fake that information. However, since the standard authentication mechanism in ASP.net MVC is regular Forms authentication, you should enable SSL so that no one can sniff the username and password when logging in.
Another approach is to use a different authentication mechanism. This could be windows authentication, kerberos, use of client certificates etc.

Resources