Reputation: 166
I am working on a little project for SharePoint 2010 that will allow users to authenticate with their OpenID (and maybe more later on).
How it currently works is I have a membership and role provider based on SQL. My login page uses DotNetOpenAuth to send an authenticationrequest to the OpenID endpoint. If I get a positive response I read the e-mail address from the OpenID persona and create a session for the MembershipUser that has that e-mail address (if I know the endpoint he's from). If that user doesn't exist, I create a new MembershipUser and store the endpoint in the comment property (so that you can't simply edit your own persona to log in as another person's e-mail address).
This works, but the problem is in creating the session. I currently do this with the following bit of code:
//authenticate
SecurityToken token = SPSecurityContext.SecurityTokenForFormsAuthentication(new Uri(SPContext.Current.Web.Url),userProvider,roleProvider,username,user.GetPassword());
SPFederationAuthenticationModule.Current.SetPrincipalAndWriteSessionToken(token);
But that bit only works if the membership provider doesn't encrypt passwords because, once encrypted, I can't just read the user's password and use it in that method.
I was hoping to find a way to just let a user log in but I can't seem to find a simple way of doing that.
Using
FormsAuthentication.SetAuthCookie(username, false);
Just creates an exception (I assume that's because that method is for standard FBA, and not claims-based FBA but I'm just guessing there. The built-in FBA login control with username and password does work, though.)
System.ArgumentException: Exception of type 'System.ArgumentException' was thrown. Parameter name: encodedValue
at Microsoft.SharePoint.Administration.Claims.SPClaimEncodingManager.DecodeClaimFromFormsSuffix(String encodedValue)
at Microsoft.SharePoint.Administration.Claims.SPClaimProviderManager.GetProviderUserKey(String encodedSuffix)
at Microsoft.SharePoint.SPGlobal.CreateSPRequestAndSetIdentity(SPSite site, String name, Boolean bNotGlobalAdminCode, String strUrl, Boolean bNotAddToContext, Byte[] UserToken, String userName, Boolean bIgnoreTokenTimeout, Boolean bAsAnonymous)
at Microsoft.SharePoint.SPWeb.InitializeSPRequest()
at Microsoft.SharePoint.WebControls.SPControl.EnsureSPWebRequest(SPWeb web)
at Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context)
at Microsoft.SharePoint.ApplicationRuntime.BaseApplication.Application_PreRequestHandlerExecute(Object sender, EventArgs e)
at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.PreRequestExecuteAppHandler(Object oSender, EventArgs ea)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Long story short, I would like a way to create tokens for my members without having to use their password.
Does anyone have some experience in this, or an idea of how I can get what I want?
Thanks in advance.
Upvotes: 1
Views: 5261
Reputation: 166
In case someone else runs into the same situation, I'll say how I 'solved' the problem.
In a professional environment, you would most likely create your own membership provider / security token service so you can request tokens in your code without requiring the password of the user.
In my case (due to time constraints) I couldn't do that, so I took a simpler way out. Instead of using encrypted passwords (via IIS) I used hashed passwords (set that manually in the web.config). I also made sure to allow resetting of passwords for my membership provider. Then I used the following code to issue a token:
MembershipUser user = membershipProvider.GetUser(username, true);
if(user == null)
{
//create new user here
}
string password = user.ResetPassword();
SecurityToken token = SPSecurityContext.SecurityTokenForFormsAuthentication(new Uri(SPContext.Current.Web.Url), membershipProviderName, roleProviderName, user.UserName, password, false);
SPFederationAuthenticationModule.Current.SetPrincipalAndWriteSessionToken(token);
Practically, this means that the forms user has his password reset each time I log him in, but since he never actually uses his password it's not that big of an issue. It works well enough to quickly show OpenID support in SharePoint.
Upvotes: 1