Home > Software engineering >  Issue with Invoke-RestMethod and JiraPS module
Issue with Invoke-RestMethod and JiraPS module

Time:07-19

I'm using the JiraPS module and I have already raised a bug for this issue, however I'm trying to work around it. I am using Jira Cloud and have found some gaps between how Jira Server and Jira Cloud operate (namely on things like using username for server but userid for cloud). When I try to call the JiraPS function Add-JiraGroupMember it errors out throwing a 401 (the same $credential is being passed for adding user, which doesn't fail).

See bug report

However I took that function and did some tweaking to it to try to make it work:

function Add-JiraGroupMemberCloud {
    [CmdletBinding( SupportsShouldProcess )]
    param(
        [Parameter( Mandatory, ValueFromPipeline )]
        [Alias('GroupName')]
        [ValidateNotNullOrEmpty()]
        [Object[]]
        $Group,

        [Parameter( Mandatory )]
        [ValidateNotNullOrEmpty()]
        [Object[]]
        $User,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential,

        [Switch]
        $PassThru
    )

    Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"

    $server = Get-JiraConfigServer -ErrorAction Stop

    $resourceURi = "$server/rest/api/2/group/user?groupId={0}"

    foreach ($_group in $Group) {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing [$_group]"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Processing `$_group [$_group]"

        $groupObj = Get-JiraGroup -GroupName $_group -Credential $Credential -ErrorAction Stop
        $groupMembers = (Get-JiraGroupMember -Group $_group -Credential $Credential -ErrorAction Stop).AccountId

        if ($groupMembers -notcontains $user.AccountId) {
            Write-Debug -Message "[$($MyInvocation.MyCommand.Name)] User [$($user.EmailAddress)] is not already in group [$_group]. Adding user."

            $parameter = @{
                URI        = $resourceURi -f ($groupObj.RestURL -split ("groupID="))[1]
                Method     = "POST"
                headers    = @{'Accept'='application/json'; 'Content-Type'='application/json'}
                Body       = ConvertTo-Json -InputObject @{ 'accountId' = $user.AccountId }
                Credential = $Credential
            }

            # echo "curl --request POST \`n  --url $($parameter.URI) \`n  --user ""$($credential.GetNetworkCredential().Username):$($credential.GetNetworkCredential().password)"" \`n  --header 'Accept: application/json' \`n  --header 'Content-Type: application/json' \`n  --data '$($parameter.Body)'"

            Write-Debug -Message "[$($MyInvocation.MyCommand.Name)] Invoking JiraMethod with `$parameter"
            if ($PSCmdlet.ShouldProcess($GroupName, "Adding user '$($user.AccountId)'.")) {
                Try{
                    $result = Invoke-RestMethod @parameter
                }
                Catch{
                    return $_
                }
            }
        }
        else {
            Write-Warning -Message "User [$($user.EmailAddress)] is already a member of group [$_group]"
        }
    }

    if ($PassThru) {
        Write-Output (ConvertTo-JiraGroup -InputObject $result)
    }
}

When it hits the invoke-restmethod it does bomb out and return an error:

Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.

so I added a step in there that basically builds out the call using cURL (based on the structure example in the Jira REST API docs). When I put a breakpoint in at the invoke-restmethod, and I run the echo to get the cURL command and run it in ubuntu, it works without any issues. I cannot seem to figure out what the issue with the invoke-restmethod call is, or why it would work in cURL, but I assuming I'm doing something stupid that I'm hoping someone here can see better than I can.

CodePudding user response:

By default, Invoke-RestMethod does not perform authentication. Solutions based on your PowerShell version:

PowerShell >= v6.0

You can use the -Authentication parameter to define an authentication method:

-Authentication

Specifies the explicit authentication type to use for the request. The default is None. The Authentication parameter can't be used with the UseDefaultCredentials parameter.

Available Authentication Options:

  • None: This is the default option when Authentication is not supplied. No explicit authentication will be used.
  • Basic: Requires Credential. The credentials will be used to send an RFC 7617 Basic Authentication Authorization: Basic header in the format of base64(user:password).
  • Bearer: Requires the Token parameter. Sends an RFC 6750 Authorization: Bearer header with the supplied token.
  • OAuth: Requires the Token parameter. Sends an RFC 6750 Authorization: Bearer header with the supplied token.

Supplying Authentication overrides any Authorization headers supplied to Headers or included in WebSession.

This feature was added in PowerShell 6.0.0.

PowerShell <= v5.1

You have to do perform your authentication manually through the headers. Example for Basic Authentication:

$base64Creds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($Credential.UserName):$($Credential.GetNetworkCredential().Password)"))

# And then add the following key-value-pair to your headers hash table:

headers    = @{Authorization="Basic $base64Creds";...
  • Related