-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding support for ADO service connection in PowershellV2 Task #20726
Open
praval-microsoft
wants to merge
37
commits into
master
Choose a base branch
from
feature/WiscPSV2Task
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
5ddf3b2
Cleanup
praval-microsoft af89e7b
Fixed the Dependency issue for Diagnostics
praval-microsoft 0ff0b82
Fix Package-Lock.json
praval-microsoft d383f31
Fix Package-lock.json
praval-microsoft ae952e6
fix
praval-microsoft 981e1c4
fix
praval-microsoft b8b0d93
fix
praval-microsoft a428ac4
Replaced class wth customobject
praval-microsoft 564d89f
fix build
praval-microsoft 43110c3
Removed New keyboard from the code
praval-microsoft 76ee25f
build
praval-microsoft 7d2be0d
trying with unit test failures
praval-microsoft 5d74ca9
trying with unit test failures
praval-microsoft 1bc344d
build
praval-microsoft 22076f6
build
praval-microsoft 450acf3
build
praval-microsoft 4b390f7
unit test fix
praval-microsoft a4f0344
evrything works here, going to sleep now.
praval-microsoft b82f1c0
ubuntu pipe name randomness
praval-microsoft bc7e370
Adding randomness in events
praval-microsoft 1658e57
try catch in finally block
praval-microsoft fab3f16
Removed VstsLeavingInvocation and added a sleep for the runspace thread
praval-microsoft 5b1a558
Removing sleep from the runspace
praval-microsoft b51eb79
Using .Net Threads
praval-microsoft 322e25f
Cleanup
praval-microsoft e1337ed
dummy change for test pipeline trigger
praval-microsoft 7745904
using the export approach
praval-microsoft d58a630
package-lock.json
praval-microsoft 7ea22ab
remvoed default access token
praval-microsoft 97fef60
Refactor
praval-microsoft 834be91
refactoring
praval-microsoft f5e89e6
Typescript comments
praval-microsoft 7bdc269
Powershell comments
praval-microsoft de34c80
powershell.ps finally
praval-microsoft 1967b9f
Task version bump
praval-microsoft 1690534
deleting vsts.ps1
praval-microsoft 9714c9c
clean up of runspace logs
praval-microsoft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
Import-Module Microsoft.PowerShell.Security | ||
Import-Module $PSScriptRoot\ps_modules\VstsTaskSdk | ||
|
||
function Get-VstsFederatedTokenPS2Task { | ||
param( | ||
[Parameter(Mandatory=$true)] | ||
$taskDict, | ||
[Parameter(Mandatory=$true)] | ||
[string]$vstsAccessToken | ||
) | ||
|
||
$serviceConnectionId = $taskDict["ConnectedServiceName"] | ||
$uri = $taskDict["Uri"] | ||
$planId = $taskDict["PlanId"] | ||
$jobId = $taskDict["JobId"] | ||
$hub = $taskDict["Hub"] | ||
$projectId = $taskDict["ProjectId"] | ||
|
||
$url = $uri + "$projectId/_apis/distributedtask/hubs/$hub/plans/$planId/jobs/$jobId/oidctoken?serviceConnectionId=$serviceConnectionId&api-version=7.1-preview.1" | ||
|
||
$headers = @{ | ||
"Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($vstsAccessToken)")) | ||
"Content-Type" = "application/json" | ||
} | ||
|
||
# POST request to generate the OIDC token | ||
$response = Invoke-WebRequest -Uri $url -Method Post -Headers $headers -Body $body | ||
$responseContent = $response.Content | ConvertFrom-Json | ||
$oidcToken = $responseContent.oidcToken | ||
|
||
if ($null -eq $oidcToken -or $oidcToken -eq [string]::Empty) { | ||
throw (New-Object System.Exception("CouldNotGenerateOidcToken")) | ||
} | ||
|
||
return $oidcToken | ||
} | ||
|
||
function Get-WiscAccessTokenPSV2Task { | ||
param( | ||
$taskDict | ||
) | ||
|
||
$clientId = $taskDict["ClientId"] | ||
$envAuthUrl = $taskDict["EnvAuthUrl"] | ||
$tenantId = $taskDict["TenantId"] | ||
$vstsAccessToken = $taskDict["VstsAccessToken"] | ||
|
||
Add-Type -Path "$PSScriptRoot\ps_modules\VstsAzureRestHelpers_\msal\Microsoft.Identity.Client.dll" | ||
|
||
$clientBuilder = [Microsoft.Identity.Client.ConfidentialClientApplicationBuilder]::Create($clientId).WithAuthority($envAuthUrl, $tenantId) | ||
|
||
$oidc_token = Get-VstsFederatedTokenPS2Task -taskDict $taskDict -vstsAccessToken $vstsAccessToken | ||
$msalClientInstance = $clientBuilder.WithClientAssertion($oidc_token).Build() | ||
|
||
$scope = "499b84ac-1321-427f-aa17-267ca6975798" | ||
[string] $resourceId = $scope + "/.default" | ||
$scopes = [Collections.Generic.List[string]]@($resourceId) | ||
|
||
$tokenResult = $msalClientInstance.AcquireTokenForClient($scopes).ExecuteAsync().GetAwaiter().GetResult() | ||
|
||
$result = @{ | ||
Token = $null | ||
ExpirationPeriod = $null | ||
ExceptionMessage = $null | ||
} | ||
|
||
if($tokenResult) { | ||
$result["Token"] = $tokenResult.AccessToken | ||
$result["ExpirationPeriod"] = $([math]::Round(([DateTime]::Parse($tokenResult.ExpiresOn) - [DateTime]::Now).TotalMinutes)) | ||
} | ||
|
||
return $result | ||
} | ||
|
||
# This is the main tokenHandler object | ||
# It is responsible for handling the access token requests for input ADO service connection received from User script via Get-AzDoToken | ||
|
||
# $filePath : Shared file between user script and task script. The generated token is written to this file. The file is access controlled. | ||
# $signalFromUserScript : Name of the event received from user script via Get-AzDoToken indicating a token request | ||
# $signalFromTask : Name of the event sent by TokenHandler to Get-AzDoToken indicating the token is generated and ready to be read from the shared file. | ||
# $exitSignal : Name of the event sent by the Main runspace of the taskScript to the token handler indicating the end of the task and exit. | ||
# $taskDict : Pre-Fetched values from the main runspace required for token generation | ||
# $waitSignal : Name of the event sent by the Main runspace of the taskScript to the token handler to verify if the token handler is ready to handle request. | ||
# sharedVar : It is an env var. When TokenHandler is ready & a wait signal is received, it will set this env var $sharedVar to "start" from "wait" | ||
|
||
# The run method | ||
# First creates the shared file with path value equal to $filePath and set the access control restricted to current user only. | ||
# Runs an infinite loop, inside that it listens to the various signals/events received from user script and the main runspace of task script. | ||
# eventFromUserScript : It indicates an event from user script requesting token | ||
# eventTaskWaitToExecute : It indicates an event from main task runspace to set the Env Var $sharedVar to "start" from "wait" | ||
# exitSignal : It indicates an event from main task runspace to break the infinite loop and exit. | ||
$tokenHandler = [PSCustomObject]@{ | ||
|
||
Run = { | ||
param( | ||
[Parameter(Mandatory=$true)] | ||
[string]$filePath, | ||
[Parameter(Mandatory=$true)] | ||
[string]$signalFromUserScript, | ||
[Parameter(Mandatory=$true)] | ||
[string]$signalFromTask, | ||
[Parameter(Mandatory=$true)] | ||
[string]$exitSignal, | ||
[Parameter(Mandatory=$true)] | ||
$taskDict, | ||
[Parameter(Mandatory=$true)] | ||
$waitSignal, | ||
[Parameter(Mandatory=$true)] | ||
$sharedVar | ||
) | ||
|
||
$eventFromUserScript = $null | ||
$eventFromTask = $null | ||
$eventExit = $null | ||
$eventTaskWaitToExecute = $null | ||
|
||
try { | ||
$eventFromUserScript = New-Object System.Threading.EventWaitHandle($false, [System.Threading.EventResetMode]::AutoReset, $signalFromUserScript) | ||
$eventFromTask = New-Object System.Threading.EventWaitHandle($false, [System.Threading.EventResetMode]::AutoReset, $signalFromTask) | ||
$eventExit = New-Object System.Threading.EventWaitHandle($false, [System.Threading.EventResetMode]::AutoReset, $exitSignal) | ||
$eventTaskWaitToExecute = New-Object System.Threading.EventWaitHandle($false, [System.Threading.EventResetMode]::AutoReset, $waitSignal) | ||
|
||
if (-not (Test-Path $filePath)) | ||
{ | ||
New-Item -Path $filePath -ItemType File -Force | ||
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name | ||
|
||
# Create a new ACL that only grants access to the current user | ||
$acl = Get-Acl $filePath | ||
$acl.SetAccessRuleProtection($true, $false) # Disable inheritance | ||
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule( | ||
$currentUser, "FullControl", "Allow" | ||
) | ||
$acl.SetAccessRule($rule) | ||
Set-Acl -Path $filePath -AclObject $acl | ||
} | ||
else | ||
{ | ||
throw "Token File not found" | ||
} | ||
|
||
# Infinite loop to wait for and handle signals from user script for token request | ||
while ($true) | ||
{ | ||
try | ||
{ | ||
$index = [System.Threading.WaitHandle]::WaitAny(@($eventFromUserScript, $eventTaskWaitToExecute, $eventExit)) | ||
|
||
if ($index -eq 0) | ||
{ | ||
# Signal from UserScript | ||
$result = @{ | ||
Token = $null | ||
ExpirationPeriod = $null | ||
ExceptionMessage = $null | ||
} | ||
|
||
try | ||
{ | ||
$result = Get-WiscAccessTokenPSV2Task -taskDict $taskDict | ||
} | ||
catch | ||
{ | ||
$result["ExceptionMessage"] = $_ | ||
} | ||
finally | ||
{ | ||
$json = $result | ConvertTo-Json | ||
$json | Set-Content -Path $filePath | ||
} | ||
|
||
# Signal UserScript to read the file | ||
$res = $eventFromTask.Set() | ||
|
||
} | ||
elseif ($index -eq 1) { | ||
[System.Environment]::SetEnvironmentVariable($sharedVar, "start", [System.EnvironmentVariableTarget]::Process) | ||
} | ||
elseif ($index -eq 2) | ||
{ | ||
# Exit signal received | ||
break | ||
} | ||
} | ||
catch | ||
{ | ||
# do nothing | ||
} | ||
} | ||
} | ||
finally | ||
{ | ||
try | ||
{ | ||
if ($null -ne $eventFromUserScript ) { $eventFromUserScript.Dispose() } | ||
if ($null -ne $eventFromTask) { $eventFromTask.Dispose() } | ||
if ($null -ne $eventExit) { $eventExit.Dispose() } | ||
} | ||
catch | ||
{ | ||
# do nothing | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Client classes are automatically generated for backend ADO REST APIs.
See
TaskHttpClient
class, which containsCreateOidcTokenAsync
method.