I have a functioning .NET MVC application that uses Windows Authentication. Because of our use of shared computers, Windows Authentication will not work for us; we need to switch to Forms Authentication, but we still want to authenticate against Active Directory. I've read various tutorials on this subject, but none of these seem to work and none show how to convert an existing Windows Authentication application to one that uses Forms Authentication against AD. What do I need to do to make this transistion?
Here is the web.config for my application:
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="Wellness.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-Wellness-20130715090235;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-Wellness-20130715090235.mdf" providerName="System.Data.SqlClient" />
<add name="tt" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=tt-20130805140115; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|tt-20130805140115.mdf" providerName="System.Data.SqlClient" />
<add name="WellnessEntities" connectionString="metadata=res://*/Models.WellnessModel.csdl|res://*/Models.WellnessModel.ssdl|res://*/Models.WellnessModel.msl;provider=System.Data.SqlClient;provider connection string="data source=MSSQL;initial catalog=Wellness;persist security info=True;user id=Wellness_User;password=xGopher2008;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<system.web>
<httpRuntime maxRequestLength="10240"/>
<customErrors mode="Off"></customErrors>
<compilation debug="true" targetFramework="4.5">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
<authentication mode="Windows" />
<authorization>
<allow roles="b-hive\AllStaff"/>
<deny users="*"/>
</authorization>
<pages controlRenderingCompatibilityVersion="4.0">
<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.Optimization" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
<profile defaultProvider="DefaultProfileProvider">
<providers>
<add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</profile>
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<roleManager defaultProvider="DefaultRoleProvider">
<providers>
<add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</roleManager>
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
</providers>
</sessionState>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
<applicationSettings>
<Wellness.Properties.Settings>
<setting name="Setting" serializeAs="String">
<value />
</setting>
</Wellness.Properties.Settings>
</applicationSettings>
</configuration>
You have two options. One, use a provider and capitalize on the built-in framework infrastructure. Two, use directory services and code everything yourself. The latter will give you complete control and flexibility. The former will give you ease-of-implementation.
Using a provider:
(1) Specify forms-auth in your web.config:
<authentication mode="Forms">
<forms name=".ADAuthCookie" loginUrl="~/Login.aspx" defaultUrl="~/Default.aspx" timeout="05"/>
</authentication>
(2) Add an LDAP connection string:
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP://fqdn.co/DC=fqdn,DC=co"/>
</connectionStrings>
(3) Add a membership provider (provide the connection string name as the one defined above):
<membership defaultProvider="MyADMembershipProvider">
<providers>
<add name="MyADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ADConnectionString" attributeMapUsername="sAMAccountName" />
</providers>
</membership>
For the provider, you will have to find out the token and version based on your ASP.Net version.
(4) Create a login page (Login.aspx as specified in forms-auth loginurl) and use the asp.net's login control:
<asp:Login ID="LoginUser" runat="server" ....
(5) You are good to go.
Doing it yourself:
(1) Specify forms-auth in your web.config:
<authentication mode="Forms">
<forms name=".MyAuth" loginUrl="~/Logon.aspx" defaultUrl="~/Default.aspx" timeout="05">
</forms>
</authentication>
(2) Obtain reference to System.DirectoryServices
and System.DirectoryServices.AccountManagement
(3) Create a method for authentication in your logic layer (something on the lines of):
<DirectoryServicesPermission(Security.Permissions.SecurityAction.LinkDemand, Unrestricted:=True)> _
Public Shared Function Authenticate(ByVal domainName As String, ByVal userAlias As String, ByVal userPassword As String) As Boolean
Try
Dim context As PrincipalContext = New PrincipalContext(ContextType.Domain, domainName)
If context.ValidateCredentials(userAlias, userPassword, ContextOptions.Negotiate) Then
Return True
Else
Return False
End If
Catch ex As Exception
Throw
End Try
End Function
The above code snippet is in VB as I am not too confident on C#, but you get the idea.
(4) Create a login page and call this method on login from your code-behind:
isAuthenticated = LogicLayer.Authenticate(domainName, userName, userPassword)
(5) If successful, i.e. isAuthenticated returns true, then set the forms-auth cookie:
FormsAuthentication.SetAuthCookie(userName, isRememberMe)
(6) You are good to go.
Note:
Please note that using forms-auth will open you to security implications as the credentials will travel in text form over the wire. You will have to take care of appropriate security measures yourself. SSL will help you in an easiest way.
Also note that, you might have to take care of a few more things like <identity impersonate="true" />
to enable access from users' account instead of app-pool identity. You also, will need to set anonymous
auth in IIS.
Edit:
I did not notice earlier that yours is an MVC app. Some of the points above are WebForms specific (like controls and code-behinds). So, please ignore that. Otherwise, I hope you got the idea behind it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With