Which scope lets a TFS extension manipulate ACLs?

2019-03-01 18:49发布

问题:

TFS 2015 u2. Trying to write a TFS extension that would use JavaScript API to manipulate the security on a release definition. Security related APIs fail on me with error 401. The code goes:

VSS.require(["VSS/Service", "VSS/Security/RestClient"],
        function (Srv, SecAPI)
        {
            var SecClient = Srv.getCollectionClient(SecAPI.SecurityHttpClient);
            SecClient.queryAccessControlLists("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee").then(function(a)
            {
                //...
            });
        }

That errors out with 401 Unauthorized. As far as I understand, the list of REST API that an extension may use is driven by the scopes parameter in the manifest. What do I place there for this to work? The scopes list lists none of the sort.

Meanwhile, calling the same endpoint from a regular REST client with Windows auth works as expected.

回答1:

In TFS 2017 u2, finally, there's vso.security_manage.


In TFS 2017 u1, there is a scope vso.base that covers this API endpoint, but only with GET. POST, which is required to change the descriptor, is still not covered by the scope.

In TFS 2015 u2, and presumably below, there's no scope that covers the ACL related endpoints.


I've found a very hackish way to enable those endpoints for OAuth in older versions of TFS. It's only applicable to on-premises TFS. The relationship between OAuth scopes and service endpoint URLs/methods is stored in a global, public, mutable singleton data structure that a piece of user code might just be able to alter. You can see it in your favorite MSIL disassembler (ILDASM, ILSpy, Reflector) if you poke around method CreateDefault in class Microsoft.VisualStudio.Services.DelegatedAuthorization.AuthorizationScopeDefinitions within Microsoft.TeamFoundation.Framework.Server.dll.

The following Global.asax does the trick. You have to copy it to C:\Program Files\Microsoft Team Foundation Server 14.0\Application Tier\Web Services (for TFS 2015).

<%@ Application Inherits="Microsoft.TeamFoundation.Server.Core.TeamFoundationApplication" %>
<%@ Import namespace="Microsoft.VisualStudio.Services.DelegatedAuthorization" %>
<%@ Import namespace="System.Collections.Generic" %>
<%@ Import namespace="System.Linq" %>
<script runat="server">
void Session_Start(object o, EventArgs a)
{
    AuthorizationScopeDefinition Def = AuthorizationScopeDefinitions.Default.scopes
        .FirstOrDefault(d => d.scope == "vso.identity");
    if(Array.IndexOf(Def.patterns, "/_apis/SecurityNamespaces#GET") < 0)
    {
        List<string> l = Def.patterns.ToList();
        l.Add("/_apis/SecurityNamespaces#GET");
        l.Add("/_apis/AccessControlLists#GET+POST");
        l.Add("/DefaultCollection/_apis/SecurityNamespaces#GET");
        l.Add("/DefaultCollection/_apis/AccessControlLists#GET+POST");
        Def.patterns = l.ToArray();
    }
}
</script>

Hooking Application_Start would've made more sense, but the code-behind DLL already hooks it. Another handler in Global.asax doesn't override. I monkey-patch the vso.identity scope, because my extension already claims that, but feel free to use any other one.

Introducing your own, brand new scope probably won't work.



回答2:

Unfortunately, there isn’t any REST API to change permission of release definition or release environment.

There is a user voice that you can vote. REST API for release defintion or release enviornment TFS PM will kindly review your suggestion.