August 2009 Entries

Date/Time:6:30 PM EST on September 21, 2009
Location:Microsoft office in Alpharetta (1125 Sanctuary Pkwy., Suite 300)

Atlanta SharePoint Users Group - http://www.atlspug.com/default.aspx

I am going to speak on Configuration to support customizations, when to customize, when to use OOB features, show some examples on configuration of settings for the Site Collection and Central Administration. Pages and some neat tricks to getting things done. I will be posting all materials here before the meeting, so if you miss it, check out the site.

Recently I was configuring SharePoint Forms Based Authentication (FBA) to use a custom login screen, Active Directory Membership Provider, and my own Role Provider, when I received the following:

Could not load file or assembly 'Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. Access is denied. …

In the error, we can see that obviously we do not have permission, but who is trying to access the DLL?
It is not the Application Pool account, but the Anonymous IIS account. Simple fix, check to see what account is running in Directory Security, give read permission to that user for the _app_bin folder, and recycle the application pool. Should be fixed. Disaster Averted!
Hope this helps.

After working on a project that had me write a custom Role Provider for WSS, I thought I would try and help explain some things about what Membership and Role Providers do, and more specifically in regards to SharePoint.


First off, in my case, the user store was Active Directory. When working with MOSS, you can use the LDAP provider for both membership and roles. In WSS however, there is only a default Membership provider, which does not allow for groups to be used, say AllUsers or Domain Users.


Membership Provider – Looks at a user store to find the specific user, by either username, email, etc.


Role Provider – Looks for roles that exist, and what roles a user has, and what users are contained by a role. For our case, Roles are AD Groups.


In my project I had a custom web part that displayed information from an external data source, looking the user information by the user id from a seperate Active Directory instance. This was not the same Domain that the users logged into their computers with, so we had to use FBA.


Now, you do not need a role provider if you do not plan on using groups from AD, but again in my case, we did not plan to add each user to the group or policy for the web application. We leveraged the role provider to be able to use Domain Groups such as Domain Users, and a couple other groups.


Implimenting the interface for "System.Web.Security.RoleProvider"

The documentation is not all that clear, but understand that a Role with regards to Active Directory is simple a Group.

I have not implimented all the methods, just the important ones for my project:

//Looks for the given user in the given Role

public override bool IsUserInRole(string username, string roleName)
{
string[] roles = GetRolesForUser(username);
if (roles.Select(r => r.ToLower() == roleName.ToLower()).Count() > 0)
{
return true;
}
return false;
}

public override string[] GetRolesForUser(string username)
{
try
{
PrincipalContext adPrincipalContext = new PrincipalContext(ContextType.Domain, Domain, ConnectionUsername, ConnectionPassword);
UserPrincipal user = UserPrincipal.FindByIdentity(adPrincipalContext, username);
PrincipalSearchResult results = user.GetAuthorizationGroups();
return results.Select(r => r.SamAccountName.ToLower()).ToArray();
}
catch (Exception ex)
{
Debug.WriteLine("Error getting Roles for User: " + ex.Message);
}
return new string[0]{};
}

public override string[] GetAllRoles()
{
try
{
PrincipalContext adPrincipalContext = new PrincipalContext(ContextType.Domain, Domain, ConnectionUsername, ConnectionPassword);
GroupPrincipal group = new GroupPrincipal(adPrincipalContext); PrincipalSearcher searcher = new PrincipalSearcher();
searcher.QueryFilter = group;

// run the query
PrincipalSearchResult results = searcher.FindAll();
return results.Select(r => r.SamAccountName.ToLower()).ToArray();
}
catch (Exception ex)
{
Debug.WriteLine("Error finding groups: " + ex.Message);
}
return new string[0] { };
}

//Find the role/AD Group by the name
public override bool RoleExists(string roleName)
{
if (String.IsNullOrEmpty(roleName))
{
return false;
}
else
{
try
{
PrincipalContext adPrincipalContext = new PrincipalContext(ContextType.Domain, Domain, ConnectionUsername, ConnectionPassword);
GroupPrincipal group = new GroupPrincipal(adPrincipalContext); group.SamAccountName = roleName;
PrincipalSearcher searcher = new PrincipalSearcher();
searcher.QueryFilter = group;

// run the query
Principal results = searcher.FindOne();
if (results != null)
{
if (results.SamAccountName == roleName)
{
return true;
}
}

//We did not find the name of the Role from the searcher, just to make sure there was not a problem with Case
return GetAllRoles().Contains(roleName.ToLower());
}
catch (Exception ex)
{
Debug.WriteLine("Error looking for Role: " + ex.Message);
}
}
return false;
}

One nice thing to note, is that I used the new .Net objects for finding users in Active Directory.

PrincipalContext, UserPrincipal, GroupPrincipal, and PrincipalSearcher sure do make things easy! They are found under the System.DirectoryServices.AccountManagement namespace.

I have a couple examples of Linq I used as well to make things a bit simpler, and less foreach loops. I have not implimented all of the methods as stated before, you can however impliment as needed, these base methods should get you most of the way there.

Hope you find a use for it, and let me know if it helps.