TFS 2018u1. I have a custom Powershell task that calls TFS services via the VSSConnection
object:
$VSS = Get-VssConnection -TaskContext $distributedTaskContext
$Client = $VSS.GetClient(...)
Question: what kind of security context does the task get? It's definitely not the agent account. To make sure, I've set up a temporary agent instance that runs as me, the TFS admin, and the custom task running on that agent doesn't have the full admin.
The underlying problem is - I'm trying to get the current agent record from a task, and the task only sees one pool, even though we have several. See this answer.
First off, the distributedTaskContext
doesn't connect to TFS with NTLM, like Patrick Lu's answer suggests. It connects with Authorization:Bearer
and a token. I've used the same token to invoke the /_api/_common/GetUserProfile
endpoint, which returns the current user, and got back the following identity record:
{
"IdentityType": "user",
"FriendlyDisplayName": "Project Collection Build Service (TEAM FOUNDATION)",
"DisplayName": "Project Collection Build Service (TEAM FOUNDATION)",
"SubHeader": "Build\\233e4ccc-d129-4ba4-9c5b-ea82c7ae1d15",
"TeamFoundationId": "7a3195ee-870e-4151-ba58-1e522732086c",
"EntityId": "vss.ds.v1.ims.user.7a3195ee870e4151ba581e522732086c",
"Errors": [],
"Warnings": [],
"Domain": "Build",
"AccountName": "233e4ccc-d129-4ba4-9c5b-ea82c7ae1d15",
"IsWindowsUser": false,
"MailAddress": ""
}
It looks like some kind of artificial identity that TFS creates just for this purpose. Looking in the TFS database in the tbl_Identity
table, there are numerous user records with names like that - one per collection, it seems, and also some that are project specific.
This user belongs to a server-level group called "Security Service Group" (and also to a collection level group with the same name). Those groups belong, respectively, to Team Foundation Valid Users and Project Collection Valid Users and nothing else.
At least on the collection level, the "Security Service Group" is visible and contains a lot of accounts.
All those "Build Service" users belong to the domain called "Build". A domain is not a security principal though, you can't grant rights to a domain.
Speaking of OAuth scopes. I've used the same token to invoke the homegrown "what are this token's scopes" page, and it turns out the distributedTaskContext
token has exactly one - app_token
. It's a valid scope that opens up all endpoints and all methods (see the dynamic scope list). The scopes
parameter in the extension manifest has no bearing on that; it only affects the client-side contributions.
When it comes to pool visibility, though, the story is tricky. Seems like all the "Project Collection Build Service" accounts belong to Valid Users, but granting the Reader role on all pools to Valid Users doesn't open them up to the REST API in tasks. Granting Reader explicitly to "Project Collection Build Service" does. However, there are numerous accounts like this (one per collection, it seems) - and granting Reader only opens the pools up to release definitions in the collection where it resides. In order to let tasks in releases in all collections read the pools, you need to go through all collections and grant Reader to the "Project Collection Build Service" from each.