Previously I’ve talked about the concepts behind securing passwords and the backend code related to that. I am now going to follow up with how to use the candor security features from a Microsoft MVC web application. The full source code can be found in the sample MVC application in candor.common on github.
All of the code here starts with the default ASP.NET MVC 4 project template with an account controller that uses forms authentication.
The http get side of rendering the login form is typical as defaulted in the normal asp.net MVC template.
[AllowAnonymous] public virtual ActionResult Login(string returnUrl) { LoginViewModel model = new LoginViewModel(); ViewBag.ReturnUrl = returnUrl; return View(model); }
I typically change the ‘user name’ field to be labeled as ‘Email Address’. This requires a change to the display name attribute in the view model.
public class LoginViewModel { [Required] [Display(Name = "Email Address")] public string UserName { get; set; } //.. } }
The http post Login action is where most of the changes are needed. The UserManager below is a static class with methods delegated to a default active provider. See the provider model articles for more on how the pattern works. Simply pass in the model property values into the AuthenticateUser method. This particular method always results in a UserIdentity instance. If the credentials are incorrect then the identity will be anonymous. Notice there is also an ExecutionResults instance passed into the AuthenticateUser method. This is filled by the method with any business errors, when applicable. A Success property is set to false if there are error messages on the ExecutionResults instance.
If the authentication succeeds then the identity is passed into a UserPrincipal which can be stored on the HttpContext.Current.User. The SecurityContextManager is another provider model static class for storing the current authenticated user. Later you’ll see how this is configured to store it on the HttpContext.Current.User.
If the authentication fails then the business layer error messages are added to the ModelState errors which can be used by the view to show the errors to the user.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public virtual ActionResult Login(LoginViewModel model, string returnUrl) { if (this.ModelState.IsValid) { var result = new ExecutionResults(); UserIdentity id = UserManager.AuthenticateUser(model.UserName, model.Password, model.RememberMe ? UserSessionDurationType.Extended : UserSessionDurationType.PublicComputer, this.Request.UserHostAddress, result); if (id.IsAuthenticated &&; result.Success) { //login successful SecurityContextManager.CurrentUser = new UserPrincipal(id); return RedirectToLocal(returnUrl); } else { //failed business layer validations for (int e = result.Messages.Count - 1; e >= 0; e--) { this.ModelState.AddModelError(e.ToString(CultureInfo.InvariantCulture), result.Messages[e].Message); } } } // failed data annotation validations return this.View(model); }
The Login.cshtml view can remain the same as in the default template. As you can see in the Login.cshtml that comes with the default template, there is a validation summary at the top of the form. This displays any error messages in from the action method ModelState. The anti forgery token is an important portion to retain.
@using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) { @Html.AntiForgeryToken() @Html.ValidationSummary(true)
One thing I usually add to the login view is a link to forgot password reset. I add it below the register link, but you can put it wherever you want. This sample is slightly different than the default template because I updated it to use T4MVC to generate urls.
<p> @Html.ActionLink("Register", MVC.Account.Register()) if you don't have an account. </p> <p> If you forgot your password, then @Html.ActionLink("request a reset", MVC.Account.ForgotPassword()). </p>
Candor security has some custom configuration sections. the first step is to add those section definitions to the web.config file. This example also includes configuration for common logging and log4net. Candor.Security does all of it’s logging using common logging.
<configuration> <configSections> <sectionGroup name="common"> <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /> </sectionGroup> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> <sectionGroup name="Candor.Security"> <section name="UserManager" type="Candor.Configuration.Provider.ProviderConfigurationSection, Candor" /> <section name="SecurityContextManager" type="Candor.Configuration.Provider.ProviderConfigurationSection, Candor" /> </sectionGroup> <sectionGroup name="Candor.Security.Cryptography"> <section name="HashManager" type="Candor.Configuration.Provider.ProviderConfigurationSection, Candor" /> </sectionGroup> </configSections> <!--other sections--> </configuration>
The Candor.Security section belongs as a direct child of the configuration node, somewhere after the configsections node. The structure of this section is similar to other provider model configuration sections. Candor security at this time only has a Sql Server implementation of UserProvider. To use that implementation use the configuration below. To use another just change the type attribute to the type of custom provider type you create.
If you use the sql server implementation, it is recommended that you create a separate connection string in the connectionStrings section for each of the 3 settings below. See the previous article for an explanation why.
The WebSecurityContextProvider configured below stores the authenticated UserPrincipal in the HttpContext.Current.User. If you are in a web application, then use this configuration. For non-web applications you’ll need to create a custom implementation.
<Candor.Security> <UserManager defaultProvider="sql"> <providers> <add name="sql" type="Candor.Security.SqlProvider.UserProvider, Candor.Security.SqlProvider" connectionNameUser="DefaultConnection" connectionNameUserSalt="DefaultConnection" connectionNameAudit="DefaultConnection" /> <!--TODO: recommended: use a different connection name with different login access to each, preferably each to separate database. --> </providers> </UserManager> <SecurityContextManager defaultProvider="Web"> <providers> <add name="Web" type="Candor.Security.Web.WebSecurityContextProvider, Candor.Security" /> </providers> </SecurityContextManager> </Candor.Security>
The HashManager is the key to cryptographic security of passwords in candor.security. It defines the algorithm used to generate random salts and hashes of the raw passwords. The SHA2 provider is the default at this time. In the future more secure algorithms will likely be created and you should begin migration to them as soon as they are available. As mentioned in the prior article you can add new algorithms here, and leave the old one. Then if the older one is in fact no longer secure, then set the ‘IsObsolete’ property to true.
Also notice the SaltModifier is optional, but it is recommended to fragment the salt used for each user’s password. When a salt is specified in the configuration then it adds one more layer that needs to be compromised in order to guess at a stolen database of user passwords. But don’t worry, salts are also generated and stored in the database per user. So compromising the configuration and users table does not give enough to even begin a dictionary attack on the user passwords.
My recommendation is to leave SaltModifier as blank in your root configuration. Then use configuration transforms to set a SaltModifier that is different for each deployment environment. If your development server is hacked, you don’t want those stolen salt modifiers usable against your production databases. Also consider security of development laptops. If one is stolen, is your production configuration stolen? You may want to limit how many developers have access to your production configuration transform. How to do this will vary per company and is beyond the scope of this article.
You could configure multiple providers here of the same algorithm with different SaltModifier setting values. Then leave IsObsolete set to false for each of them. Then users will be distributed among the providers and get different sets of configured salt modifiers.
<Candor.Security.Cryptography> <HashManager defaultProvider="sha2"> <providers> <add name="sha2" type="Candor.Security.Cryptography.SHA2HashProvider, Candor.Security" SaltModifier="" IsObsolete="false" /> <!--Optional: Add SaltModifier varied per database environment via config transform--> </providers> </HashManager> </Candor.Security.Cryptography>
You also need to configure authentication and role manager in the system.web section. Notice the authentication section uses the “None” mode. We also need to configure role manager to use the candor role provider. And finally, configure the CandorAuthenticationModule in the httpModules section. This handles recognizing users that have already authenticated. It does this using cookies.
<system.web> <authentication mode="None" /> <roleManager enabled="true" defaultProvider="CandorAuthorizationRoleProvider"> <providers> <clear /> <add name="CandorAuthorizationRoleProvider" type="Candor.Security.CandorAuthorizationRoleProvider, Candor.Security" useAuthorizationManager="true" /> </providers> </roleManager> <httpModules> <add name="CandorAuthenticationModule" type="Candor.Security.Web.CandorAuthenticationModule, Candor.Security" /> </httpModules> <!-- other non-related sections ommitted from sample --> </system.web>
This project could be made easier to put into an existing project. Making a template would be a good next step for new projects. But even better would be putting the AccountController, the view models, and the views into a NuGet package. Then if the package is improved, applications that are already using it could be updated easily with the NuGet manage packages dialog or the NuGet package console.
Next Step – NuGet Package MVC Controller from a Live Application
http://candordeveloper.com/2013/02/11/nuget-package-mvc-controller-from-live-application/
Securing user passwords (part 1)
http://candordeveloper.com/2012/12/19/securing-user-passwords/
Article source code solution – ‘candor.common’
https://github.com/michael-lang/candor-common
Provider Model Layered Architecture (more on the pattern UserManger/UserProvider uses)
http://candordeveloper.com/2012/07/05/provider-model-layered-architecture/
2 Comments