My web app uses Windows authentication. All other authentication methods are disabled.
It works at first; User.Identity.Name returns "MYDOMAIN\myuser." However, if I wait 131 seconds (yes, I timed it, though I'm not sure it always takes exactly that long) and reload the page, User.Identity.IsAuthenticated = false and User.Identity.Name = "". At this point I can just reload the page and it works again, for another 131 seconds of inactivity.
Relevant parts of web.config:
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
<identity impersonate="false" />
...
<security>
<authentication>
<windowsAuthentication enabled="true" />
<anonymousAuthentication enabled="false" />
</authentication>
</security>
More information, possibly relevant:
My solution is deployed to two different IIS applications. The first one is for internal users; it just uses Windows authentication. The second one is for external users; it uses anonymous authentication (in the root folder only) and forms authentication. I'm only having problems with the internal site.
The web.config file under the Account folder was allowing anonymous authentication (the one I posted with my question is the main web.config). Not sure how that happened, but removing it fixed the problem.
Related
For more than a couple of years, we have successfully used the approach outlined in this post for enabling mixed-mode authentication in our Asp.Net app:
https://stackoverflow.com/a/7735008
We have 2 pages, Login.aspx and WindowsLogin.aspx with appropriate elements as highlighted in above post. Everything has been working fine until recently when it broke and we are unable to figure out why or when it broke down (for a few months, we had been working on major new features in our app, we added a few managed modules and other things, but I have tried eliminating them one at a time with no avail).
We have this defined for our global authentication:
<system.web>
<authentication mode="Forms">
<forms cookieless="UseCookies" loginUrl="~/Login.aspx" slidingExpiration="true" timeout="10" />
</authentication>
</system.web>
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="true" />
<basicAuthentication enabled="false" />
<digestAuthentication enabled="false" />
<windowsAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
Then appropriate elements exactly as in the referenced post. Now when I visit WindowsLogin.aspx directly in browser, it 302 redirects me to Login.aspx with return url set to WindowsLogin.aspx. I have tried simplifying web.config by eliminating all unneeded configuration until all remained was bare bones authentication and other pieces. Still WindowsLogin.aspx redirects to Login.aspx (i.e. Forms authentication is kicking on WindowsLogin.aspx page).
The interesting thing is if I change loginUrl to WindowsLogin.aspx (with everything else remaining exactly same), then WindowsLogin.aspx shows me the native browser authentication challenge as expected.
I have tried and exhausted all options I could think of to get this work with loginUrl set to Login.aspx, but it simply doesn't work.
I enabled IIS tracing rules for 302 redirect and captured a log file where WindowsLogin.aspx was redirecting to Login.aspx (with loginUrl set to Login.aspx). The trace file is available here:
http://imbibe.in/public/fr000001.xml
Can someone please help me in figuring out why is FormsAuthentication module kicking on WindowsLogin.aspx page when its WindowsAuthentication module that is supposed to do the auth there. And why does just switching the login url raises the 401 challenge on Windows Auth page. We are working with IIS 7.5 on Win Server 2008.
UPDATE: I created a simple web app with only 3 pages, Default, Login and WindowsLogin and followed the mixed-mode authentication approach on the same server and it worked. Which obviously means its something in our application/app pool that is interfering. I am hoping the IIS Trace log provided can shed some light on it.
If I completely remove <authentiction mode="Forms"> from our app's web.config (which essentially means no auth is enabled), then Login and WindowsLogin pages work fine.
But with the current configuration only, going to WindowsLogin redirects back to Login.aspx.
You need to add some location exceptions in your web.config file (anywhere outside the regular System.Web section):
<!-- Providing it's in the root - No leading slashes! -->
<location path="WindowsLogin.aspx">
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
This will allow all non-authenticated FORMS users to access the page. Otherwise your users will keep getting redirected to the FORMS login page (as they should).
I've recently migrated a web app from .Net 3.5 to .Net 4 and changed the app pool to Integrated mode in IIS 7.5. This app has 2 parts: the first is open to the public and the second is by login only. I use forms authentication for login which is configued thusly in the root web.config:
<authentication mode="Forms">
<forms loginUrl="~/private/login.aspx" protection="All" timeout="20" name=".ASPXAUTH" path="/" requireSSL="false" slidingExpiration="true" defaultUrl="~/private/default.aspx" cookieless="UseCookies" enableCrossAppRedirects="true" />
</authentication>
In the root web.config I have the default authorization to to deny unauthenticated users, thusly:
<authorization>
<deny users="?" />
</authorization>
BUT I have the setting below configured in the root web.config to allow everyone to see the welcome page:
<location path="Default.aspx">
<system.web>
<authorization>
<allow users="?,*" />
</authorization>
</system.web>
This has been working great for years but now, if I don't explicily put Default.aspx in the URL, the forms redirect module causes the login page to be served. I've verified that I have my default pages configured correctly and they are enabled in IIS7. I have also tried specifying them in web.config. I have verified that the DefaultDocumentModule is sequenced before the DirectoryListing module.
If I remove the element the problems "goes away" but the effect would be to default to allow all users and this is completely undesireable.
I'm out of ideas. Suggestions?
Thanks
I
Seems like some kind of default doc issue. If you look in IIS Manager at the site, what is in the "Default Document" list. Is it possible that something other than Default.aspx is higher in the list? If something matching this is found in your root web, it will attempt to go there first and thus be redirected to login.
Are you explicitly setting the default document in your web.config? as in:
<defaultDocument enabled="true">
<files>
<clear />
<add value="Default.aspx" />
<add value="Default.htm" />
<add value="index.htm" />
<add value="index.html" />
<add value="iisstart.htm" />
</files>
</defaultDocument>
OK, I had a Microsoft Premier Support Engineer dig into this for me. We sat down together at my workstation and went through (a) the environment and app configuration and (b) possible solutions.
He referenced this MS "Fast Publish" article which suggests that I remove the ExtensionLessURL handlers from IIS via MMC. Well, we're a huge organization with servers out the wazoo and I could not guarantee that this change would always be honored so I didn't want to do that. We tried using web.config to remove them but that did not work.
So, I showed him this solution from another StackOverflow thread (posted by Dmitry.Alk) and he said it was a good work-around for now. It works great for this particular situation.
The Fast Publish article references this hotfix A update is available that enables certain IIS 7.0 or IIS 7.5 handlers to handle requests whose URLs do not end with a period which I've got to sell to our IT "department".
I don't call what I've written here an "answer" but I wanted to share what I've come to learn in case others happen upon this thread.
We are converting some of our web applications that used to run under forms authentication, to now run as windows authentication. I want to recreate the page security that forms authentication had with minimum modification to the actual pages. I was able to recreate the effect I want, with a simplified web app. I am running the app on Server 2008 R2 integrated pipeline IIS 7.5.
I created a simple 3 page app using windows authentication. The three pages are:
Openpage.aspx, that is open to any authenticated user
Blockedpage.aspx that is blocked to all users (symbolic of a directory or page that would be blocked to a subset of users based on user role)
ErrorPage.aspx,if blockedpage.aspx is accessed (and rejected) the application should forward to ErrorPage.aspx where the user gets generic information about the application.
The Web.Config for the app:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Windows"/>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
<location path="blockedpage.aspx">
<system.web>
<authorization>
<deny users="*"/>
</authorization>
</system.web>
</location>
<system.webServer>
<httpErrors errorMode="Custom" >
<remove statusCode="401" subStatusCode="-1" />
<error statusCode="401" path="/development/simplesecurityapp/errorpage.aspx" responseMode="ExecuteURL" />
</httpErrors>
<validation validateIntegratedModeConfiguration="false" />
<defaultDocument>
<files>
<clear />
<add value="openpage.aspx" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
(If I don’t attempt to redirect the 401 errors at the asp.net level, I just get the standard “not authorized message” which is not the effect I want to give my users.)
However, I am getting an error that I don’t understand – every time the server resets, the app stops working. IIS simply returns 401 errors until the browser pops up a manual log-in control, which cannot be satisfied. (I never want my users to be presented with the browser log-in prompt)
However, if I replace the httperrors section once the application is set up (either by editing the web config, or updating it with the server GUI) removing the section, accessing the page, and then adding the section back, the application starts to work as expected, and continues to until the server is rebooted, at which time it starts giving users the manual login pop-up again, which they cannot resolve.
1) Is this the correct way to secure an app with windows authentication (is there a better way to configure a directory inaccessible like in forms, yet still supply a custom error page?)
2) Is this an effect of the integrated pipeline and why is it working this way?
You're trying to provide content over a transport error message.
Forms allows you to do this because it's composed of layer 7 stuff, like 302s and 200s. 401s are interpreted by the client browser as "the server didn't like my credentials, so raise a dialog box to ask for new ones".
An authenticated page produces at least 1 401 in order to become authenticated; that you're overloading the "error" for something else is probably the root of the problem.
I'm not sure there's an elegant way of doing what you want.
I have multiple web applications that I've built for our intranet. I wanted to allow users to not worry about logging in, so these apps pull the currently logged on user when they hit the site. I used this code for this to happen:
Dim userName As String = User.Identity.Name
CurrentUser = userName.Substring(userName.IndexOf("\") + 1)
This works like a charm, no issues here. The next step is to query Active Directory for that logged in user to pull various information. How I currently have it coded, it works like a charm on the devleopment side (typical because I'm not running IIS).
The problem becomes when I publish it to my IIS server (Windows Server 2008 R2 running IIS 7.5), I get error messages that point to the specific line in my code that queries Active Directory. The interesting part is these apps were working great last week. They broke after my server admin did the latest batch of Windows Updates (please note, I am running them using .Net Framework 4.0)
Before I had each app setup so that Windows Authentication was Enabled, the other Authentication types were disabled. For providers, Negotiate is #1, NTLM is #2. For Advanced Settings, Extended Protection = Off, and Enable Kernel-mode authentication is checked.
My web.config has the following set:
<customErrors mode="Off"/>
<authentication mode="Windows" />
<authorization>
<deny users="?"/>
</authorization>
These were the settings I had, and everything worked like a charm. Now to get it to somewhat work I need to swap the providers around so NTLM is #1 and Negotiate is #2. Because of this, the user's credentials are not properly passed in and the AD query fails. This is the coding I'm using for the query:
Dim adSearchRoot As New DirectoryEntry("LDAP://DC=[DOMAIN],DC=com")
Dim adSearch As New DirectorySearcher(adSearchRoot)
adSearch.Filter = "(&(ObjectClass=User)(sAMAccountName=" & CurrentUser & "))"
Dim searchResult As SearchResult = adSearch.FindOne()
Ever since the updates, when loading the site with Negotiate in front, it fails on that bottom line because I don't have a username/password set for the DirectoryEntry. Even when I set a username/password, it still does not 100% work like it used to.
So my question becomes, what do I need to do so that the user accesses the site, I can know their username, and can query active directory without requiring the use of a username/password in the DirectoryEntry??
Is it a setting in IIS?
Or do I need to recode?
web.config setting perhaps?
Do I need to revert server updates and figure out which one causes the break to occur?
Thanks for the advice in advance. If you have any questions to help answer the question, let me know.
UPDATE
I tried as Matt suggested by adding the following clip to my web.config file:
<security>
<authorization>
<add accessType="Deny" users="?" />
</authorization>
</security>
This did not work. I did some reading, and then altered this section further:
<location path="Default Web Site/NameOfApp">
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="false"/>
<windowsAuthentication enabled="true">
<providers>
<add value="Negotiate" />
<add value="NTLM" />
</providers>
</windowsAuthentication>
</authentication>
<authorization>
<add accessType="Deny" users="?" />
</authorization>
</security>
</system.webServer>
</location>
In doing this I also removed the string that was higher up in my web.config section. This did not work either (fyi, this was a great reference http://www.iis.net/ConfigReference/system.webServer/security/authentication)
I then tripped across this article: http://social.technet.microsoft.com/Forums/en/winserverDS/thread/7deba16b-295a-4887-98f9-9f291ed49871 which seemed to be a similar situation. This article eventually referenced "Double Hops", after looking into this and trying a few things, this didn't solve my issue either.
Next Step
I am going to try a new IIS 7.5 implementation on a different Server 2008 R2 system and essentially start from scratch, to see if the problem recreates or not.
ANY new suggestions would be of great help.
I was able to make the code execute without any problems on a Windows 2008 Server. I created a new .NET 4.0 application pool and assigned it to the web application. I changed the web.config to deny anonymous access and use Windows authentication. The code executed without exception.
Looking at your web.config clip, I wonder if this might be what you're missing:
<system.webServer>
<security>
<authorization>
<add accessType="Deny" users="?" />
</authorization>
</security>
</system.webServer>
It's important that you have this authorization section within the system.webServer section. IIS 7 uses the system.webServer section to store some settings that were part of the metabase in IIS 6.
I had this same problem. Here's how I solved it:
Use overload 4 of 5 for the DirectoryEntry constructor which allows for not only a path, but a username, and a password as well. So, your AD connection should look like this:
DirectoryEntry adSearchRoot = new DirectoryEntry("LDAP://DC=[DOMAIN],DC=com", "DOMAIN\Username", "Password");
DirectorySearcher adSearch = new DirectorySearcher(entry);
Now, instead of "DOMAIN\Username", use a service account and then for the password, obviously, use the password for the service account.
I think as long as the service account is a member of the "Domain Users" group, then you should be able to query AD no problem.
I tryed this ways:
Request.ServerVariables["LOGON_USER"]
or
HttpContext.Current.User.Identity.Name
or
User.Identity.Name
-- If i run it by F5 from VS2010, it runs OK.
-- If i run it on IIS (I tryed it on 5.1 and 6.0, other IIS i can't use) there are empty strings.
In web.config i have:
<authentication mode="Windows"/>
<authorization>
<allow users="*"/>
</authorization>
so, all users should by autentificated.
Maybe, there should be more things in web.config.
I tryed it in IE, Firefox, and Chrome.
I post this question before, but there was some misleading information, so i post it again.
so, all users should by autentificated.
Exactly. All users include anonimous.
Any web browser will attempt an anonymous request at first, if it's successful it won't try to authenticate. So you want to deny anonymous requests:
<authentication mode="Windows" />
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
Note that the order of items in the authorization element is important - they're like any access rules in that they're processed from top to bottom.
In this case the ? is anonymous users and * is all users (including anonymous) but as the deny anonymous user statement comes first - they will be denied and never get to see the allow statement which allows everyone else.
Also, if this is an ASP.NET MVC 3 web application, there're some quirks to be heedy of - please correct me if I'm wrong as I don't recall all the details right now:
<appSettings>
<add key="autoFormsAuthentication" value="false" />
</appSettings>
The autoFormsAuthentication has to be disabled to enable Windows authentication in an MVC 3 web application - or it was anyway, it might have been fixed by now but as it took quite some time to figure it out, I'm including it here. The symptom when not disabling it is every authentication request is redirected to the account forms url (which you might not even have).