Authentication in ASP.NET using FormsAuthentication - asp.net

I am using FormsAuthentication and ASP.NET Memberships and Roles in my ASP.NET project. I have some aspx files which can be viewed / accessed by only authenticated users. I think I can do this using one of the following two ways.
Configuring the web.config file. Allow users with roles 'admin' and 'members' to access those apsx files, and deny all other anonymous users.
In page_load events of those apsx files, just checking whether the curent user is authenticated or not using HttpContext.Current.User.Identity.IsAuthenticated
I am wondering whether these two approaches are equivalent or not for apsx files.

They are not equivalent. Method 1. gives access only to the "admin" and "members" roles. If you add another role, they won't have access. Method 2 lets any signed in user access the data.
I think that the preferred way is to organize the aspx files in directories depending on what roles should access them. Then configure access on the directories in web.config.

As others mention, this is not equivalent. However, even if you modify "2." to check roles, this is worse approach as you introduce a custom code to handle something which can easily be handled in a standard way.
Consider also yet another approach, where you create a separate folder, put your restricted pages there and create an auxiliary web.config to contain:
...
<system.web>
<authorization>
<allow roles="admin,members" />
<deny users="*" />
</authorization>
</system.web>
This way you require authorization to all resources in the folder, pages, styles, images.

Hello you must distinct between Authentification and Authorization
"HttpContext.Current.User.Identity.IsAuthenticated" is : Authentification
"Allow users with roles 'admin' and 'members'" is : authorization, after authentification we execute authorization
You can read this article : http://www.duke.edu/~rob/kerberos/authvauth.html
Authentication is the mechanism whereby systems may securely identify their users. Authentication systems provide an answers to the questions:
Who is the user?
Is the user really who he/she represents himself to be?
Authorization systems provide answers to the questions:
Is user X authorized to access resource R?
Is user X authorized to perform operation P?
Is user X authorized to perform operation P on resource R?

Related

Windows Authentication IIS7

I have an ASP.NET Dynamic Data site that should only be accessible to administrators currently logged in and on the domain. I want the site to be able to tell who the user is based on their login and either allow or deny access without challenging for credentials. Due to the nature of a Dynamic Data site, I want to be certain no one else is finding their way in their so I'd like to manage authentication and authorization in IIS rather than the web.config. But no matter what I do, it denies access even as administrator.
Using IIS7 on a 64 bit Windows Server 2008 R2 Standard machine. When clicked on the site and go into Authentication, I have disabled all modes except Windows.
All three available providers are enabled in the following order:
Negotiate:Kerberos
Negotiate
NTLM
In Authorization, I have added a deny rule to deny anonymous users and then allow all users. Eventually will change that to allow role administrator but I can do that once I get this working.
What am I missing? If it matters, the web server, the domain controller, the file server the pages are on are all on the same domain.
You may want to use this little snippet of code:
Public Function GetGroups() As ArrayList
Dim groups As New ArrayList()
For Each group As System.Security.Principal.IdentityReference In System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups
groups.Add(group.Translate(GetType(System.Security.Principal.NTAccount)).ToString())
Next
Return groups
End Function
This returns all the groups the current windows user is part of, that way you can check if the admin group is in the array list and just redirect them if not.
So drop the other access deny/allow and use whether or not they are in the admin group to determine access.
You will need to make sure that the following is in your config file:
<system.webServer>
...etc
<security>
...etc
<authentication>
<windowsAuthentication enabled="true" />
</authentication>
...etc
</security>
...etc
</system.webServer>

Restricting a public-facing demo site for an asp.net application?

I'm convinced there has to be a dupe of this somewhere, but I couldn't find it easily:
Given an asp.net application that in itself uses Forms Authentication, what is the best practice for securing a public-facing demo site such that nobody who is not in the "in crowd" can see the site at all?
IP Filtering?
Basic auth wrapped around the forms auth? I've banged my head on this one and can't seem to make it work :/
VPN?
"making a demo site public facing considered harmful" in the first place?
Have you considered leveraging your Web.Config?
For areas that you want anonymous access use:
<location path="unsecured_path">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
Or to deny anonymous users
<location path="secured_path">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
If you deny anonymous users, you will need a way to authenticate your users. Either by Windows security which will give a challenge response when you try hitting it anonymously, or by giving the user a pretty log in page.
Typically the "demo sites" are secured with Basic Authentication. e.g. return a 401 to the browser with a basic authentication challenge that it turns into prompting for credentials. In theory, once this is done, the rest of the site is just regular stuff -- forms auth when needed.
The difficulty with this approach in ASP.NET comes in the fact that the default FormsAuthenticationProvider is hard-wired to interpret a 401 as "need to 302 to the login page." With that as a premise, getting both Forms Authentication and Basic Authentication to happen simultaneously is a challenge.
Also, the Basic Authentication built-in to IIS uses Windows as the authentication store (Active Directory or local windows accounts.) Getting it to use a different credential store is not easy to do "in the box".
http://custombasicauth.codeplex.com/ is a project I've been watching that is quite intriguing. It provides a custom Basic Authentication provider that allows you to rig up Basic Authentication from a different provider store. Pop open the source to http://custombasicauth.codeplex.com/SourceControl/changeset/view/53965#183990 and http://custombasicauth.codeplex.com/SourceControl/changeset/view/53965#183995 and see that they're just extracting the Base64-encoded header, and comparing it to an ASP.NET Membership Provider. With that as a premise, you could rig up a similar HttpModule to compare the header data to a user/pass stored in AppSettings, and include the module in your demo site. The magic sauce is that you don't set the 401 status on Authenticate, you do so at EndRequest -- after the FormsAuthenticationModule has finished it's "401 to 302 to login page". The only down-side is the <location> tags have to be used by Forms Auth or by Basic Auth, but not both. If the use-case is truely "secure the entire demo site", then it's sufficient to code the Basic Auth module to "just do it all". I'm about 2/3 of the way doing exactly this. When I'm done, I'll likely post it to GitHub as it's turning out pretty cool. Alas, the technique isn't that hard, and perhaps the description of the solution is sufficient.
And if you really want a hands-off, no-code solution, install http://custombasicauth.codeplex.com/. It even gives you pretty config windows in IIS. :D
You might want to try using a different port other than 80 for the site. It's not the most secure thing in the world if you really don't want people to know about it, but it is definitely security via obscurity. It doesn't prevent you from using your forms authentication, but you will probably need a little extra configuration to transition between http and https traffic neatly.
So if your site is http://test.org and you also set up your demo site to be http://test.org:9666, any regular traffic to the site will hit the non-demo site. That may not be clear, but I hope it gets the idea across meaningfully.
You can filter by IP - I have done this before in a backend admin system. This worked fine in my case as the only users had static IPs but most people I would expect don't have this so you will constantly have to keep tweaking to allow access.
Using some settings in IIS you can add an additional level of authorisation (you will have to Google how to do this) - users will then need to login once to view the site and again on the login screen.
You hit the nail on the head here - if you don't want people to see it, don't put it on the Internet.
Based on the above my answer would be either do nothing and rely on your login system for this (after all the only thing public is the login page) or do not make it public - use some sort of VPN.
If you're familiar w/ Apache .htacces and .htpasswd configuration take a look at http://www.helicontech.com/ape/ (Free up to 3 sites). Helicon Ape is an IIS plugin that implements htacess/htpasswd features.
Very simple password mechanism. '.htpasswd' lets control access by creating a simple text file w/ username:md5 password hashes. You can either MD5 the passwords yourself or use an online site like http://aspirine.org/htpasswd_en.html to generate. Example:
apple:$apr1$4SZNOvdK$P7b6AkKVw.gXfdxlcvENp1
orange:$apr1$fvcwHIlc$OF7Mkhv8JfELDJnRmsku7/
banana:$apr1$IoSJc9GM$xtSY4nI3KCnTtjWKwxhmx/
User/pass to gain access is:
apple:sauce
orange:juice
banana:split

ASP.NET Security: Deny Anonymous access to login page

I'm looking to deny all anonymous access to my login page and only allow people who are in a certain role to be able to view the page or anything under that directory. Is this possible? I have tried to implement this in the web.config but had no joy :(
thanks
This would only be possible in an intranet application where your users would be authenticated against Active directory. See MSDN
Otherwise, how would users log in if they don't have access to the login page?
I would rather implement access control on the actual content pages, or do an additional check when users attempt to log in and let them know that they need to be in a certain role in order to log into the system successfully.
Yes, you can...assuming that your clients are all running Windows workstations that are in the same AD domain as your IIS webservers and are using Internet Explorer (so, intranet only and not over the Internet). You want to configure IIS to only accept Integrated Windows Authentication, which will force the client workstations to use Kerberos to supply authentication information to IIS. Here's a how-to from Microsoft on how to configure this.
In web.config:
<configuration>
<system.web>
<location path="MyLoginPage.aspx">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>
</system.web>
</configuration>
The special keyword ? means anonymous users; which is documented in the element schema:
Attribute: users
A comma-separated list of user names that are denied access to the resource.
A question mark (?) denies anonymous users and an asterisk (*) indicates that all user accounts are denied access.
Basically this is the Microsoft long-winded way of saying:
Location: MyLoginPage.aspx
Deny: anonymous
This means that someone will have to be authenticated using a mechanism other than Form; such as Integrated (aka Kerberos, Windows) authentication, or with Basic authentication. You won't be able to use Forms Authentication, because they won't be able to reach the login page to login.

Mixing Forms authentication with Windows authentication

I have an (ASP.NET 3.5) intranet application which has been designed to use forms authentication (along with the default aspnet membership system). I also store additional information about users in another table which shares its primary key with the aspnet_users table.
For users who are part of our domain I store their domain account name in the secondary users table, and I want to automatically log in users whose domain account name matches a name stored in the table.
I have read the guides which are available - they're all from two years ago or more and assume that you are able to activate Windows Authentication on a separate login page that allows you to extract the domain account name. From what I can tell, though, this is not possible in IIS7 (the overall authentication method is applied on all pages and cannot be selectively deactivated, and both authentication methods can't be applied on the same page).
Is there a way of getting IIS to pass through the windows domain account name of the requesting user? I don't need proper AD authentication, just the domain name.
Actually, you can do it. Bit late for #dr_draik, but this cropped up in a google result for me so I thought I'd share some knowledge.
If you're in classic mode - Enable both Windows and Forms auth. You'll get a warning about not being able to do both at once, but you can ignore it. Then, you can spelunk around various properties like
Code:
HttpContext.Current.Request.ServerVariables["LOGON_USER"]
and fish the username out of there.
If you're in integrated mode - 4021905 IIS7 Challenge-based and login redirect-based authentication cannot be used simultaneiously leads to IIS 7.0 Two-Level Authentication with Forms Authentication and Windows Authentication which is a module that allows you to selectively change the auth for different pages.
You could always set up 2 separate application in IIS7. One would have Windows Authentication enabled. The other would be the main app with forms authentication. If a user went to the windows authentication app, the page could grab their credentials and pass it to the forms authentication app.
(More for completeness of information really)
I asked a .Net security guy this question at a conference a while back. His response was that it is technically possible, but he'd never seen it done (and to let him know if I did it and it worked!).
He suggested the way it could be done was by making your own ISAPI filter and installing it into IIS. The ISAPI filter would intercept the requests and basically do the job that IIS does when using integrated authentication, but fall back to using forms if this was not present. This involved some complicated challenge/response logic in the filter. This was for IIS6 though, so it might be different in IIS7.
Whilst this might be technically possible, I wouldn't suggest this route as it feels like a bit of a hack, and rolling your own security is never really a good idea (unless you really know what you are doing).
There are plenty articles on mixing the authenticaton by setting config to use the forms with allowing anonymous access to the app. Secondly, a page for integrated auth should be created with IIS settings set to deny anonymous and use Intgrated Authentication. There you would the magic trick by checking the "Logon_User" variable of the requets's ServerVariables collection. And finally for integrated authentication to silently sign in the user it has to have short hosted name. So if your forms authentication piece is exposed to internet via FQDN there should be some kind of redirect to the short host page. I think it is possible to achieve with just one application under IIS with 2 virtual directories.
I found a solution using no special add-ons. It was tricky and involved cobbling together elements from all the pages referenced here.
I posted about it: http://low-bandwidth.blogspot.com.au/2014/11/iis7-mixed-windows-and-forms.html
In essence, forms, windows and anon authentication have to be enabled.
The login screen should be forms based, and contain a button to trigger Windows login, that issues an HTTP 401 response challenge which if successful creates a forms based login ticket.
The issues are rather complex, and the post goes through the principles and the solution in detail.
Unfortunately, what you are trying to do just isn't supported. In order for ASP.NET to know the Windows username, you must use Windows Authentication.
You could set up another site / virtual directory that just forwarded the username information to another page. But what happens when non-Windows authenticated users try to log in?
I've got something you can try - not sure if it will work.
In the past we've used Request.ServerVariables["LOGON_USER"] but obviously for this to return a non-empty value you need to disable Anonymous access.
See this article: http://support.microsoft.com/default.aspx/kb/306359
It suggests keeping Anonymous access on the IIS side, and Forms authentication, but denying the anonymous user as follows:
<authorization>
<deny users = "?" /> <!-- This denies access to the Anonymous user -->
<allow users ="*" /> <!-- This allows access to all users -->
</authorization>

Authorization check using Global.asax

In my ASP.NET web application, I want to check every time the user is trying to get a page from my application if the user exist in the DB (of course after the first time we save the user details in the session).
I tried to use the Application_AuthenticateRequest event in the global.asax to
check for each request but the session does not exist in this event.
I need an advice for where i can put my authorization logic that i would still have the session data available (to reduce db access).
You sound as though you are "rolling your own" authentication system.
I would look into using ASP.NET's built in Forms authentication system that is commonly used with an ASP.NET Membership Provider. Built-in providers already exist for SQL Server, and you can create your own Membership Provider by inheriting from the System.Web.Security.MembershipProvider base class.
Essentially, the ASP.NET membership providers usually work by setting a client side cookie (also known as an Authentication Ticket) in the client's browser, once the client has successfully authenticated themselves. This cookie is returned to the web server with each subsequent page request, allowing ASP.NET, and thus your code, to determine who the user is, usually with a single line of code like so:
string username = HttpContext.Current.User.Identity.Name;
// The above gets the current user's name.
if(HttpContext.Current.User.Identity.IsAuthenticated)
// Do something when we know the user is authenticated.
You then should not need to store anything in the Session state. Of course, if you want to store user-specific data in a session variable (i.e. user-data that may not be part of the authentication of a user, perhaps the user's favourite colour etc.) then by all means you can store that in a session variable (after retrieving it from the DB when the user is first authenticated). The session variable could be stored based on the user's name (assuming unique names) and retrieved using code similar to the above which gets the current user's name to access the correct session object.
Using the built-in forms authentication will also allow you to "protect" areas of your website from un-authorized users with simple declarative code that goes in your web.config, for example:
<authorization>
<deny users="?"/>
</authorization>
Adding the above to your "main" web.config would ensure that none of your pages are accessible to un-authorized users (though you'd probably never do this in reality - it's just meant as an example). Using the ASP.NET Role Provider in conjunction with the Membership Provider will give you even greater granularity over who can or can't access various sections of your website.
You could use the SqlMembershipProvider (or a custom provider if you're not using MSSQL) and deny unauthenticated users from the entire application except from the login page. This check will be limited to the time of logon as the authentication ticket will be stored either in session or as a cookie on the user's machine.
More details at How To: Use Membership in ASP.NET 2.0 and
Examining ASP.NET 2.0's Membership, Roles, and Profile

Resources