In your SharePoint (or other) / K2 solution, you may find yourself in a situation where you want to check if the current user belongs to a given K2 role. Perhaps, you want to allow only users who belong to particular K2 role to view a page, or you want to show a different page depending on the K2 role the user belongs to.
Surprisingly, K2 API does not provide a convenience method to do that. You have to implement it yourself. Even further, K2 Roles may contain ActiveDirectory groups and you will have to check if the current user belongs to them! In this article, we will discuss how all this is being done.
In the project where you will be implementing this method, make sure you have references to those libraries (which should be in the GAC):
- SourceCode.HostClientAPI
- SourceCode.Security.UserRoleManager.Management
First, let's think about the signature of our method. It needs to return a boolean and receive a K2 role name as parameter:
public static bool CurrentUserBelongsToK2Role(string roleName)
That should do it. Now let's start implementing the method. We need to get the name of the current user.
string loginName = WindowsIdentity.GetCurrent().Name;
(By the way, WindowsIdentity is in System.Security.Principal)
What we have so far is:
public static bool CurrentUserBelongsToK2Role(string roleName)
{
string loginName = WindowsIdentity.GetCurrent().Name;
// TODO: Implement further
return false;
}
Not much. We need to get an instance of K2's UserRoleManager class. We will create a separate method which returns us an instance of this object:
public static UserRoleManager GetUserRoleManager()
{
UserRoleManager userRoleManager = new UserRoleManager();
userRoleManager.CreateConnection();
userRoleManager.Connection.Open(GetSCConnectionStringBuilder().ToString());
return userRoleManager;
}
And implement a second method, to get us a GetSCConnectionStringBuilder object.
public static SCConnectionStringBuilder GetSCConnectionStringBuilder()
{
SCConnectionStringBuilder connectionString = new SCConnectionStringBuilder();
connectionString.Authenticate = true;
connectionString.Host = ConfigurationSettings.AppSettings["K2Server"];
connectionString.Integrated = true;
connectionString.IsPrimaryLogin = true;
connectionString.Port = uint.Parse(ConfigurationSettings.AppSettings["K2ServerPort"]);
return connectionString;
}
Basically, this method will read K2Server and K2ServerPort keys from your config and use them for connection to K2. You are free to implement it any way you like. Now, when we have those two helper methods, we can finally do:
UserRoleManager userRoleManager = GetUserRoleManager();
Using the Role Manager, we will try to get an object representation of the K2 role we are checking against:
Role role = userRoleManager.GetRole(roleName);
if (role == null)
{
throw new Exception("Role " + roleName + " not found!");
}
So this piece of code will throw an exception in case the role we are trying to check does not exist. If it exists, our Role object will not be null. Now we need to enumerate the RoleItems within the role. Basically, it will give us all the users (or AD groups) included in this K2 role:
foreach (RoleItem roleItem in role.Include)
{
string currentRoleName = roleItem.Name;
}
Again, let's see what we have so far:
public static bool CurrentUserBelongsToK2Role(string roleName)
{
string loginName = WindowsIdentity.GetCurrent().Name;
UserRoleManager userRoleManager = GetUserRoleManager();
Role role = userRoleManager.GetRole(roleName);
if (role == null)
{
throw new Exception("Role " + roleName + " not found!");
}
foreach (RoleItem roleItem in role.Include)
{
string currentRoleName = roleItem.Name;
// TODO: Implement here
}
return false;
}
So far so good, at least we are now able to enumerate all items within a K2 role! Let's keep going and finish the implementation as marked in bold above.
The currentRoleName object could be returned to us in the format of K2:DOMAIN\Name. We need to normalize it to DOMAIN\Name (i.e. remove the 'K2:' part).
if (currentRoleName.IndexOf(':') > -1)
{
currentRoleName = roleItem.Name.Split(':')[1];
}
Now... the roleItem object we have (in the foreach statement) is of base type RoleItem. There are two classes which inherit from it - UserItem and GroupItem. This means, the current roleItem could be any of the two, which will help us understand if we are dealing with a single user or an ActiveDirectory group added to the K2 role. Let's detect this:
if (roleItem is UserItem)
{
// TODO: Implement
}
else if (roleItem is GroupItem)
{
// TODO: Implement
}
Now we know when we are dealing with user and when with AD group. We just need to implement both cases. Implementing the UserItem case is as easy as comparing the currentRoleName to the loginName:
if (currentRoleName.ToLower() == loginName.ToLower())
{
// Found a USER match
userRoleManager.Connection.Close();
return true;
}
Implementing the GroupItem case is a little bit trickier. First, we need to implement a method which will return us a string array of the AD groups the current user belongs to, so we can later compare against them. Here is the code you will need:
private static string[] GetCurrentUserADGroups()
{
List
// Get the Groups of the current user
foreach (IdentityReference group in WindowsIdentity.GetCurrent().Groups)
{
// Ad the group to the list
NTAccount ntAcctGroup = group.Translate(typeof(NTAccount)) as NTAccount;
groups.Add(ntAcctGroup.Value.ToLower());
}
return groups.ToArray();
}
With the help of this method, we can get back to the implementation of the GroupItem case now:
else if (roleItem is GroupItem)
{
string[] loginNameADGroups = GetCurrentUserADGroups();
}
Then, we simply check if the loginNameADGroups contain the currentRoleName string (which in this case is an AD group).
if (loginNameADGroups.Contains(currentRoleName.ToLower()))
{
userRoleManager.Connection.Close();
return true;
}
And at the end of our CurrentUserBelongsToK2Role method we just have to add:
// No match found
userRoleManager.Connection.Close();
return false;
And that's all! So, let's see now how the whole thing looks:
public static bool CurrentUserBelongsToK2Role(string roleName)
{
string loginName = WindowsIdentity.GetCurrent().Name;
UserRoleManager userRoleManager = GetUserRoleManager();
Role role = userRoleManager.GetRole(roleName);
if (role == null)
{
throw new Exception("Role " + roleName + " not found!");
}
foreach (RoleItem roleItem in role.Include)
{
string currentRoleName = roleItem.Name;
// Is it K2:DOMAIN\Name ?
if (currentRoleName.IndexOf(':') > -1)
{
// Get DOMAIN\Name
currentRoleName = roleItem.Name.Split(':')[1];
}
if (roleItem is UserItem)
{
if (currentRoleName.ToLower() == loginName.ToLower())
{
// Found a USER match
userRoleManager.Connection.Close();
return true;
}
}
else if (roleItem is GroupItem)
{
string[] loginNameADGroups = GetCurrentUserADGroups();
if (loginNameADGroups.Contains(currentRoleName.ToLower()))
{
userRoleManager.Connection.Close();
return true;
}
}
}
// No match found
userRoleManager.Connection.Close();
return false;
}
Of course, you can find the whole project attached here.
No comments:
Post a Comment