I have an ASP.NET 2010 web app that uses the default membership controls. When I log in, the Login control on the Master reveals a Log out control. When I click that, it does redirect me to Default page, but I notice that if I naviagte back to an authenticated page, it lets me in. So I added the following code when the log out link is clicked to ensure the cookie is killed,
FormsAuthentication.SignOut()
Session.Abandon()
But I can still navigate to the authenticated page. It only stops me if I actually close the browser and reopen it.
Here is my web.config....
<authentication mode="Forms">
<forms
name=".ASPXAUTH"
loginUrl="~/Account/Login.aspx"
protection="All"
timeout="2880"
slidingExpiration="true"
defaultUrl="~/Authenticated/User/UserHome.aspx"
/>
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
passwordFormat="Hashed"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="ApplicationServices"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/"/>
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="true">
<providers>
<clear />
<add connectionStringName="ApplicationServices" applicationName="/"
name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
<add applicationName="/" name="AspNetWindowsTokenRoleProvider"
type="System.Web.Security.WindowsTokenRoleProvider" />
</providers>
</roleManager>
Try this:
Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddYears(-1)
FormsAuthentication.SignOut()
Session.Abandon()
// Now, forward to a safe unauthenticated page if SignOut() doesn't already do this.
Response.Redirect("/default.aspx")
This attempts to set the ASP.NET_SessionID cookie to expire immediately. The browser should remove it from its collection. I've not run this up in VS2010, so please take my typing with a grain of salt.
Let me know if this works for you.
Related
I am working on a legacy MVC3 application which uses Forms authentication and SQLMembership Provider for authorizing user access. It has the folowing configuration:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
<membership>
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="3" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/TimeSheets" passwordFormat="Clear" />
</providers>
</membership>
<profile inherits="Timesheets.Services.UserProfile">
<providers>
<clear />
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/TimeSheets" />
</providers>
</profile>
<roleManager enabled="true">
<providers>
<clear />
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/TimeSheets" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/TimeSheets" />
</providers>
</roleManager>
If I create a new MVC application using Windows Authentication this configuration seems to be replaced with configuration like this:
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
I have tried just changing the configuration of the legacy MVC site to use this new authentication mode, but this fails to authenticate (I get an Error message "401.2.: Unauthorized: Logon failed due to server configuration.")
However the new web project runs and authenticates correctly (so it's not an AD or local permissions issue)
I had thought to try just putting all the legacy code into the new project but it is rather large and complex and getting everything lined up again in the new site could be very time consuming.
I'm hoping that changing the Auth model should be simpler and less intrusive - But what additional steps would I need to perform to configure the legacy site for Windows Authentication?
The missing part of my configuration change was in the .proj file. This is due to using the IIS Express within Visual Studio.
In order to get the Windows Auth to work in the IIS Express for debugging you need to configure it in the project settings:
The lines:
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
Need to be replaced with:
<IISExpressAnonymousAuthentication>disabled</IISExpressAnonymousAuthentication>
<IISExpressWindowsAuthentication>enabled</IISExpressWindowsAuthentication>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<connectionStrings>
<add name="ApplicationServices"
connectionString="data source="Localhost\SQLEXPRESS";
Initial Catalog=Saqib;Integrated Security=SSPI;
AttachDBFilename=|D:\SAQIB|\aspnetdb.mdf;
User Instance=true; User ID=sa;Password=angel"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="false" strict="false" explicit="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
I create a connectionstring to access localhost database. My code is below please suggest me that is it correct or not? Because when I run my login page on the browser it give this error:
Server Error in '/SAQIB1' Application.
Invalid value for key 'attachdbfilename'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: Invalid value for key 'attachdbfilename'.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Usually when you specify the db filename, you would use the |DataDirectory| placeholder. Its a substitution string used to denote the location of your db file like so:
"AttachDBFilename=|DataDirectory|database.mdf;"
In your case, you are specifying your own value and not using DataDirectory, so exclude the | characters and your setting would be:
AttachDBFilename=D:\SAQIB\aspnetdb.mdf;
I am building a MVC3 Intranet application using the default MembershipProvider, ProfileProvider, and RoleProvider connected to a SQL Server dB. If I use Forms authentication, the roles provider populates properly. When I switch to Windows authentication, the roles provider no longer populates. This is tested by putting a breakpoint in the code and looking at "Roles.GetRolesForUser()". What I suspect is happening is that the userid that is being passed to the database is 'DOMAIN\USERID' (this is what is in User.Identity.Name), whereas what is in the database is just the userid.
Since everything is default, there is not much code to post.
<authentication mode="Windows" />
<authorization>
<deny users="?"/>
</authorization>
<membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear />
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
</providers>
<properties></properties>
</profile>
<roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider" cacheRolesInCookie="true">
<providers>
<clear />
<add connectionStringName="ApplicationServices" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
<add applicationName="/" name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" />
</providers>
</roleManager>
My first thought, is can we just remove the domain before the identity is passed to the membership provider, but User.Identity.Name is get only.
What would be the best route at correcting this, without having to change my entire database to have domain\userid instead of just userid? Can this be done without having to write a custom membership/profile/role provider?
If you just want to use Windows Authentication, then you don't want to be use the SqlRoleProvider, but instead want to use the WindowsTokenRoleProvider, which will return their AD roles. (There is no reason to use a membership provider because when using Windows Authentication you can't get to the site without being authenticated already)
If you want to use Windows Authentication, but use SqlRoles then you probably want to do something like this:
http://weblogs.asp.net/scottgu/pages/Recipe_3A00_-Implementing-Role_2D00_Based-Security-with-ASP.NET-2.0-using-Windows-Authentication-and-SQL-Server.aspx
I have a "Internet Application" - "A default ASP.NET MVC 3 project with an account controller that uses forms authentication." called MyMv3App. I run the site in IIS Express using Ctrl + F5 and then I go to localhost:10382/Account/Register and I create a user "test1". Once the user is created I'm redirected to the Home page. I log off. Then I go to localhost:10382/Account/LogOn and type the username and password for the user "test1" and click on "Log On" button and the user is logged in. Cool, everything OK so far!
Next I add a new C# "Class Library" project and I name it MyCustomMembershipProvider. Then I download the ProviderToolkitSamples.msi from here http://weblogs.asp.net/scottgu/archive/2006/04/13/442772.aspx, run the msi installer, and go to the folder C:\Program Files (x86)\ASP.NET Provider Toolkit SQL Samples where all the files get installed. I then add these files to my C# Class Library project MyCustomMembershipProvider I just created, SQLMembershipProvider.cs, SecUtil.cs, SqlConnectionHelper.cs and SR.cs. (I need all these files or the C# Class Library project MyCustomMembershipProvider won't compile). Then I add a reference to System.configuration, System.Web and System.Web.ApplicationServices to the C# Class Library project MyCustomMembershipProvider. Then I build the project and then I go to MyMvc3App and
I add a reference to the MyCustomMembershipProvider project.
Note: Forgot to mention that I changed the namespace for all four files in the project
MyCustomMembershipProvider to "namespace MyCustomMembershipProvider" and also I renamed the class name to MyCustomMembershipProvider. And also in SQLMembershipProvider.cs line 110 I changed it from name = "SqlMembershipProvider"; to name = "MyCustomMembershipProvider";
Next I change the web.config file membership section from this:
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
to this:
<membership defaultProvider="MyCustomMembershipProvider">
<providers>
<clear/>
<add name="MyCustomMembershipProvider" type="MyCustomMembershipProvider.MyCustomMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
The entire web.config looks like this now:
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=152368
-->
<configuration>
<connectionStrings>
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="1.0.0.0"/>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
<membership defaultProvider="MyCustomMembershipProvider">
<providers>
<clear/>
<add name="MyCustomMembershipProvider" type="MyCustomMembershipProvider.MyCustomMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages"/>
</namespaces>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Now I do the exact same thing I did in the first paragraph; I go to localhost:10382/Account/Register and I create a user, this time I call the user
"test2". Once the user is created I'm redirected to the Home page. I log off. Then I go to
localhost:10382/Account/LogOn to log in again and type the username and password for the user "test2" and click on "Log On" button and I get the error message:
Login was unsuccessful. Please correct the errors and try again.
The user name or password provided is incorrect.
Why? What did I miss? I haven't touched anything besides the namespace and that name variable in SQLMembershipProvider.cs in line 110.
I tried to understand why so I googled and found that adding the machineKey element might work. So I went to this site http://www.developmentnow.com/articles/machinekey_generator.aspx and generated a ASP.NET 2.0 machineKey and copy pasted it into web.config's system.web element:
<machineKey
validationKey="A5E72C3BF96D34B9401278890361AA0949EAE806B124573AC3C1A8D77936B4E42BB1374D1DA443706C4E575B7F1234CB48F4CF52444CB4B1F343994752416569"
decryptionKey="47869B2D1F1D3EBC92FCC4C2D7B0EFB707535925E116AEF85F470E138A6C8CB5"
validation="SHA1" decryption="AES"
/>
I once again did the exact same thing as before; I go to localhost:10382/Account/Register and I create a user, I'm calling the user "test3" this time. Once the user is created I'm redirected to the Home page. I log off. Then I go to localhost:10382/Account/LogOn and type the username and password for the user "test3" and click on "Log On" button and BAM! the user is once again logged in!?
Why did I have to manually configure a machineKey with a generated validationKey and decryptionKey in web.config for the MyCustomMembershipProvider to be able to work with the login page? As far as I have seen there is not a single article / page / blog that talks about adding a machineKey element to your web.config for your custom membership provider to be able to work!
UPDATE 1: Adding hashAlgorithmType="SHA1" works as well:
<membership defaultProvider="MyCustomMembershipProvider" hashAlgorithmType="SHA1">
Funny thing though is that MSDN says SHA1 is the default!?
hashAlgorithmType
Optional String attribute.
Specifies the name of the encryption algorithm that is used to hash password values.
The value of this attribute corresponds to the name attribute of a nameEntry element in the cryptoNameMapping configuration section. For information about specifying a custom hash algorithm, see Mapping Algorithm Names to Cryptography Classes.
The default is SHA1.
UPDATE 2:
After reading up on Microsoft latest technologies I decided to share some of the findings I discovered regarding their latest Mebership provider; SimpleMembership. I'm at the stage in my personal project where I've decided to drop the CustomMembershipProvider from the ASP.NET 2.0 days I built and use SimpleMembership provider instead. Why? Well you have all the info you'll ever want to know in the following blogpost by Jon Galloway. I'm also adding some more links to resources worth checking out. According to Microsoft SimpleMembership is the successor to ASP.NET 2.0 Membership.
http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx
http://mvccentral.net/Story/Details/tools/kahanu/securityguard-nuget-package-for-asp-net-membership
http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/
http://blog.osbornm.com/archive/2010/07/21/using-simplemembership-with-asp.net-webpages.aspx
http://blogs.msdn.com/b/rickandy/archive/2012/08/15/initializesimplemembership-attribute-and-simplemembership-exceptions.aspx
I have an ASP.NET 2010 app. When I go through the registraiton process, I correctly get logged in. However, if I just try to log in later, ValidateUser always returns false'
blnSuccess = Membership.ValidateUser(strUserName, strPassword)
I've stepped through to ensure the correct username & password are being sent in and that this person is in the db (Express). Here's my Web.Config....All just regular stuff.
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>
</connectionStrings>
<authentication mode="Forms">
<forms
name=".ASPXAUTH"
loginUrl="~/Account/Login.aspx"
protection="All"
timeout="2880"
slidingExpiration="true"
/>
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="ApplicationServices"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/"/>
</providers>
</membership>
Please take a look and see if this help you:
Membership.ValidateUser always returns false after upgrade to VS 2010 / .NET 4.0
Why might Membership.ValidateUser return false when the user is approved and is not locked out?