Search code examples
tfsazure-devopstfs-sdk

Set and retrieve the Team Administrator in Team Foundation Server or VSTS


TFS 2012 and later as well as VSTS have a concept of a Team Administrator. I've looked all over the API for a simple way to set and retrieve the value through code to make it easier to provision these settings, but could not find it.

Reflectoring through the Server Object Model for the web UI gives hints for how to do it, but it relies on a number of private methods to get this done. Especially the part that calculates the Security Scope Token is hidden magic.


Solution

  • It took quite a bit of digging to find this old blogpost from 2013 which details how to do this, and I don't seem to be the only person who got stumped by the private methods. In the end they also ended up using Reflection to call the private method to retrieve the token:

    This functionality is now available through the TFS Team Tools:

    Retrieve

    Find the security group matching the team, use it to calculate the team's token, get the people who are part of that special security namespace:

    public List<string> ListTeamAdministrators(string team, out string message)
    {
        // Retrieve the default team.
        TeamFoundationTeam t = this.teamService.ReadTeam(this.projectInfo.Uri, team, null);
        List<string> lst = null;
        message = "";
    
        if (t == null)
        {
            message = "Team [" + team + "] not found";
        }
        else
        {
            // Get security namespace for the project collection.
            ISecurityService securityService = this.teamProjectCollection.GetService<ISecurityService>();
            SecurityNamespace securityNamespace =
                securityService.GetSecurityNamespace(FrameworkSecurity.IdentitiesNamespaceId);
    
            // Use reflection to retrieve a security token for the team.
            var token = GetTeamAdminstratorsToken(t);
    
            // Retrieve an ACL object for all the team members.
            var allMembers = t.GetMembers(this.teamProjectCollection, MembershipQuery.Expanded)
                .ToArray();
            AccessControlList acl =
                securityNamespace.QueryAccessControlList(token, allMembers.Select(m => m.Descriptor), true);
    
            // Retrieve the team administrator SIDs by querying the ACL entries.
            var entries = acl.AccessControlEntries;
            var admins = entries.Where(e => (e.Allow & 15) == 15).Select(e => e.Descriptor.Identifier);
    
            // Finally, retrieve the actual TeamFoundationIdentity objects from the SIDs.
            var adminIdentities = allMembers.Where(m => admins.Contains(m.Descriptor.Identifier));
    
            lst = adminIdentities.Select(i => i.DisplayName).ToList();
        }
        return lst;
    }
    
    private static string GetTeamAdminstratorsToken(TeamFoundationTeam team)
    {
        return IdentityHelper.CreateSecurityToken(team.Identity);
    }
    

    Set

    Setting works in a similar fashion. Grab the token and then add the users unique identifier to the Access Control List:

    IdentityDescriptor descriptor = GetMemberDescriptor(memberId);
    securityNamespace.SetPermissions(token, descriptor, 15, 0, false);
    

    Remove

    And removing a person from the list is then, of course, easy to guess;

    IdentityDescriptor descriptor = GetMemberDescriptor(memberId);
    securityNamespace.RemovePermissions(token, descriptor, 15);