It happens quite often that I have to write a piece of code to set user permissions on a SharePoint site. One of the challenges you encounter when doing so is that you need to have a valid SPUser object, that is known in the site collection to be able to do this.
If you want to create a new subsite or web you can start out like this:
// Open an existing site collection
SPSite portalSite = new SPSite("http://portal");
// Create a new subsite (web)
SPWeb newWeb =
portalSite.AllWebs.Add("http://portal/newweb", "My New WebSite", "This is my new web site", 1033, "STS#0", true,
// Get the default roledefinitions known on the new web
SPRoleDefinitionCollection roleDefinitions = newWeb.RoleDefinitions;
// Get the roleassignments collections of the new web
SPRoleAssignmentCollection roleAssignments = newWeb.RoleAssignments;
Next you want to get an SPUser object, so you can give this person the right permissions on the site. Unfortunately there is no way of telling whether you can get this user from the site collection. If the user is known on the site collection there are three ways to get it:
SPUserCollection users = portalSite.RootWeb.AllUsers;
The description in the SDK for this function is:
"Gets the collection of user objects that represents all users who are either members of the site or who have browsed to the site as authenticated members of a domain group in the site."
This means that if you have a site collection where you have authenticated all domain users by using an Active Directory group and the user we want to give the permissions to has never browsed to the site before this function won't return our user.
SPUserCollection users = portalSite.RootWeb.SiteUsers;
The SDK about this one:
"Gets the collection of all users that belong to the site collection."
Which means users explicitly added to the site collection.
And the last one:
SPUserCollection users = portalSite.RootWeb.Users;
The SDK about this one:
"Gets the collection of user objects that are explicitly assigned permissions on the Web site."
So this only gets us the users that are explicitly to the web. And since we are actually trying to assign our user to the web we won't find him in this collection.
The way to solve this problem is to user SPWeb.EnsureUser(loginName) (I have to thank Donald for finding the solution!). The description in the SDK for EnsureUser is:
"Checks whether the specified login name belongs to a valid user of the Web site, and if the login name does not already exist, adds it to the Web site." Which happens to be exactly what we want!
Now we can finish our code:
SPUser newUser = newWeb.EnsureUser(@"domain\username");
newWeb.AllowUnsafeUpdates = true;
// Create the new roleassignment that we want to add to the collection of roleassignments of the new web
SPRoleAssignment roleAssignment = new SPRoleAssignment(newUser);
SPRoleDefinitionBindingCollection roleDefBindings = roleAssignment.RoleDefinitionBindings;
// Add the binding to the correct roledefinition to the roleassignment
// This can also be Contribute for contributor rights.
// Keep in mind that in sites in other languages this needs to be translated
newWeb.AllowUnsafeUpdates = false;