Skip to content

Commit

Permalink
Merge branch 'develop' into fix/AtlassianPS#324-FixedDateFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
lipkau authored Dec 12, 2018
2 parents 1f5f641 + 41d4bb3 commit b8b4130
Show file tree
Hide file tree
Showing 6 changed files with 410 additions and 23 deletions.
8 changes: 0 additions & 8 deletions JiraPS/Public/Get-JiraIssueAttachment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,6 @@ function Get-JiraIssueAttachment {

ConvertTo-JiraAttachment -InputObject $attachments
}
else {
$errorMessage = @{
Category = "ObjectNotFound"
CategoryActivity = "Searching for resource"
Message = "This issue does not have any attachments"
}
Write-Error @errorMessage
}
}

end {
Expand Down
68 changes: 68 additions & 0 deletions JiraPS/Public/Get-JiraIssueAttachmentFile.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
function Get-JiraIssueAttachmentFile {
# .ExternalHelp ..\JiraPS-help.xml
[CmdletBinding()]
[OutputType([Bool])]
param (
[Parameter( Mandatory, ValueFromPipeline )]
[PSTypeName('JiraPS.Attachment')]
$Attachment,

[ValidateScript(
{
if (-not (Test-Path $_)) {
$errorItem = [System.Management.Automation.ErrorRecord]::new(
([System.ArgumentException]"Path not found"),
'ParameterValue.FileNotFound',
[System.Management.Automation.ErrorCategory]::ObjectNotFound,
$_
)
$errorItem.ErrorDetails = "Invalid path '$_'."
$PSCmdlet.ThrowTerminatingError($errorItem)
}
else {
return $true
}
}
)]
[String]
$Path,

[Parameter()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)

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

process {
Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)"
Write-DebugMessage "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)"

foreach ($_Attachment in $Attachment) {
if ($Path) {
$filename = Join-Path $Path $_Attachment.Filename
}
else {
$filename = $_Attachment.Filename
}

$iwParameters = @{
Uri = $_Attachment.Content
Method = 'Get'
Headers = @{"Accept" = $_Attachment.MediaType}
OutFile = $filename
Credential = $Credential
}

$result = Invoke-JiraMethod @iwParameters
(-not $result)
}
}

end {
Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended"
}
}
154 changes: 154 additions & 0 deletions Tests/Functions/Get-JiraIssueAttachmentFile.Unit.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#requires -modules BuildHelpers
#requires -modules @{ ModuleName = "Pester"; ModuleVersion = "4.4.0" }

Describe "Get-JiraIssueAttachmentFile" -Tag 'Unit' {

BeforeAll {
Remove-Item -Path Env:\BH*
$projectRoot = (Resolve-Path "$PSScriptRoot/../..").Path
if ($projectRoot -like "*Release") {
$projectRoot = (Resolve-Path "$projectRoot/..").Path
}

Import-Module BuildHelpers
Set-BuildEnvironment -BuildOutput '$ProjectPath/Release' -Path $projectRoot -ErrorAction SilentlyContinue

$env:BHManifestToTest = $env:BHPSModuleManifest
$script:isBuild = $PSScriptRoot -like "$env:BHBuildOutput*"
if ($script:isBuild) {
$Pattern = [regex]::Escape($env:BHProjectPath)

$env:BHBuildModuleManifest = $env:BHPSModuleManifest -replace $Pattern, $env:BHBuildOutput
$env:BHManifestToTest = $env:BHBuildModuleManifest
}

Import-Module "$env:BHProjectPath/Tools/BuildTools.psm1"

Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue
Import-Module $env:BHManifestToTest
}
AfterAll {
Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue
Remove-Module BuildHelpers -ErrorAction SilentlyContinue
Remove-Item -Path Env:\BH*
}

InModuleScope JiraPS {

. "$PSScriptRoot/../Shared.ps1"

$jiraServer = 'http://jiraserver.example.com'
$issueID = 41701
$issueKey = 'IT-3676'

$attachments = @"
[
{
"self": "$jiraServer/rest/api/2/attachment/10013",
"id": "10013",
"filename": "foo.pdf",
"author": {
"self": "$jiraServer/rest/api/2/user?username=admin",
"name": "admin",
"key": "admin",
"accountId": "000000:000000-0000-0000-0000-ab899c878d00",
"emailAddress": "[email protected]",
"avatarUrls": { },
"displayName": "Admin",
"active": true,
"timeZone": "Europe/Berlin"
},
"created": "2017-10-16T10:06:29.399+0200",
"size": 60444,
"mimeType": "application/pdf",
"content": "$jiraServer/secure/attachment/10013/foo.pdf"
},
{
"self": "$jiraServer/rest/api/2/attachment/10010",
"id": "10010",
"filename": "bar.pdf",
"author": {
"self": "$jiraServer/rest/api/2/user?username=admin",
"name": "admin",
"key": "admin",
"accountId": "000000:000000-0000-0000-0000-ab899c878d00",
"emailAddress": "[email protected]",
"avatarUrls": { },
"displayName": "Admin",
"active": true,
"timeZone": "Europe/Berlin"
},
"created": "2017-10-16T09:06:48.070+0200",
"size": 438098,
"mimeType": "'application/pdf'",
"content": "$jiraServer/secure/attachment/10010/bar.pdf"
}
]
"@

Mock Get-JiraIssueAttachment -ModuleName JiraPS {
$object = ConvertFrom-Json -InputObject $attachments
$object[0].PSObject.TypeNames.Insert(0, 'JiraPS.Attachment')
$object[1].PSObject.TypeNames.Insert(0, 'JiraPS.Attachment')
$object
}

Mock Invoke-JiraMethod -ModuleName JiraPS -ParameterFilter {
$Method -eq 'Get' -and
$URI -like "$jiraServer/secure/attachment/*"
} {
ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri', 'OutFile'
}

# Generic catch-all. This will throw an exception if we forgot to mock something.
Mock Invoke-JiraMethod -ModuleName JiraPS {
ShowMockInfo 'Invoke-JiraMethod' 'Method', 'Uri'
throw "Unidentified call to Invoke-JiraMethod"
}

#############
# Tests
#############

It 'only accepts JiraPS.Attachment as input' {
{ Get-JiraIssueAttachmentFile -Attachment (Get-Date) } | Should Throw
{ Get-JiraIssueAttachmentFile -Attachment (Get-ChildItem) } | Should Throw
{ Get-JiraIssueAttachmentFile -Attachment @('foo', 'bar') } | Should Throw
{ Get-JiraIssueAttachmentFile -Attachment (Get-JiraIssueAttachment -Issue "Foo") } | Should Not Throw
}

It 'takes the issue input over the pipeline' {
{ Get-JiraIssueAttachment -Issue "Foo" | Get-JiraIssueAttachmentFile } | Should Not Throw
}

It 'uses Invoke-JiraMethod for saving to disk' {
$script:ShowMockData = $true
Get-JiraIssueAttachment -Issue "Foo" | Get-JiraIssueAttachmentFile
Get-JiraIssueAttachment -Issue "Foo" | Get-JiraIssueAttachmentFile -Path "../"

$assertMockCalledSplat = @{
CommandName = 'Invoke-JiraMethod'
ModuleName = "JiraPS"
ParameterFilter = {
$OutFile -in @("foo.pdf", "bar.pdf")
}
Exactly = $true
Times = 2
Scope = 'It'
}
Assert-MockCalled @assertMockCalledSplat

$assertMockCalledSplat = @{
CommandName = 'Invoke-JiraMethod'
ModuleName = "JiraPS"
ParameterFilter = {
$OutFile -like "..*.pdf"
}
Exactly = $true
Times = 2
Scope = 'It'
}
Assert-MockCalled @assertMockCalledSplat
}
}
}
63 changes: 48 additions & 15 deletions docs/en-US/about_JiraPS_Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,65 @@ permalink: /docs/JiraPS/about/authentication.html

# SHORT DESCRIPTION

In order to authenticate with the Jira server, the user can provide the credentials with each command or create a session.
In order to authenticate with the Jira server, the user can provide the
credentials with each command or create a session.

# LONG DESCRIPTION

At present, there are two main methods of authenticating to Jira:

* HTTP basic authentication
* session-based authentication, which uses HTTP basic authentication once and preserves a session cookie.
* session-based authentication,
which uses HTTP basic authentication once and preserves a session cookie.

> Be sure to set JIRA up to use HTTPS with a valid SSL certificate if you are concerned about security!
> Be sure to set JIRA up to use HTTPS with a valid SSL certificate if you are
> concerned about security!
## HTTP Basic

Each JiraPS function that queries a Jira instance provides a `-Credential` parameter. Simply pass your Jira credentials to this parameter.
Each JiraPS function that queries a Jira instance provides
a `-Credential` parameter.
Simply pass your Jira credentials to this parameter.

```powershell
$cred = Get-Credential 'powershell'
Get-JiraIssue TEST-01 -Credential $cred
```

> HTTP basic authentication is not a secure form of authentication. It uses a Base64-encoded String of the format "username:password", and passes this string in clear text to Jira. Because decrypting this string and obtaining the username and password is trivial, the use of HTTPS is critical in any system that needs to remain secure.
> HTTP basic authentication is not a secure form of authentication.
> It uses a Base64-encoded String of the format "username:password"
> and passes this string in clear text to Jira. Because decrypting this
> string and obtaining the username and password is trivial,
> the use of HTTPS is critical in any system that needs to remain secure.
## API Token

API tokens (also called Private Access Token (PAT)) are tokens generated
by the user. This token is necessary when the user has a two-step verification
activated for his account.

An API token can be used for authenticating JiraPS with the server
in the same way as described in [HTTP Basic](#http-basic).
The only difference is, that instead of providing the password for the account,
the API token must be used.

> As of December 1st 2018, Atlassian requires API authentication
> with **Cloud Servers** to **always** use API Tokens.
> More information in the [Deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth/).
_More information on the API tokens and how to create one can be found at:_
_<https://confluence.atlassian.com/cloud/api-tokens-938839638.html>_

## Sessions

Jira sessions still require HTTP Basic Authentication once to create the connection.
But in this case a persistent session is saved as a `WebRequestSession`. This is Powershell's way of reusing the data provided with the first call.
Jira sessions still require [HTTP Basic](#http-basic) or [API Token](#api-token)
Authentication once to create the connection.
But in this case a persistent session is saved as a `WebRequestSession`.
This is Powershell's way of reusing the data provided with the first call.

> Previously Jira allowed for the authentication to use a session token. This token did not contain the username and password.
> But unfortunately, this API can no longer be used in combination with this module.
> Previously Jira allowed for the authentication to use a session token.
> This token did not contain the username and password.
> Unfortunately, this API can no longer be used in combination with this module.
To create a Jira session, you can use the New-JiraSession function:

Expand All @@ -48,17 +78,20 @@ $cred = Get-Credential 'powershell'
New-JiraSession -Credential $cred
```

Once you've created this session, you're done! You don't need to specify it when running other commands - JiraPS will manage this session internally.
Once you've created this session, you're done!
You don't need to specify it when running other commands - JiraPS will
manage this session internally.

The session is stored in the module's runtime.
This means that it will not be available in a new Powershell session or if the module is reloaded.
This means that it will not be available in a new Powershell session
or if the module is reloaded.

## What About OAuth?
## What About OAuth

Jira does support use of OAuth, but JiraPS does not yet.
Jira does support use of OAuth, but JiraPS does not - yet.
This is a to-do item.

# SEE ALSO

- [Wikipedia's "Basic Access Authentication"](https://en.wikipedia.org/wiki/Basic_access_authentication)
- [Implement OAuth for JiraPS](https://github.com/AtlassianPS/JiraPS/issues/101)
* [Wikipedia's "Basic Access Authentication"](https://en.wikipedia.org/wiki/Basic_access_authentication)
* [Implement OAuth for JiraPS](https://github.com/AtlassianPS/JiraPS/issues/101)
2 changes: 2 additions & 0 deletions docs/en-US/commands/Get-JiraIssueAttachment.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ If neither are supplied, this function will run with anonymous access to JIRA.

## RELATED LINKS

[Get-JiraAttachmentFile](../Get-JiraAttachmentFile/)

[Add-JiraIssueAttachment](../Add-JiraIssueAttachment/)

[Get-JiraIssue](../Get-JiraIssue/)
Expand Down
Loading

0 comments on commit b8b4130

Please sign in to comment.