//http://blog.sharedove.com/adisjugo/index.php/2011/01/05/writing-a-custom-membership-provider-and-using-it-for-fba-forms-based-authentication-in-sharepoint-2010-from-the-scratch/

Developing a Custom Membership Provider from the scratch, and using it in the FBA (Form Based Authentication) in SharePoint 2010
A

SharePoint 2010 brought us the whole new authentication world – Claims-Based authentication, based on the Windows Identity Foundation. To go through the whole claims-based logic would take too much time and space on this blog, but it’s nevertheless crucial for understanding the whole concept. If you haven’t already seen it, please take a look at a great interview with Microsoft’s Venky Veeraraghavan, one of the people who have designed the whole concept.

What I will focus on now is how to use the claims-based authentication to set up a combined, Windows Authentication and Forms Based Authentication (FBA) on a SharePoint Web Application. It’s a fairly common scenario – you have your internal people, who are members of the domain, and external partners or salesmen who have to use resources in your intranet, but they are not members of your domain.

internalexternal
Past times
Way back, in the times of MOSS 2007, there was a Form Based Authentication. There was even a way to combine it with Windows Authentication. But it was not an easy thing to do. And, even once it was done, it was always a funny thing to observe an user who has just authenticated over FBA trying to open a Word document. After clicking three times on the “Cancel” button in the great Windows authentication popup, the document opens anyways. Sometimes.

Now, try to explain that to the customer…

It ended up with administrators creating domain accounts for external people just because of the SharePoint. Man, the loved it.

But, as we have said earlier, everything is claims and good now. Except if you chose the classical authentication mode when you are creating your SharePoint web application, which is the default setting. But let’s not get into it…

Anyway, it works now. You do have to change some defaults, you do need some afterwards (no, Microsoft still doesn’t want us to give up on the SharePoint-Voodoo), but – it works.

Back to the future
Let’s think of the following scenario. We are a rock label. Our employees have the following usernames: bspringsteen, jcocker, bvox, mjagger and smacgowan. We make a great business, earn lot of money, and we have decided to support some poor jazz guys. We have an old web application, maybe even PHP with MySQL database, which is used by those external jazz people. It means, they already have usernames and passwords there. Now, we want to give them the access to our brand new SharePoint portal, but we don’t want them in the AD. They are not the rock’n’roll people, after all. We want to use existing authentication (usernames and passwords for the old PHP application), and just to give them necessary rights on our SharePoint portal.

Building a custom ASP.NET membership and roles provider
The first thing we have to do is to write a custom ASP.NET membership provider. It’s peace of code which will tell us who can authenticate, and who can’t. That’s nothing new, but it has to be done.

1. Create a new .NET 3.5 class library in VS 2010

2. Create two new classes in the class library, one has to inherit from the MembersipProvider class, and the other from the RolesProvider class (both in System.Web.Security):

image

Now, let’s take a look at the “ShareDoveMembershipProvider” class. You have to implement the following methods:

public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)

public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)

public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)

public override MembershipUser GetUser(string username, bool userIsOnline)

public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)

public override string GetUserNameByEmail(string email)

public override bool ValidateUser(string username, string password)
You see, this is the place where you implement all your user-authentication logic. Let’s keep the things simple for the demo purposes, and let’s hard code our Jazz-people as users in this class.

In the real life you would of course talk to the MySql database mentioned in the example above which contains usernames and passwords, or to the web service, or to a sharepoint-voodoo-priest or whatever. Right now, as we said, just a hard coded example:

1: using System;

2: using System.Collections.Generic;

3: using System.Linq;

4: using System.Text;

5: using System.Web.Security;

6: using System.Collections.Specialized;

7:

8: namespace Progressive.ShareDove.DiverseTests.ShareDoveMembershipAndRolesProvider

9: {

10: /// <summary>

11: /// Custom ShareDove Membership Provider

12: /// </summary>

13: public class ShareDoveMembershipProvider : MembershipProvider

14: {

15:

16: /// <summary>

17: /// List of all membership users

18: /// </summary>

19: private MembershipUserCollection m_AllUsers;

20:

21:

22: /// <summary>

23: /// /// <summary>

24: /// Generate Some dummy users for demo purposes :)

25: /// </summary>

26: private void generateUsers()

27: {

28: m_AllUsers = new MembershipUserCollection();

29:

30: //

31: //in this part of code there should be some really impressive logic - like retrieving users from the external LOB system, or web service, or whatever

32: //but let's in this example add just somt jazz legends here... :)

33: m_AllUsers.Add(new MembershipUser(this.Name, "Ella Fitzgerald", "EllaFitzgerald", "Ella.Fitzgerald@sharedove.com", "How good is jazz?", "EF is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

34: m_AllUsers.Add(new MembershipUser(this.Name, "Billie Holiday", "BillieHoliday", "Billie.Holiday@sharedove.com", "How good is jazz?", "BH is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

35: m_AllUsers.Add(new MembershipUser(this.Name, "Louis Armstrong", "LouisArmstrong", "Louis.Armstrong@sharedove.com", "How good is jazz?", "LA is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

36: m_AllUsers.Add(new MembershipUser(this.Name, "Duke Ellington", "DukeEllington", "Duke.Ellington@sharedove.com", "How good is jazz?", "DE is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

37: m_AllUsers.Add(new MembershipUser(this.Name, "Miles Davis", "MilesDavis", "Miles.Davis@sharedove.com", "How good is jazz?", "MD is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

38: m_AllUsers.Add(new MembershipUser(this.Name, "Fletcher Henderson", "FletcherHenderson", "Fletcher.Henderson@sharedove.com", "How good is jazz?", "FH is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

39: m_AllUsers.Add(new MembershipUser(this.Name, "Benny Goodman", "BennyGoodman", "Benny.Goodman@sharedove.com", "How good is jazz?", "BG is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

40: m_AllUsers.Add(new MembershipUser(this.Name, "Jelly Roll Morton", "JellyRollMorton", "Jelly.Roll.Morton@sharedove.com", "How good is jazz?", "JRM is good", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));

41:

42:

43: }

44:

45: /// <summary>

46: /// Retrieve all the users ShareDove Membership provider can authenticate.

47: /// We will ignore the paging here, for demo purposes

48: /// </summary>

49: /// <param name="pageIndex">Index of the results page we are returning (ignored in this demo example)</param>

50: /// <param name="pageSize">Number of the items returned in a results page (ignored in this demo example)</param>

51: /// <param name="totalRecords">Total number of records we are returning</param>

52: /// <returns>User Collection with all users</returns>

53: public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)

54: {

55:

56: if (m_AllUsers == null) generateUsers();

57:

58: totalRecords = m_AllUsers.Count;

59: return m_AllUsers;

60: }

61:

62: /// <summary>

63: /// Find users by email

64: /// </summary>

65: /// <param name="emailToMatch">Email sto search</param>

66: /// <param name="pageIndex">Index of the results page we are returning (ignored in this demo example)</param>

67: /// <param name="pageSize">Number of the items returned in a results page (ignored in this demo example)</param>

68: /// <param name="totalRecords">Total number of records we are returning</param>

69: /// <returns>Members found by email</returns>

70: public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)

71: {

72:

73: if (m_AllUsers == null) generateUsers();

74:

75:

76: MembershipUserCollection returnFoundUsers = new MembershipUserCollection();

77:

78: (m_AllUsers.Cast<MembershipUser>().

79: Where(membershipUser => membershipUser.Email.ToLowerInvariant().Contains(emailToMatch.ToLowerInvariant())))

80: .ToList().ForEach(returnFoundUsers.Add);

81:

82: totalRecords = returnFoundUsers.Count;

83: return returnFoundUsers;

84:

85: }

86:

87: /// <summary>

88: /// Find users by username

89: /// </summary>

90: /// <param name="emailToMatch">Email sto search</param>

91: /// <param name="pageIndex">Index of the results page we are returning (ignored in this demo example)</param>

92: /// <param name="pageSize">Number of the items returned in a results page (ignored in this demo example)</param>

93: /// <param name="totalRecords">Total number of records we are returning</param>

94: /// <returns>Members found by email</returns>

95: public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)

96: {

97: if (m_AllUsers == null) generateUsers();

98:

99: MembershipUserCollection returnFoundUsers = new MembershipUserCollection();

100:

101: (m_AllUsers.Cast<MembershipUser>().

102: Where(membershipUser => membershipUser.UserName.ToLowerInvariant().Contains(usernameToMatch.ToLowerInvariant())))

103: .ToList().ForEach(returnFoundUsers.Add);

104:

105: totalRecords = returnFoundUsers.Count;

106: return returnFoundUsers;

107: }

108:

109: /// <summary>

110: /// Gets a specified user by it's username

111: /// </summary>

112: /// <param name="username">Username</param>

113: /// <param name="userIsOnline">If true, updates the last-activity date/time stamp for the specified user.</param>

114: /// <returns>Found Membership user</returns>

115: public override MembershipUser GetUser(string username, bool userIsOnline)

116: {

117:

118: if (m_AllUsers == null) generateUsers();

119:

120: IEnumerable<MembershipUser> usersFound = m_AllUsers.Cast<MembershipUser>().Where(membershipUser => membershipUser.UserName == username);

121:

122: return usersFound.FirstOrDefault();

123:

124: }

125:

126:

127: /// <summary>

128: /// Gets a specified user by it's Provider User Key

129: /// </summary>

130: /// <param name="username">Provider User Key</param>

131: /// <param name="userIsOnline">If true, updates the last-activity date/time stamp for the specified user.</param>

132: /// <returns>Found Membership user</returns>

133: public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)

134: {

135:

136: if (m_AllUsers == null) generateUsers();

137:

138: IEnumerable<MembershipUser> usersFound = m_AllUsers.Cast<MembershipUser>().Where(membershipUser => membershipUser.ProviderUserKey.ToString() == providerUserKey.ToString());

139:

140: return usersFound.FirstOrDefault();

141: }

142:

143:

144: /// <summary>

145: /// Get's the username based on the member's email address

146: /// </summary>

147: /// <param name="email">member's email address</param>

148: /// <returns>Found username</returns>

149: public override string GetUserNameByEmail(string email)

150: {

151: if (m_AllUsers == null) generateUsers();

152:

153: IEnumerable<MembershipUser> usersFound = m_AllUsers.Cast<MembershipUser>().Where(membershipUser => membershipUser.Email.ToLowerInvariant() == email.ToLowerInvariant());

154:

155: MembershipUser user = usersFound.FirstOrDefault();

156:

157: if (user != null)

158: return user.UserName;

159: else

160: return null;

161:

162: }

163:

164:

165: /// <summary>

166: /// A Dummy validation method - here we are only going to check if the username exists and if any password is given - it will be enough for the demo purposes

167: /// </summary>

168: /// <param name="username">username</param>

169: /// <param name="password">password</param>

170: /// <returns>validation result</returns>

171: public override bool ValidateUser(string username, string password)

172: {

173: if (m_AllUsers == null) generateUsers();

174:

175: IEnumerable<MembershipUser> usersFound = m_AllUsers.Cast<MembershipUser>().Where(membershipUser => membershipUser.UserName == username);

176:

177: MembershipUser user = usersFound.FirstOrDefault();

178:

179: if (user != null)

180: {

181: if (string.IsNullOrEmpty(password))

182: {

183: return false;

184: }

185: else

186: {

187: return true;

188: }

189: }

190: else

191: return false;

192:

193: }

194:

195: #region Not implemented methods and properties

196: public override string ApplicationName

197: {

198: get

199: {

200: throw new NotImplementedException();

201: }

202: set

203: {

204: throw new NotImplementedException();

205: }

206: }

207:

208: public override bool ChangePassword(string username, string oldPassword, string newPassword)

209: {

210: throw new NotImplementedException();

211: }

212:

213: public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)

214: {

215: throw new NotImplementedException();

216: }

217:

218: public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)

219: {

220: throw new NotImplementedException();

221: }

222:

223: public override bool DeleteUser(string username, bool deleteAllRelatedData)

224: {

225: throw new NotImplementedException();

226: }

227:

228: public override bool EnablePasswordReset

229: {

230: get { throw new NotImplementedException(); }

231: }

232:

233: public override bool EnablePasswordRetrieval

234: {

235: get { throw new NotImplementedException(); }

236: }

237:

238: public override int GetNumberOfUsersOnline()

239: {

240: throw new NotImplementedException();

241: }

242:

243: public override string GetPassword(string username, string answer)

244: {

245: throw new NotImplementedException();

246: }

247:

248: public override int MaxInvalidPasswordAttempts

249: {

250: get { throw new NotImplementedException(); }

251: }

252:

253: public override int MinRequiredNonAlphanumericCharacters

254: {

255: get { throw new NotImplementedException(); }

256: }

257:

258: public override int MinRequiredPasswordLength

259: {

260: get { throw new NotImplementedException(); }

261: }

262:

263: public override int PasswordAttemptWindow

264: {

265: get { throw new NotImplementedException(); }

266: }

267:

268: public override MembershipPasswordFormat PasswordFormat

269: {

270: get { throw new NotImplementedException(); }

271: }

272:

273: public override string PasswordStrengthRegularExpression

274: {

275: get { throw new NotImplementedException(); }

276: }

277:

278: public override bool RequiresQuestionAndAnswer

279: {

280: get { throw new NotImplementedException(); }

281: }

282:

283: public override bool RequiresUniqueEmail

284: {

285: get { throw new NotImplementedException(); }

286: }

287:

288: public override string ResetPassword(string username, string answer)

289: {

290: throw new NotImplementedException();

291: }

292:

293: public override bool UnlockUser(string userName)

294: {

295: throw new NotImplementedException();

296: }

297:

298: public override void UpdateUser(MembershipUser user)

299: {

300: throw new NotImplementedException();

301: }

302: #endregion

303:

304: }

305: }
Now we have to do the same thing with the ShareDoveRolesProvider class – this is where we implement our roles logic – which user belongs to which internal role. Don’t mix this up with SharePoint roles – they still exist, SharePoint still takes care of the authorization, but there might be a case where we want to know the internal roles of the source system. It means, we might want to know who of our jazz people play piano (they are in the “pianist” role), and the roles provider can give us this answer.

The following methods have to be implemented in the Roles provider:

public override string[] GetAllRoles()

public override string[] GetRolesForUser(string username)

public override string[] GetUsersInRole(string rolename)

public override bool IsUserInRole(string username, string rolename)

public override bool RoleExists(string rolename)

public override string[] FindUsersInRole(string rolename, string usernameToMatch)
And again, let’s do some hard coding for this demo purposes. Here is how the class should look like:

1: using System;

2: using System.Collections.Generic;

3: using System.Linq;

4: using System.Text;

5: using System.Web.Security;

6:

7: namespace Progressive.ShareDove.DiverseTests.ShareDoveMembershipAndRolesProvider

8: {

9: /// <summary>

10: /// ShareDove Roles Provider

11: /// </summary>

12: public class ShareDoveRolesProvider : RoleProvider

13: {

14:

15: public override string ApplicationName { get; set; }

16:

17: /// <summary>

18: /// All Roles

19: /// </summary>

20: private string[] m_AllRoles = { "Drummer", "Pianist", "Saxophonist", "Trumpeter", "Clarinetist", "Singer", "Bandleader" };

21: private string[,] m_RolesForUser = new string[,] {

22: {"Ella Fitzgerald", "Vocalist"},

23: {"Billie Holiday","Vocalist"},

24: {"Louis Armstrong","Vocalist,Trumpeter"},

25: {"Duke Ellington","Pianist,Bandleader"},

26: {"Miles Davis", "Trumpeter,Bandleader"},

27: {"Fletcher Henderson","Pianist,Bandleader"},

28: {"Benny Goodman","Clarinetist,Bandleader"},

29: {"Jelly Roll Morton","Pianist,Bandleade"},

30: };

31:

32: /// <summary>

33: /// Retrieve all available roles

34: /// </summary>

35: /// <returns>String-array with all roles</returns>

36: public override string[] GetAllRoles()

37: {

38: return m_AllRoles;

39: }

40:

41: /// <summary>

42: /// Get the array of roles for the specified user

43: /// </summary>

44: /// <param name="username">User name</param>

45: /// <returns>String-array with all roles for the specified user</returns>

46: public override string[] GetRolesForUser(string username)

47: {

48: List<string> users = new List<string>();

49: for (int i = 0; i <= m_RolesForUser.GetUpperBound(0); i++)

50: {

51: if (m_RolesForUser[i, 0] == username)

52: users = m_RolesForUser[i, 1].Split(',').ToList<string>();

53: }

54:

55: return users.ToArray();

56: }

57:

58: /// <summary>

59: /// Get all the users who are in the given role

60: /// </summary>

61: /// <param name="rolename">Role name</param>

62: /// <returns>String-array with all users being in the given role</returns>

63: public override string[] GetUsersInRole(string rolename)

64: {

65: List<string> users = new List<string>();

66: for (int i = 0; i <= m_RolesForUser.GetUpperBound(0); i++)

67: {

68: List<string> userRoles = m_RolesForUser[i, 1].Split(',').ToList<string>();

69: if (userRoles.Where(userRole => userRole == rolename).Count() > 0)

70: {

71: users.Add(m_RolesForUser[i, 0]);

72: }

73: }

74:

75: return users.ToArray();

76:

77: }

78:

79: /// <summary>

80: /// Check if the user is in the role

81: /// </summary>

82: /// <param name="username">Username</param>

83: /// <param name="rolename">Role name</param>

84: /// <returns>True if user is in the role</returns>

85: public override bool IsUserInRole(string username, string rolename)

86: {

87: List<string> usersForRole = GetUsersInRole(rolename).ToList();

88:

89: if (usersForRole.Where(userName => userName == username).Count() > 0)

90: {

91: return true;

92: }

93: else

94: {

95: return false;

96: }

97:

98: }

99:

100: /// <summary>

101: /// Check of the role with the given name exists

102: /// </summary>

103: /// <param name="rolename">Role name</param>

104: /// <returns>True if the role exists</returns>

105: public override bool RoleExists(string rolename)

106: {

107: bool roleExsists = m_AllRoles.ToList().Where(roleName => roleName == rolename).Count() > 0;

108:

109: return roleExsists;

110: }

111:

112: /// <summary>

113: /// Search for users in the goven role

114: /// </summary>

115: /// <param name="rolename">Name of the role to search the users in</param>

116: /// <param name="usernameToMatch">Pattern to search in the role</param>

117: /// <returns>All the users which mach the pattern</returns>

118: public override string[] FindUsersInRole(string rolename, string usernameToMatch)

119: {

120: List<string> users = GetUsersInRole(rolename).ToList<string>();

121:

122: List<string> foundUsers = users.Where(userName => userName.ToLowerInvariant().Contains(usernameToMatch.ToLowerInvariant())).ToList<string>();

123:

124: return foundUsers.ToArray();

125:

126: }

127:

128: #region Not implemented methods

129: public override void AddUsersToRoles(string[] usernames, string[] roleNames)

130: {

131: throw new NotImplementedException();

132: }

133:

134: public override void CreateRole(string roleName)

135: {

136: throw new NotImplementedException();

137: }

138:

139: public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)

140: {

141: throw new NotImplementedException();

142: }

143:

144:

145: public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)

146: {

147: throw new NotImplementedException();

148: }

149: #endregion

150: }

151: }
So that’s it, we have our custom ASP.NET membership and roles provider that is authenticating our jazz people. Finally, we have to do with it is to sign it, and to throw it to the GAC. Yes, it has to go there.

(gacutil -i ShareDove.MembershipAndRolesProvider.dll)

00-gac

Creating a Claims-based Web Application
The next step is to create a SharePoint Web Application which will used Claims-based authentication. As we said, the classical mode authentication is still the default mode, so we have to change it manually:

(click on the picture for the full size)

01-a-createwebapp

We see that we explicitly have to choose the “Claims based authentication”, and to select the “Enable Forms Based Authentication (FBA)” option.

We also see that we have to set the “ASP.NET Membership Provider Name” and “ASP.NET Role Manager Name”. At this point just give some names which make sense (these names will be later displayed to your users!), but write them down in the Notepad since we will be using it in the SharePoint-Voodoo session that is coming.

Voodoo time!
OK, now we have just created a SharePoint web application, and we told to the Web Application that we want to use a custom ASP.NET membership and role providers for our Form Based Authentication, and that they are called, for example, “ShareDove Membership Provider” and “ShareDove Roles Provider”.

Now, we have to associate somehow this canonical names with our class library which is waiting in GAC to be used. The most logical and straight-forward way is to do it in the web.config.

And since it is that logical, we have to do it three times. Three. The magical voodoo number.

This is not a joke. We have to register our assembly in the web.config of the newly created SharePoint web application (ok, that makes sense). Then in the SharePoint STS (Security Token Service – a SharePoint Service Application which is handling whole this claims thing). OK, somehow I can understand that as well. But then, we have to register it in the web.config of the Central Administration application as well. Voodoo. No other explanation for that.

iis1

iis2

iis3

(Applications where we have to edit the web.config)

Luckily, at all three web.config files we have to enter the same peace of code. Under the <system.web> section, we have to add our new providers in the “membership” and “roleManager” sections as following:

1: <membership defaultProvider="i">

2: <providers>

3: <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

4: <add name="ShareDove Membership Provider" applicationName="ShareDove Membership" type="Progressive.ShareDove.DiverseTests.ShareDoveMembershipAndRolesProvider.ShareDoveMembershipProvider, ShareDove.MembershipAndRolesProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f1182222d75a911e"/>

5: </providers>

6: </membership>

7: <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">

8: <providers>

9: <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

10: <add name="ShareDove Role Provider" type="Progressive.ShareDove.DiverseTests.ShareDoveMembershipAndRolesProvider.ShareDoveRolesProvider, ShareDove.MembershipAndRolesProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f1182222d75a911e" applicationName="ShareDove Membership" />

11: </providers>

12: </roleManager>

WARNING 1: Leave the existing providers alone, otherwise the SharePoint-Voodo-Gods will take revenge on you.

WARNING 2: Don’t copy my assembly names and tokens – they won’t work at your SharePoint.

WARNING 3: the “name” attribute of both providers have to be EXACTLY the same as entered when creating the web application.

Creating the Site Collection and testing the whole thing
Now we can create a SiteCollection on this application as we are used to.

sitecol

And, when we try to open our site collection, voila…

image_thumb_5_01744BD2

SharePoint asks us how we would like to log on!

Let’s try the Forms Authentication, and let’s try to sign in as a great jazz pianist Jelly Roll Morton:

image_thumb_7_01744BD2

04-signed-accessdenied

OK, it’s obvious that good ol’ Jelly doesn’t have any rights on our SharePoint portal yet! We did authenticate him (“You are currently signed in as: jelly roll morton”), but, authorization is still on the SharePoint part of the game. Poor Jelly can’t do anything yet.

Let’s sign out, and sign in again as Administrator (or some other Very Powerful User) using the Windows Authentication. Let’s create a SharePoint Group called “Jazzers”, and fill it with some users:

07-picker-jazzers

OK, here is our new people picker! We see, on the left side, more groups, one of them being the “Forms Auth” – that is where we find our jazz people. Let’s select them all in our “Jazzers” SharePoint group, and let’s give some rights to that group:

09-give-permissions-group

When selecting the FBA users, if we click at the user information, we see the following:

08-member-info

User Information panel gives us all the information we provided through our ASP.NET membership provider, and it clearly states the provider which gave the info (“ShareDove Membership Provider”)

We can now log out as the Administrator, and try to log in as Billie Holiday using the FBA again:

10-logged-claims

So, we see, it really does work! Our external users can do exactly what we authorize them to do. Even open the Word documents!

Open-mouthed smile

Hope this helps someone.

Comments
0 comments

Tagged on: SharePoint
By Adis Jugo | 05.01.2011 | Development | 6 Comments |
← Happy New Year!How to Become a SharePoint Admin? →
6 thoughts on “Developing a Custom Membership Provider from the scratch, and using it in the FBA (Form Based Authentication) in SharePoint 2010”
Pingback: Writing a Custom Membership Provider from the scratch and using it for FBA in SharePoint 2010 - Quark’s bar

NADY(Egypt)
23.03.2011 at 16:41
Thank you soOooOOo Much …. i like your way

Log in to Reply

luis
11.04.2012 at 19:25
Voodoo

“OK, somehow I can understand that as well. But then, we have to register it in the web.config of the Central Administration application as well. Voodoo. No other explanation for that.”

just one reazon for now:

example: who do you set the administrator, if you want an administrator from the FBA provider? :)))

Log in to Reply

Kashif
31.05.2012 at 17:41
this post as well as many others only outline the steps. i have followed each instruction here and on other posts available on the net (which are almost exactly the same), however i do not get the user to show up when trying to add. further it would be nice to mention that Central Admin doens’t have any membership/providers in the config file so simply adding my custom providers, it resulted in username/password to appear everytime i click on any of the links in CA and it wouldn’t even validate the user that is actually logged in. removing membership/providers from CA config file stabilizes this. The question remains: why am i not able to add the user?

Log in to Reply

Arjun
21.06.2012 at 13:09
Unfortunately also followed all steps, but fails when users are to be added (none found). Too many possible causes of error to look into, but just thought to post to flag that all is not straightforward and well with this :(

Log in to Reply

Adis Jugo Post author
05.07.2012 at 12:27
Hi Arjun,

difficult to guess – you didnt’t provide much of an info what went wrong & possible error messages.

Log in to Reply
Leave a Reply
You must be logged in to post a comment.

Developing a Custom Membership Provider from the scratch, and using it in the FBA (Form Based Authentication) in SharePoint 2010的更多相关文章

  1. SharePoint 2010 配置基于MemberShip的身份验证

    场景:通常需要为sharepoint打通其他的系统整合到sharepoint认证,ad通常是为内部域用户,外网访问的可以使用membership来登录,那么这个既可以内部用户访问,外部用户也可以访问 ...

  2. Cognos权限Custom Java Provider表结构实例

    select * from org_user;USER_ID USER_CODE USER_NAME FULL_NAME EMAIL PWD2 889 zhangsan 张三 123@126.com ...

  3. SharePoint 2010/SharePoint 2013 Custom Action: 基于Site Collection 滚动文字的通知.

    应用场景: 有时候我们的站点需要在每个页面实现滚动文字的通知,怎么在不修改Master Page的情况下实现这个功能?我们可以使用Javascript 和 Custom Action 来实现. 创建一 ...

  4. 解决Sharepoint 2010 custom display form 不显示附件的问题

    sharepoint 2010用designer添加自定义的 display form默认是不会显示附件的. 需要添加如下代码才会显示附件: <tr> <td width=" ...

  5. sharepoint 2010 页面添加footer方法 custom footer for sharepoint 2010 master page

    转:http://blog.csdn.net/chenxinxian/article/details/8720893 在sharepoint 2010的页面中,我们发现,没有页尾,如果我们需要给页面添 ...

  6. [转]SharePoint 2010 Download as Zip File Custom Ribbon Action

    在SharePoint 2010文档库中,结合单选框,在Ribbon中提供了批量处理文档的功能,比如,批量删除.批量签出.批量签入等,但是,很遗憾,没有提供批量下载,默认的只能一个个下载,当选择多个文 ...

  7. SharePoint Development - Custom List using Visual Studio 2010 based SharePoint 2010

    博客地址 http://blog.csdn.net/foxdave 之前两次我们定义了内容类型和字段,我们现在用它们为这一讲服务--创建一个自定义列表. 打开Visual Studio,打开之前的工程 ...

  8. SharePoint Development - Custom Field using Visual Studio 2010 based SharePoint 2010

    博客地址 http://blog.csdn.net/foxdave 自定义列表的时候有时候需要自定义一些字段来更好地实现列表的功能,本文讲述自定义字段的一般步骤 打开Visual Studio,我们还 ...

  9. SharePoint Development - Custom Content Type using Visual Studio 2010 based SharePoint 2010

    博客地址 http://blog.csdn.net/foxdave 本文所述均来自之前实际的项目模块 首先再论述一下SharePoint ContentType内容类型 SharePoint的列表和文 ...

随机推荐

  1. WebForm 文件上传

    //Button1的点击事件 //FileUpload1.FileName为所传文件的名字. //以DateTime.Now.ToString("yyyyMMddhhmmssms" ...

  2. 在ubuntu14.04上安装openstack mitaka

    最近在工作环境安装部署了juno版本,在GE口测试网络性能不太满意,发现mitaka版本支持ovs-dpdk,于是抽时间安装实验一番. 参考官网的安装文档,先准备将mitaka版本安装好再配置ovs. ...

  3. RSA算法记录----摘抄

    RSA算法原理(一)   "公钥加密算法". 因为它是计算机通信安全的基石,保证了加密数据不会被破解.你可以想象一下,信用卡交易被破解的后果. 进入正题之前,我先简单介绍一下,什么 ...

  4. iOS SDWebImage的使用

    现在把代码贴出来,供大家参考.尤其是新手,看完这篇博客,图片缓存so easy.最后有demo供大家下载,先学习. 第一步,下载SDWebImage,导入工程.github托管地址https://gi ...

  5. Chrome 插件自定义博客编辑界面

    总觉得博客园的编辑器太白了,特别是在晚上,太明亮了刺眼.在后台设置里面找不到任何可以修改UI的地方,考虑用浏览器插件自己改一下.要是做得好,可以给大家一起用. 新建目录 E:/cnblog.js,添加 ...

  6. Let's Encrypt(开源SSL证书管理工具)

    刚装上一个StartSSL 的证书没几天,却看到官方发出这样的通知: 无聊中看到了网上各种相关的扯淡: http://tieba.baidu.com/p/4801786642 http://www.t ...

  7. DBCP数据源的使用

    DBCP(DataBase Connection Pool)是一个开源的数据源工具,实际开发直接使用就行了 导入需要的jar包,数据库使用mysql测试

  8. php 问答

    1,如何设置长生命期的session ? 将 session.cookie_lifetime ,session.gc_maxlifetime 的时间设置长一点. 2,为什么初始化session的时候报 ...

  9. sortable items不让他拖,也不让他放。cancel不然他拖动

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. 寒假学干货之------初步布局Layout

    在开发的最初,需要设计好我们的Activity,在res/layout下,找到**activitymian(名字都差不多的)的.xml文件,打开他就可以开始编辑. http://www.tuicool ...