Recently I had to implement Create User, Change Password, Password Reset (Recovery) in SharePoint 2010. I decided to use the OOTB ASP.NET login controls for this. Mostly these controls just worked in SharePoint 2010 as they do in ASP.NET. There were however a few issues that need to be worked around.
1. System.ArgumentException: Exception of type ‘System.ArgumentException’ was thrown. Parameter name: encodedValue
First and foremost is the exception above. The full stack is as follow:
[ArgumentException: Exception of type ‘System.ArgumentException’ was thrown. Parameter name: encodedValue] Microsoft.SharePoint.Administration.Claims.SPClaimEncodingManager.DecodeClaimFromFormsSuffix(String encodedValue) +26166622 Microsoft.SharePoint.Administration.Claims.SPClaimProviderManager.GetProviderUserKey(String encodedSuffix) +79 Microsoft.SharePoint.SPGlobal.CreateSPRequestAndSetIdentity(SPSite site, String name, Boolean bNotGlobalAdminCode, String strUrl, Boolean bNotAddToContext, Byte UserToken, String userName, Boolean bIgnoreTokenTimeout, Boolean bAsAnonymous) +27682553 Microsoft.SharePoint.SPWeb.InitializeSPRequest() +223 Microsoft.SharePoint.WebControls.SPControl.EnsureSPWebRequest(SPWeb web) +365 Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context) +520 Microsoft.SharePoint.ApplicationRuntime.BaseApplication.Application_PreRequestHandlerExecute(Object sender, EventArgs e) +351 Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.PreRequestExecuteAppHandler(Object oSender, EventArgs ea) +60 System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +171
This exception occurs under a number of scenarios:
- You created a user using the CreateUserWizard control, then choose Sign in as a Different User in SharePoint
- You changed your password using the ChangePassword control
This exception occurs because the ASP.NET login controls add a cookie, namely .ASPXAUTH, which is incompatible with the SharePoint claim provider. The workaround is to expire this cookie after the ASP.NET login controls have done their work. Credit for this finding and the workaround code go to this post (toward the end): http://social.msdn.microsoft.com/Forums/en/sharepoint2010general/thread/787b6d6c-9ed5-45f6-84fb-c01827bf28d4
For the CreateUserWizard control, you should do this on both the ActiveStepChanged and ContinueButtonClick events.
2. The ChangePassword control requires claim information to be removed from the user name
When using Claim Authentication in SharePoint, the claim information is added to the user name, e.g. 0#.f|portal81sqlmembershipprovider|user1. When using the OOTB ASP.NET user database, the user name above is stored as user1. The ChangePassword control therefore will not be able to find the user if the full user name with claim information is passed to it. We therefore must remove the claim information from the user name for this control to work.
The ChangePassword control may give you a generic error message when failing, e.g. “Password incorrect or New Password invalid. New Password length minimum: 7. Non-alphanumeric characters required: 1″. Ensure that you have addressed the user name and the .ASPXAUTH cookie above if you can’t get this control to work.
Again, credit for this go to the post linked above.
3. Explicitly reference your MembershipProvider rather than the default one
The System.Web.Security.Membership class has a number of static methods that you can use to manage your users, e.g. GetAllUsers, DeleteUser, UpdateUser, etc. When you use these methods directly off the Membership class however, they will use the default MembershipProvider defined for the SharePoint web application, and often this is not the one you want. You may get the exception “The method or operation is not implemented” if you do this.
Instead, retrieve your specific MembershipProvider, and invoke these methods on this provider. For example:
System.Web.Security.Membership.GetAllUsers(); //DON'T System.Web.Security.Membership.Providers["MySQLMembershipProvider"].GetAllUsers(); //DO