Change Password Issue in AspNet MembershipProvider - c#

I am using AspNet Membership Provider in MVC 3.
I am facing issue in change password.
I have two functionality in my project
Forgot password : ask security question and based on security answer change password.
Admin change password: a admin can change password of any user without knowing old password or security answer.
Now the issue is that for functionality # 1, i have to make changes in web config for making requiresQuestionAndAnswer="true" for change password so that i can change password only if security answer is valid.
<membership>
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
and i am using below code for changing password in forgot password:
string resetPassword = res.ResetPassword(model.PasswordAnswer);
MembershipService.ChangePassword(model.Username, newPassword, model.NewPassword)
now for situation # 2, where for admin i wants facility to change password of any user without knowing old password or security answer. which is only possible (as i know) by making requiresQuestionAndAnswer="false" .
Note:I am using separate MVC AREA for admin part, so may be a another web config can do some magic.
please suggest how can i have have both the features (reset password with security answer and without security answer) together in single application.
Thanks a lot

Finally got the answer:
In web config i set the requiresQuestionAndAnswer="true" so this resolves the issue#1, now for forgot password a security answer is required.
and for issue#2 where i want the facility for admin to change password of any user without knowing old password or security answer. I have used Reflection for it to change the value of private variable _RequiresQuestionAndAnswer to false then reset the password and then again set its value to true:
var _requiresQA = Membership.Provider.GetType().GetField("_RequiresQuestionAndAnswer",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
//change the value in the private field
_requiresQA.SetValue(Membership.Provider, false);
//do the reset
tempPassword = user.ResetPassword();
//set it's original value
_requiresQA.SetValue(Membership.Provider, true);
I got this solution at : http://djsolid.net/blog/asp.net-membership---change-password-without-asking-the-old-with-question-and-answer

Related

Authenticating an AD user using Membership Provider

I am running into a weird problem.
Synopsis
My login page can authenticate against SQL uses or AD users. To identify if a user is an AD user, user name should contain a backslash.
The logic for SQL works fine, but I am getting the most generic error (Object reference not set to an instance of an object.) when authenticating a user against AD.
Details
For SQL users, I've CustomSqlMembershipProvider(). The call is like this:
if(Membership.Provider.ValidateUser(userName, userPassword))
userAuthenticated = true;
The class CustomSqlMembershipProvider() sends the credentials to SQL database.
For AD users, I've this logic:
if (Membership.Providers["ADMembership"].ValidateUser(userName, userPassword))
userAuthenticated = true;
This above if statement is generating the error Object reference not set to an instance of an object.
Web.config
<add name="ConnectionStringAD" connectionString="LDAP://it.CompanyName.local" />
...
<membership defaultProvider="CustomSqlMembershipProvider" userIsOnlineTimeWindow="30">
<providers>
<clear/>
<add name="CustomSqlMembershipProvider"
type="Authentication.MembershipProviders.CustomSqlMembershipProvider"
connectionStringName="SqlProviderConnectionString"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="/" />
<add name="ADMembership"
type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ConnectionStringAD"
connectionUsername="it\LDAPuser"
connectionPassword="LDAPuserPassword"
connectionProtection="Secure"
maxInvalidPasswordAttempts="5"
attributeMapUsername="sAMAccountName" />
</providers>
</membership>
I strongly think that there is some small issue, but I could not figure it out.
Software
Visual Studio 2010
.NET 4.0
Server 2008 R2 with SP2 (10.50.4000)
IIS 7.5
Its not an answer directly but few suggestion to narrow down the problem:
Try changing defaultProvider in web.config. Set it to ADMembership.
Break down the call:
if (Membership.Providers["ADMembership"].ValidateUser(userName, userPassword))
userAuthenticated = true;
to
var activeDirectoryProvider = Membership.Providers["ADMembership"];
if(activeDirectoryProvider != null)
{
userAuthenticated = true;
}
else
{
Log("activeDirectoryProvider is null");
}
This is wild guess :). Rename "ADMembership" to "ADMembershipProvider" suffixing "Provider" just in case some convention stuff.

How does Membership.ValidateUser method access a database?

I wanted to build a membership system at the beginning of my MVC project and I used Membership.ValidateUser method to verify credentials. However I could not understand how does this method access my database and check my email and password informations.
[HttpPost]
[ActionName("Login")]
public ActionResult Login(LoginModel loginModel)
{
if (Membership.ValidateUser(loginModel.Email, loginModel.Password))
{
FormsAuthentication.SetAuthCookie(loginModel.Email, true);
return Json(true);
}
return new JsonNetResult()
{ Data = new { Error = true, Messages = new[] { new { Message = "Wrong username or password" } } } };
}
It' used the MembershipProvider specified on your Web.config file to validate the user. By default, it uses DefaultMembershipProvider
Membership.ValidateUser method at first check membership defaultProvider in your web.config file which matches with name that you provide like below:
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider"
connectionStringName="Context" applicationName="myapp"
enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" requiresUniqueEmail="true"
passwordFormat="Hashed" minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="0" />
</providers>
</membership>
Above configuration will call .net framework abstraction class MembershipProvider -> ValidateUser (abstract method) which implementation lies in SqlMembershipProvider -> ValidateUser method that you have configured in your web.config file [like above].In that method it simply call two store procedures of your database , first one is aspnet_Membership_GetPasswordWithFormat which check your application name, username , last login activity date and current time and based on that makes you authenticate and secondly call to other store procedure which name is aspnet_Membership_UpdateUserInfo which is self explanatory as you realize which update aspnet_membership table with columns like islockedout, lastlockoutdate, failedpasswordattemptcount.. etc.
Hope this helps you.

Password Policy in ASP.NET Profile (Membership)

In change password page, we have this code, So if we want to change Password Policy into "StrongPolicy", have we a way or is it by default?
Also can we change it to weak policy ?
I read MSDN but couldn't find it.
Membership mu ;
mu=Membership.GetUser(txtUserName.Text);
mu.UnlockUser();
var newPass= mu.ResetPassword();
mu.ChangePassword(newPass,TxtPassword.Text);
If you are using MVC 5 (possibly MVC4, havent checked).
Theres a nice easy way of changing this without changing the config. In your solution explorer, go to
'App_Start' > IdentityConfig
Here you will see a passwordvalidator, changing these settings will allow you to alter the complexity of passwords required for your site:
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
By default the memebership provider in .net restricts you to have password of length 7(atleast) and of which one character must be alpha-numeric.
Although there many ways by which you can change that. You can check Changing password policy setting in membership provider.
Using minimum length and non-alphanumeric character
<membership ...>
<providers>
<add minRequiredPasswordLength=10 minRequiredNonalphanumericCharacters=2 .../>
</providers>
</membership>
Using regular expression
<membership ...>
<providers>
<add passwordStrengthRegularExpression=
"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$" .../>
</providers>
</membership>
The above code is from the same site.
By default ASP.NET Membership enforces strong passwords. If you want to make it weaker, by changing the configuration settings in Web.config
<membership>
<providers>
<add passwordStrengthRegularExpression= "" .../>
<add minRequiredPasswordLength=... minRequiredNonalphanumericCharacters=2 .../>
</providers>
</membership>
MSDN
By default, the ASP.NET membership providers enforce strong passwords.
For example, the SqlMembershipProvider and the
ActiveDirectoryMembership providers ensure that passwords are at least
seven characters in length with at least one non-alphanumeric
character. Ensure that your membership provider configuration enforces
passwords of at least this strength. To configure the precise password
complexity rules enforced by your provider, you can set the following
additional attributes:
More information :
http://msdn.microsoft.com/en-us/library/ff649487.aspx

Webmatrix Reset password

I want to know how to set a password using mvc4 providers without knowing the old password ?
I want to make a forgot password function, where the user receives a secure link via email and then clicks the link, gets directed to the my application and then has to fill in only the new password, no security questions needed.
It was easy to do this with the membership providers that came with mvc3. I'm now using the simple membership providers that come with mvc4 and I'm having trouble getting it working.
the code so far looks as simple as:
MembershipUser user = Membership.GetUser( cust.Email );
String pass = user.GetPassword();
Boolean success = WebSecurity.ChangePassword( cust.Email, pass, model.Password );
It currently gives error on the above line that calls GetPassword() with the error :
Specified method is not supported.
I'll show the relevant section in the web.config also here :
<system.web>
<roleManager enabled="true" defaultProvider="SimpleRoleProvider">
<providers>
<clear/>
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear/>
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData"
enablePasswordRetrieval="true" enablePasswordReset="true" passwordFormat="Encrypted" requiresQuestionAndAnswer="false"
requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="5" minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10" />
</providers>
</membership>
Above I tried to add the attributes you use for the providers in mvc3 but it doesn't seem to be applicable here.
WebSecurity.GeneratePasswordResetToken generates and returns a unique string.
WebSecurity.ResetPassword uses that token to change the password.
Give the user a link to an action with the token as a parameter, then give them a simple form to change their password.

How do I go about Authorization in MVC 2?

How do I go about Authorization in MVC 2?
I want to use AD groups/roles rather than the default that is provided. That seems to be "AspNetSqlMembershipProvider".
Anyway I put :
[Authorize(Users = "username")]
public ActionResult About()
{
ViewData["Welcome"] = "Welcome About";
return View();
}
And then loading the page gives me: The connection name 'ApplicationServices' was not found in
the applications configuration or the connection string is empty.
Line 34: <providers>
Line 35: <clear />
Line 36: <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="/" />
Line 37: </providers>
Line 38: </membership>
I read this stackoverflow, but after creating a custom class AuthorizationAttribute extending ActionFilterAttribute ContextCache, IoC and a number of other things could not resolve, and not really sure where to go from there. I also read this stackoverflow and it suggests going about it differently, starting to get confused.
How do I go about using AD groups rather than AspNetSqlMembershipProvider in MVC app ?
Bonus question: Say I have a "Edit" button a page. Can I add logic to decide whether to render this button based on the Authorization ?
Thank you for your help.
Edit: some further information.
I do not intend to block or allow ALL access to this site.
I intend to have 3 basic user groups differentiating level of access, i.e. Super Admin, Admin,
Basic Access.
There will be no log in form, when the user hits the site we will check which group the user is a member of- then the page renders based on that.
So for example, user 'bob' in 'Basic Access' group will hit the page and buttons/actions like "Edit", "Delete" are disabled, so basically a read only group. But user 'jim' in group 'Super Admin', has all actions/buttons available to him. How could I achieve this ?
You should look into Windows Authentication
Still use the Authorize attribute on your controllers/actions, but configure your site to use Windows Authentication instead.
Bonus answer: To check authentication and authorization in code, you can use one of the following from a controller:
this.User.Identity.IsAuthenticated
this.User.Identity.Name
this.User.IsInRole("roleName")
The answers to use Windows authentication work great, with the following caveats.
First, the server must be joined to your Domain. And it has to have free AD access if there are any firewalls in place.
Second, you have to be ok with having a popup dialog for login, rather than using a form based login.
If you need AD with forms login, then there's more work involved. Can you be more specific about your needs?
well, you can restrict access to the site via webconfig.
<authentication mode="Windows" />
<authorization>
<allow roles="[YOURADSERVER]\[YOUR AD GROUP]"/>
<deny users="*"/>
</authorization>
this will block any others not listed in the given ad groups.
in IIS you will need to disable anon access and enable windows auth

Categories