Showing posts with label Event Handlers. Show all posts
Showing posts with label Event Handlers. Show all posts

Sunday, February 12, 2012

How to: Display SharePoint 2010 groups and users in a web part

Hi all,

Working with Visual Studio 2010 and SharePoint 2010 programming is indeed fun. As we know that Visual Studio 2010 is first class tool for developing SharePoint project templates. In my previous blog post Display SharePoint groups and users in a custom application page. I tried same project (SharePoint 2007) to SharePoint 2010 but faced some issue with SP 2010 and VS 2010.

In my previous blog entry I used (SharePoint 2007): 
  • Publishing features 
  • Custom Application page
  • A user control and application page will host this user control. 
I followed the same steps but I ran into errors.

Firstly, I tried to create a custom application page (which I created in my previous post ) but it gave following Error:
The dynamicmasterpagefile attribute on the page directive is not allowed in this page.

Thus, I found some solutions over the Internet and discovered an interesting written by Geoff Webber  and I created MasterPage in SharePoint and tried to deployed my custom application page but it failed with exactly same error mentioned above.    

Then I tried remove "autoeventwireup" attribute but yet again I got another error: 
The attribute "autoeventwireup" is not allowed in this page.

  I dug into MSDN documentation and found an article from Kirk Evans titled Creating a SharePoint Site Page With Code-Behind Using Visual Studio 2010 I tried using his code. However, he explained more into Site Pages and modifying web.config by using SPWebConfigModification class and I was not convinced because he used site pages and modified web.config and I knew that there should be easier option. Thus, I used to own way and used developed a visual web part and did not use publishing features. There is the walk through: 

Step1: 
Created a new Visual Studio 2010 project >> SharePoint 2010 (Visual C#) template >> chose "Empty SharePoint Project" >> Name: SP2010DisplayGroupsUsers.         

Step2:
The wizard prompts to specify the site  and security level for debugging


Step3: 
Right click on the project >> Add >> New Item >> choose "Visual Web Part" and name it "ShowsGroupsUsers"

Visual Studio 2010 creates a new visual web part associated with a feature. We have to rename the feature so that its more meaningful.


Step 4: 
We drag the TreeView ASP.NET control onto our visual web part, use smart tag to use "Contacts" (AutoFormat) and set appropriate properties such as widh and ID of the tree view control.


Step5: 
Whenever we develop a custom solution such as web part, list with content type or workflow, its best practice also remove via an event receiver so that unnecessary artifacts are removed from the SharePoint server. I have seen people using custom solution but during the deactivation of the feature, the SharePoint root (14 hive) still exists. Thus, we should always clean up the code for deactivation as well.

I am using visual web part and I have to obtain an instance of the "Web Part Gallery". This web part gallery is in fact a list. Therefore, I get used  "GetCatalog" method and supplied WebPartCatalog to get all the web parts that are hosted for the current site collection.   
Then create a SPQuery instance and use CAML query to specific web part which we are creating "ShowsGroupsUsers" as follows:

Event Receiver Feature Activation 


We do the code for feature deactivating and this time we will remove web part item from the site collection. 

Event Receiver Feature Deactivation
 
Step6: 
What I found slightly annoying while developing Visual Studio 2010 SharePoint projects, when we develop a custom solution and tried to deploy to SharePoint, the features are activated automatically. Thus, I created a custom deployment by clicking on the project, right click on the "Properties", going on SharePoint tab, create a "New" deployment configuration and selected only till "Add Solution" and choose "Active Deployment Configuration" our new "Custom Deployment". 

Step7: 
We create images folder for your web part. VS2010 provides "Mapped" folder when we create any new artifact. 

We use 'SharePoint "Images" mapped folder' for our project. It will VS2010 will then create a sperate folder for our project. 
Step8:
We will then deploy our custom solution to SharePoint server using our own "Custom Deployment"

Now, we go to "Site Collection Features" and activate our new web part. 

Again, CKSDev helps to attach all the IIS worker processes (w3p). 

Step8: 
We can test our web part inserting our new web part. 


The web part shows all groups and members for specific site collection.  

We can also check if the web part is there in web part gallery: 


Now, comes an important aspect. If at all business users wants to deactivate this feature. We must remove this web part from this site collection by clicking the "Deactivating" feature. After feature is deactivated we must check if the web part is there in web part gallery. It should not. 


I need to point out few things here:
  1. I have configured Active Directory, add few dummy users and used User Profile Service Application (detailed in my earlier blog: Configure User Profile Service Application in Sharepoint 2010 ) and pulled AD users in SharePoint 2010. So, all the users actually come from Active Directory.      
  2. There are third party components which, I think, does same thing which I have written in this blog entry. One of the products is Qdabra Active Directory Web Service  and product leverages InfoPath to pull the information from AD onto SharePoint. They have dedicated support but the product comes with hefty price.
If you feel that it helped you in anyway, please comment.
Happy programming!

Cheers.
--aaroh

Download the source code here.

Friday, May 28, 2010

My tryst with groups and custom permissions programmatically in SharePoint 2007,


Hi all,

Of late, I had to work for a project where business needed custom groups and permissions to be provisioned. Well, working with creating custom groups/permissions programmatically is not cup of tea as concepts are quite involved.

Business requirement:

There are different set of groups which has to be hooked to a site and document library.

GroupWeb permission List permission
Manager Can add users into different groups but
can not  create new group not add/edit/delete items
in a document library. (Custom permission)
Read only
AuthorCan add/edit/delete his/her own document but can not
delete other's users document. (Event handler)

Contribute
ContributorCan add/edit/delete document. (SharePoint OOTB permission)Contribute
System AdministratorHas full control (SharePoint OOTB permission)Full control

The SharePoint Security Model: 

When we create site via "Central Admin" and choose Team or Blank template, by default SharePoint creates three groups as follows:

Group                                Site Owners            Site Contributors                     Site Visitor              
Permission levelFull ControlContributor Read
Permissions Contribute permissions +
Manage Lists, Override checkout
Read permissions +
Add, Edit, Delete items, delete versions

View, Open items, View versions, create alerts, View Application pages

NOTE: 

1) Please note if we create sites programmatically, the default groups will be not present. 
We have to create these groups programmatically via code. 


2) When we develop our custom groups or role definitions, its most important that we have to "RunWithElevatedPrivileges" which is a delegate method that run with elevated privileges. This method runs under "Application pool" identity.    


Caveat!!

Daniel Larson does NOT recommend
RunWithElevatedPrivileges method in the object model but use "SPUserToken" to impersonate. Also, check out this blog where author has elevated the privileges without using  RunWithElevatedPrivileges method


Creating groups programmatically: 


I have to develop groups and permissions in a separate classes so that even the permission have been changed groups part is intact.  In my scenario, I have 4 SharePoint Groups and Manager group is the one who can create add/remove users in any of 4 SharePoint groups but he/she could be delete any lists and should have access to the lists as read-only access.


I have defined a GroupHelper class, which create a those 4 SharePoint groups. When I provided  my custom SharePoint group and added a user named "local1Manager" who is in "Manager" (SharePoint Group). When I logged in as "local1Manager", I was not able to add any user in any SharePoint Group such as Manager, Contributor, System Administrator and Author. SharePoint displayed this message: 


You do not have permission to view the membership of the group
 

I also looked at one of person who had same issue. Apparently, when we create a SharePoint site, three SharePoint groups are provided by default (Site Owners, Site Members and Site Visitors). These groups have a permission level (Full Control/Contribute/Read) 




Group                             Permission level                                  Group Owner      
Site OwnersFull Control Site Owners
Site MembersContributeSite Owners
Site VisitorsReadSite Owners


This means, that Site Owner MUST BE group owner for all the groups as well.


 By default, when we create the groups programmatically, the group owner will be always "System Account". But I wanted to give this role to my own custom SharePoint Group (Manager) and explicitly assign the group owner as "Manager" for all 4 custom SharePoint Groups


The  bottom line is that, when we create groups programmatically and in one of the group such as "Manager" who want to add users to some other groups then, we MUST explicitly assign the group owner as manager for all other SharePoint groups.
  
Following is the code: 


Receiver Code

-----------------------------------------------------------------------

namespace Company.SiteProvisioning
{
    class CompanyGroups : SPFeatureReceiver
    {

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            //Get the web instance
           using (var web = properties.Feature.Parent as SPWeb)
            {
                if (null != web)
                {

                    #region 1) Creating the Custom Groups here

                    GroupsHelper.CreateGroups(web);
                    #endregion 
                } 
            } 
      }
}



---------------------------------------------------------------------------



GroupHelper.cs 
--------------------------------------------------------------------------





namespace Company.Common.Utilities 
{
    public class GroupsHelper
    {
        #region Methods

         /// <summary>
        /// This function creates all the Company groups
        /// </summary>
        /// <param name="web">The web where groups have to be created.</param>
        public static void CreateGroups(SPWeb web)
        {
            SPGroup group;

            try
            {
                #region 1) For Manager (Manager will be "Group Owner" for other custom SharePoint groups)
                             if (!SPUtility.GroupExists(web, Groups.ManagerName))
                                {


                                      #region i) Create an Company Group

                                                 web.SiteGroups.Add(Groups.ManagerName, web.Site.Owner, web.Site.Owner, Groups.ManagerDescription);
                                                 group = web.SiteGroups[Groups.ManagerName];

                                      #endregion

                                       #region ii) Bind the web to the associated groups

                                                web.AssociatedGroups.Add(group);
                                                web.Update();

                                      #endregion

                                      #region iii) Assign the custom group owner to be "Manager"

                                                 group.Owner = web.SiteGroups[Groups.ManagerName];
                                                 group.Update();

                                      #endregion
                              } 

                              // DO THE SAME STUFF OF OTHER 3 CUSTOM SharePoint Groups
 
               
 
            } 

         }


--------------------------------------------------------------------------------------------------------------


Theory of SharePoint security, Role definitions, Role Types, Role assignments and ISecurableobject: 


SharePoint 2007 technologies is on top of and depends on the security of underlying technologies such as: 
>> ASP.NET 
>> IIS 6/7
>> SQL Server 2005/2008/2008 R2
>> Windows server 2003/2008 
as well firewall configuration. 


Any web application for SharePoint site is only as secure as its weakest link and therefore security is a concern across all the components of our SharePoint 2007 deployment. Security is addressed at different levels in SharePoint that includes: 
>>Organization's security policies 
>>SharePoint Product and Technology configuration 
>> Windows Server 2003/2008 configuration 
>> IIS configuration  
>> ASP.NET configuration  
>> communication configuration  etc. 


SharePoint product and technology make use of a number of technologies so that it mitigates the risk of security being comprised.  
  • Authentication that uses Windows principles (authentication methods, password policies, encryption etc.) 
  • Authorization that is based on the permission model to ensure a high level of granular control over access to contents of a site. 
  • Code access security (CAS)
  • Security techniques (such as Secure Sockets Layer (SSL, HTTPS://))

WSS 3.0 security and permission model is role-based.

a) Role Definition (Permission level):
A role definition is a collection of rights which are hooked up to a user or a SharePoint group. They have following definitions: 
>> Full Control (Administrator)
>> Contribute
>> Read
>> Design 
>> Limited access 


We can develope your own custom permission which I will use for "Manager". Manager can add users but he/she CAN NOT create a new group neither he/she can add/edit/delete documents. 


Its obviously not an OOTB permission. I have created a new class named "Permission.cs" which just details all the permissions. Later, if the business needs the permission to be altered then we have to change in  just one file i.e. Permissions.cs

If we deep dive into the SharePoint's object model, SPRoleDefinition defines a single role definition, including a name, description, management properties, and a set of rights. 


Permissions.cs 
-------------------------------------------------------------------------------------------------------------------

using System.Linq;
using Microsoft.SharePoint;
using Company.Common.Utilities;  

namespace Company.Common.Constants
{
    public static class Permissions
    {

        #region i) Permissions for the Manager

        public static SPRoleDefinition ManagerWebPermission (SPWeb web)
        {


            if (!SPUtility.IsRoleDefinitionExists(Groups.ManagerName,web))
            {
                #region i) Create a custom permission level
                SPRoleDefinition roleDefinition = new SPRoleDefinition
                                                      {
                                                          Name = Groups.ManagerName,
                                                          Description =
                                                              Groups.ManagerDescription,
                                                          BasePermissions =
                                                              SPBasePermissions.FullMask ^
                                                              (SPBasePermissions.ManagePermissions |
                                                               SPBasePermissions.ManageLists |
                                                               SPBasePermissions.AddListItems |
                                                               SPBasePermissions.EditListItems |
                                                               SPBasePermissions.DeleteListItems |
                                                               SPBasePermissions.ViewVersions |
                                                               SPBasePermissions.DeleteVersions |
                                                               SPBasePermissions.CreateAlerts |

                                                               SPBasePermissions.CreateGroups)
                                                      };

                #endregion

                #region ii) Create a custom permission and bind it to the web

                web.RoleDefinitions.Add(roleDefinition);
                web.Update();
             

                #endregion
            }
           

            web.AllowUnsafeUpdates = true;

            SPRoleDefinition userManagerRoleDef = web.RoleDefinitions
                .Cast<SPRoleDefinition>()
                .First(def => def.Name == Groups.ManagerName);
            //SPRoleDefinition userManagerRoleDef = web.RoleDefinitions[Groups.ManagerName];

            web.AllowUnsafeUpdates = false;

            return userManagerRoleDef;
        }

        public static SPRoleDefinition ManagerListPermission (SPWeb web)
        {
            return web.RoleDefinitions.GetByType(SPRoleType.Reader);               
        }

        #endregion 

         #region ii) Permissions for the Document Author

        public static SPRoleDefinition DocAuthorWebPermission(SPWeb web)
        {
            return web.RoleDefinitions.GetByType(SPRoleType.Reader);
        }

        public static SPRoleDefinition DocAuthorListPermission(SPWeb web)
        {
            return web.RoleDefinitions.GetByType(SPRoleType.Contributor);
        }


        #endregion
}
}
}

--------------------------------------------------------------------------------------------------------------------------
 
Let's discuss the code above. SPBasePermissions defines all the built-in permissions which available SharePoint. These base permissions are extremely powerful and we can customize the permissions as we want. In the code above I have defined SPBasePermission.FullMask means for Manager who has full rights. But he do not want to give permissions full rights as he can not delete/add/edit rights. Therefore, use "^" operator to negate those permissions. Please refer how to use these operators

After the we have defined a custom permission level, we need to bind this permission to the web  


   web.RoleDefinitions.Add(roleDefinition);
   web.Update();


While developing the code, I found a bug which I have commented. 


//SPRoleDefinition userManagerRoleDef = web.RoleDefinitions[Groups.
ManagerName];


When I debugged the code, I got this bug. 

BUG: Microsoft.SharePoint.SPException: You cannot grant a user a permission level that is not attached to a web. at Microsoft.SharePoint.SPRoleDefinitionBindingCollection.AddInternal(SPRoleDefinition roleDefinition)
  at Microsoft.SharePoint.SPRoleDefinitionBindingCollection.Add(SPRoleDefinition roleDefinition)


 ISSUE: It may be because SharePoint doesn’t allow you to use the SPRoleDefinition you just created and you have to return the one you just added.

FIX
a) using System.Linq
b) SPRoleDefinition userManagerRoleDef = web.RoleDefinitions
                .Cast<SPRoleDefinition>()
                .First(def => def.Name == Groups.ManagerName);

it will fix this issue. 


b) Role Assignment: We have defined a custom permission level that is bound to the web. But, now we have to bind this permission level to the user or the SharePoint group. This can be achieved by leveraging the role assignment. The SPRoleAssignment class defines the role assignments for a user or group on the current object.



The RoleAssignment property comes with an interface named: ISecurableObject. This interface is extremely useful as we can implement by the SharePoint: 
SPWeb, 
SPList, 
SPListItem classes.
Have a look onto its implementation at this URL


Therefore, I added one more function as follows: 


GroupHelper.cs 
-----------------------------------------------------------------------------------------------------------


    /// <summary>
        /// This function assigns the permissions to the web or to the list.
        /// </summary>
        /// <param name="web">The web</param>
        /// <param name="securableObject">Securable object which could be a web, list or list item</param>
        /// <param name="principal">Principal could be a group or an individual user.</param>
        /// <param name="roleDefinition">The permission level bound to a specific user or group</param>
        public static void AssignPermissions(SPWeb web, ISecurableObject securableObject, SPPrincipal principal, SPRoleDefinition roleDefinition)
        {
            //Assign the role to group/users
            SPRoleAssignment roleAssignment;
            //SPList list;
            try
            {

                if (securableObject.GetType().Name == "SPWeb")
                {

                    web.AllowUnsafeUpdates = true;

                    #region i) Get an SPPrincipal (Group/Users) and assign custom permission level

                    // create a new role assigment for the group/users
                    roleAssignment = new SPRoleAssignment(principal);

                    //bind the role assignment to the role definition
                    roleAssignment.RoleDefinitionBindings.Add(roleDefinition);

                    #endregion

                    #region ii) Bind the role assignment to the web, associate the group to the web and update

                    //bind the role assignment to the web, associate the group to the web and update
                    web.RoleAssignments.Add(roleAssignment);
                    web.AssociatedMemberGroup = (SPGroup) principal;
                    web.Update();

                    #endregion

                    #region iii) Assign the role assigment to the securableObject

                    securableObject.RoleAssignments.Add(roleAssignment);

                    #endregion

                    web.AllowUnsafeUpdates = false;
                }

                if(securableObject.GetType().Name == "SPDocumentLibrary")
                {
                    web.AllowUnsafeUpdates = true;

                    #region i) Check if the Doc Lib has unique permissions or not.

                    if (!securableObject.HasUniqueRoleAssignments)
                    {
                        securableObject.BreakRoleInheritance(true);
                    }

                    #endregion

                    #region  ii) Get the reference of role assignment to the SPPrincipal(Group), Bind role assigment to roledefintion
                       
                        roleAssignment = new SPRoleAssignment(principal);
                        roleAssignment.RoleDefinitionBindings.Add(roleDefinition);

                    #endregion

                    #region iii) Bind the role assigment to the securableObject

                        securableObject.RoleAssignments.Remove(principal);
                        securableObject.RoleAssignments.Add(roleAssignment);

                    #endregion

                    web.AllowUnsafeUpdates = false;
                }

            }
            catch (Exception ex)
            {
                SPUtility.LogToULS(ex);
            }

        }

        #endregion
------------------------------------------------------------------------------


This functions come with 4 parameters: 
AssignPermissions(SPWeb web, ISecurableObject securableObject, SPPrincipal principal, SPRoleDefinition roleDefinition)

SPWeb:  The Web object we pass in the feature receiver. 
ISecurablObject: The web, SPList or the ListItem parameter and therefore gives flexibility in the code.
SPPrincipal: A SharePoint user or a group. 
SPRoleDefinition: The custom permission level which is pre-defined. 




Once we are defined with custom SharePoint groups permissions, we complete out code for the feature receiver.



Receiver Code

-----------------------------------------------------------------------

namespace Company.SiteProvisioning
{
    class CompanyGroups : SPFeatureReceiver
    {

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            //Get the web instance
           using (var web = properties.Feature.Parent as SPWeb)
            {
                if (null != web)
                {

                    #region 1) Creating the Custom Groups here

                    GroupsHelper.CreateGroups(web);
                    #endregion  

                     SPSecurity.RunWithElevatedPrivileges(delegate
                        {
                          
                                    #region 2) Assign the permission to the groups. Permissions to the web and to the list

                                    SPGroup grp;
                                    //SPRoleDefinition roleDefinition;

                                    #region i) Manager

                                    grp = web.SiteGroups[Groups.rManagerName];

                                    GroupsHelper.AssignPermissions(web, web, grp,
                                                                   Permissions.WebPermission(web));
                                    GroupsHelper.AssignPermissions(web, web.Lists[Register.ListDocLibName], grp,
                                                                   Permissions.ManagerListPermission(web));

                                    #endregion

                                    #region ii) Doc Author

                                    grp = web.SiteGroups[Groups.DocAuthorName];

                                    GroupsHelper.AssignPermissions(web, web, grp,
                                                                   Permissions.DocAuthorWebPermission(web));
                                    GroupsHelper.AssignPermissions(web, web.Lists[Register.ListDocLibName], grp,
                                                                   Permissions.DocAuthorListPermission(web));

                                    #endregion

                } 
            } 
      }
}



Note that in permissions.cs we have defined custom permission level for Manager on the web but reader permission on the lists. Whereas, author/contributor has read only access to the web but contributor permission to the list. 


I guess, these sample codes will give an idea on SharePoint groups and permissions. 


Cheers, 
--aaroh 


References
BUG: You cannot grant a user a permission level that is not attached to a web.
BUG: You do not have permission to view the membership of the group  
SharePoint Groups and Permissions concepts (Reza)
Sample codes for groups/permissions  
SPRoleDefinition class, SPRoleAssignment class, SPBasePermissions class, ISecurableObject 1, ISecurableObject 2



Low Code Reimagined with AI + Copilot Pitch Deck - Copy Copilot day (Virtual) - 2023

 Hi All,  I presneded a session at Pune UG on Low Code Reimagined with AI + Copilot Pitch Deck.  Video is at this address  https://www.youtu...