Skip to content
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

P12 cert password #300

Merged
merged 4 commits into from
Jun 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 42 additions & 32 deletions PSGSuite/Private/EncryptionHelpers.ps1
Original file line number Diff line number Diff line change
@@ -1,47 +1,58 @@
function Get-GSDecryptedConfig {
[CmdletBinding()]
Param(
[parameter(Position = 0,ValueFromPipeline,Mandatory)]
[parameter(Position = 0, ValueFromPipeline, Mandatory)]
[object]
$Config,
[parameter(Position = 1,Mandatory)]
[parameter(Position = 1, Mandatory)]
[string]
$ConfigName,
[parameter(Position = 2)]
[string]
$ConfigPath
)
Process {
$Config | Select-Object -Property `
@{l = 'ConfigName';e = { $ConfigName }},
@{l = 'P12KeyPath'; e = { Invoke-GSDecrypt $_.P12KeyPath } },
'P12Key',
@{l = 'P12KeyPassword'; e = { Invoke-GSDecrypt $_.P12KeyPassword } },
@{l = 'P12KeyObject'; e = { Invoke-GSDecrypt $_.P12KeyObject } },
@{l = 'ClientSecretsPath'; e = { Invoke-GSDecrypt $_.ClientSecretsPath } },
@{l = 'ClientSecrets'; e = { Invoke-GSDecrypt $_.ClientSecrets } },
$Config | Select-Object -Property @(
@{l = 'ConfigName'; e = { $ConfigName }}
@{l = 'P12KeyPath'; e = { Invoke-GSDecrypt $_.P12KeyPath } }
'P12Key'
@{l = 'P12KeyPassword'; e = { Invoke-GSDecrypt $_.P12KeyPassword } }
@{l = 'P12KeyObject'; e = { Invoke-GSDecrypt $_.P12KeyObject } }
@{l = 'JSONServiceAccountKeyPath'; e = {Invoke-GSDecrypt $_.JSONServiceAccountKeyPath}}
@{l = 'JSONServiceAccountKey'; e = {Invoke-GSDecrypt $_.JSONServiceAccountKey}}
@{l = 'ClientSecretsPath'; e = { Invoke-GSDecrypt $_.ClientSecretsPath } }
@{l = 'ClientSecrets'; e = { Invoke-GSDecrypt $_.ClientSecrets } }
@{l = 'AppEmail'; e = {
if ($_.AppEmail) {
if ($_.JSONServiceAccountKey) {
(Invoke-GSDecrypt $_.JSONServiceAccountKey | ConvertFrom-Json).client_email
} elseif ($_.AppEmail) {
Invoke-GSDecrypt $_.AppEmail
}
elseif ($_.ClientSecrets) {
(Invoke-GSDecrypt $_.ClientSecrets | ConvertFrom-Json).client_email
}
}
@{l = 'AdminEmail'; e = {
if ($_.AdminEmail) {
Invoke-GSDecrypt $_.AdminEmail
} elseif ($_.JSONServiceAccountKey) {
(Invoke-GSDecrypt $_.JSONServiceAccountKey | ConvertFrom-Json).client_email
} elseif ($_.AppEmail) {
Invoke-GSDecrypt $_.AppEmail
}
}
},
@{l = 'AdminEmail'; e = { Invoke-GSDecrypt $_.AdminEmail } },
@{l = 'CustomerID'; e = { Invoke-GSDecrypt $_.CustomerID } },
@{l = 'Domain'; e = { Invoke-GSDecrypt $_.Domain } },
@{l = 'Preference'; e = { Invoke-GSDecrypt $_.Preference } },
}
@{l = 'CustomerID'; e = { Invoke-GSDecrypt $_.CustomerID } }
@{l = 'Domain'; e = { Invoke-GSDecrypt $_.Domain } }
@{l = 'Preference'; e = { Invoke-GSDecrypt $_.Preference } }
@{l = 'ServiceAccountClientID'; e = {
if ($_.ServiceAccountClientID) {
if ($_.JSONServiceAccountKey) {
(Invoke-GSDecrypt $_.JSONServiceAccountKey | ConvertFrom-Json).client_id
} elseif ($_.ServiceAccountClientID) {
Invoke-GSDecrypt $_.ServiceAccountClientID
}
elseif ($_.ClientSecrets) {
(Invoke-GSDecrypt $_.ClientSecrets | ConvertFrom-Json).client_id
} elseif ($_.ClientSecrets) {
(Invoke-GSDecrypt $_.ClientSecrets | ConvertFrom-Json).installed.client_id
}
}
},
}
@{l = 'Chat'; e = {
$dict = @{
Webhooks = @{ }
Expand All @@ -55,10 +66,12 @@ function Get-GSDecryptedConfig {
}
$dict
}
},
}
@{l = 'ConfigPath'; e = {
if ($ConfigPath) {(Resolve-Path $ConfigPath).Path} elseif ($_.ConfigPath) {$_.ConfigPath} else {$null}
}}
if ($ConfigPath) {(Resolve-Path $ConfigPath).Path} elseif ($_.ConfigPath) {$_.ConfigPath} else {$null}
}
}
)
}
}
function Invoke-GSDecrypt {
Expand All @@ -69,11 +82,9 @@ function Invoke-GSDecrypt {
$String
)
)
}
elseif ($String -is [ScriptBlock]) {
} elseif ($String -is [ScriptBlock]) {
$String.InvokeReturnAsIs()
}
else {
} else {
$String
}
}
Expand All @@ -82,8 +93,7 @@ Function Invoke-GSEncrypt {
param($string)
if ($string -is [System.String] -and -not [String]::IsNullOrEmpty($String)) {
ConvertTo-SecureString -String $string -AsPlainText -Force
}
else {
} else {
$string
}
}
29 changes: 25 additions & 4 deletions PSGSuite/Public/Configuration/Import-PSGSuiteConfig.ps1
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
function Import-PSGSuiteConfig {
<#
.SYNOPSIS
Allows you to import an unecrypted PSGSuite config from a portable JSON string format, typically created with Export-PSGSuiteConfig. Useful for moving a config to a new machine or storing the full as an encrypted string in your CI/CD / Automation tools.
Allows you to import an unecrypted PSGSuite config from a portable JSON string format, typically created with Export-PSGSuiteConfig. Can also import directly from a PSCustomObject. Useful for moving a config to a new machine or storing the full as an encrypted string in your CI/CD / Automation tools.

.DESCRIPTION
Allows you to import an unecrypted PSGSuite config from a portable JSON string format, typically created with Export-PSGSuiteConfig. Useful for moving a config to a new machine or storing the full as an encrypted string in your CI/CD / Automation tools.
Allows you to import an unecrypted PSGSuite config from a portable JSON string format, typically created with Export-PSGSuiteConfig. Can also import directly from a PSCustomObject. Useful for moving a config to a new machine or storing the full as an encrypted string in your CI/CD / Automation tools.

.PARAMETER Json
The Json string to import.

.PARAMETER Path
The path of the Json file you would like import.

.PARAMETER Object
The PSCustomObject you would like to import

.PARAMETER Temporary
If $true, the imported config is not stored in the config file and the imported config persists only for the current session.

Expand All @@ -23,6 +26,16 @@ function Import-PSGSuiteConfig {
Import-PSGSuiteConfig -Json '$(PSGSuiteConfigJson)' -Temporary

Azure Pipelines inline script task that uses a Secure Variable named 'PSGSuiteConfigJson' with the Config JSON string stored in it, removing the need to include credential or key files anywhere.

.EXAMPLE
[PSCustomObject]$PSGSuiteSettings = [PSCustomObject]@{
P12KeyObject = Get-AutomationCertificate -name 'gcert.p12'
AppEmail = Get-AutomationVariable -name 'gappemail'
AdminEmail = Get-AutomationVariable -name 'gadminemail'
}
Import-PSGsuiteConfig -Object $PSGSuiteSettings -Temporary

Some properties can't be serialized in JSON, this is another way to store secrets in your automation tool (this example shows Azure Automation)
#>
[CmdletBinding(DefaultParameterSetName = "Json")]
Param (
Expand All @@ -34,6 +47,10 @@ function Import-PSGSuiteConfig {
[Alias('P')]
[String]
$Path,
[parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = "Object")]
[Alias('O')]
[PSCustomObject]
$Object,
[parameter(Mandatory = $false)]
[Alias('Temp','T')]
[Switch]
Expand All @@ -47,11 +64,15 @@ function Import-PSGSuiteConfig {
switch ($PSCmdlet.ParameterSetName) {
Path {
Write-Verbose "Importing config from path: $Path"
$script:PSGSuite = (ConvertFrom-Json (Get-Content $Path -Raw))
$script:PSGSuite = (ConvertFrom-Json (Get-Content $Path -Raw)) | Get-GSDecryptedConfig -ConfigName 'ImportPath'
}
Json {
Write-Verbose "Importing config from Json string"
$script:PSGSuite = (ConvertFrom-Json $Json)
$script:PSGSuite = (ConvertFrom-Json $Json) | Get-GSDecryptedConfig -ConfigName 'ImportJSON'
}
Object {
Write-Verbose "Importing config from Object"
$script:PSGSuite = $Object | Get-GSDecryptedConfig -ConfigName 'ImportObject'
}
}
if (-not $Temporary) {
Expand Down
21 changes: 18 additions & 3 deletions PSGSuite/Public/Configuration/Set-PSGSuiteConfig.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ function Set-PSGSuiteConfig {
.PARAMETER P12KeyPassword
The password for the P12 Key file. If not specified the default of 'notasecret' will be used and this config value will not be set. This is only needed in the case where the P12 file has been manually rexported with a custom password

.PARAMETER JSONServiceAccountKeyPath
The path to the Service Account JSON file downloaded from the Google Developer's Console.

.PARAMETER JSONServiceAccountKey
The string contents of the Serivce Account JSON file downloaded from the Google Developer's Console.

.PARAMETER ClientSecretsPath
The path to the Client Secrets JSON file downloaded from the Google Developer's Console. Using the ClientSecrets JSON will prompt the user to complete OAuth2 authentication in their browser on the first run and store the retrieved Refresh and Access tokens in the user's home directory. The config will auto-update with this value after running any command, if ClientSecretsPath is filled and this value is not already present. If JSONServiceAccountKeyPath or P12KeyPath is also specified, ClientSecretsPath will be ignored.

Expand Down Expand Up @@ -102,6 +108,12 @@ function Set-PSGSuiteConfig {
$P12KeyPassword,
[parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[string]
$JSONServiceAccountKeyPath,
[parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[string]
$JSONServiceAccountKey,
[parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[string]
$ClientSecretsPath,
[parameter(Mandatory = $false,ValueFromPipelineByPropertyName = $true)]
[string]
Expand Down Expand Up @@ -155,7 +167,7 @@ function Set-PSGSuiteConfig {
}
}
Write-Verbose "Setting config name '$ConfigName'"
$configParams = @('P12Key','P12KeyPath','P12KeyPassword','ClientSecretsPath','ClientSecrets','AppEmail','AdminEmail','CustomerID','Domain','Preference','ServiceAccountClientID','Webhook','Space')
$configParams = @('P12Key','P12KeyPath','P12KeyPassword','JSONServiceAccountKeyPath','JSONServiceAccountKey','ClientSecretsPath','ClientSecrets','AppEmail','AdminEmail','CustomerID','Domain','Preference','ServiceAccountClientID','Webhook','Space')
if ($SetAsDefaultConfig -or !$configHash["DefaultConfig"]) {
$configHash["DefaultConfig"] = $ConfigName
}
Expand All @@ -181,8 +193,11 @@ function Set-PSGSuiteConfig {
$configHash["$ConfigName"]['P12Key'] = ([System.IO.File]::ReadAllBytes($PSBoundParameters[$key]))
}
}
P12KeyPassword {
$configHash["$ConfigName"][$key] = $PSBoundParameters[$key]
JSONServiceAccountKeyPath {
if (-not [System.String]::IsNullOrWhiteSpace($PSBoundParameters[$key].Trim())) {
$configHash["$ConfigName"][$key] = (Invoke-GSEncrypt $PSBoundParameters[$key])
$configHash["$ConfigName"]['JSONServiceAccountKey'] = (Invoke-GSEncrypt $(Get-Content $PSBoundParameters[$key] -Raw))
}
}
ClientSecretsPath {
if (-not [System.String]::IsNullOrWhiteSpace($PSBoundParameters[$key].Trim())) {
Expand Down
3 changes: 3 additions & 0 deletions Tests/2. Unit Tests/Configuration/AppEmailOnly.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
AppEmail = 'app@psgsuite.io'
}
3 changes: 3 additions & 0 deletions Tests/2. Unit Tests/Configuration/ClientSecrets.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
ClientSecrets = '{"installed":{"client_id":"123-abc.apps.googleusercontent.com","project_id":"test-data-456","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"secret","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}'
}
1 change: 1 addition & 0 deletions Tests/2. Unit Tests/Configuration/JSONConfiguration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"JSONServiceAccountKey":"{\r\n \"type\": \"service_account\",\r\n \"project_id\": \"psgsuite-id\",\r\n \"private_key_id\": \"12345\",\r\n \"private_key\": \"-----BEGIN PRIVATE KEY-----\\n-----END PRIVATE KEY-----\\n\",\r\n \"client_email\": \"service@psgsuite.io\",\r\n \"client_id\": \"6789\",\r\n \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\r\n \"token_uri\": \"https://oauth2.googleapis.com/token\",\r\n \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\r\n \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/service%40psgsuite.io\"\r\n}\r\n"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@{
JSONServiceAccountKey ='{"type":"service_account","project_id":"psgsuite-id","private_key_id":"12345","private_key":"-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n","client_email":"service@psgsuite.io","client_id":"6789","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/service%40psgsuite.io"}'
AdminEmail = 'admin@psgsuite.io'
}
12 changes: 12 additions & 0 deletions Tests/2. Unit Tests/Configuration/JSONServiceKey.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "service_account",
"project_id": "psgsuite-id",
"private_key_id": "12345",
"private_key": "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n",
"client_email": "service@psgsuite.io",
"client_id": "6789",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/service%40psgsuite.io"
}
3 changes: 3 additions & 0 deletions Tests/2. Unit Tests/Configuration/JSONServiceOnly.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
JSONServiceAccountKey ='{"type":"service_account","project_id":"psgsuite-id","private_key_id":"12345","private_key":"-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n","client_email":"service@psgsuite.io","client_id":"6789","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/service%40psgsuite.io"}'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<#
* Unit test files should be wrapped with InModuleScope
* Each unit test file should have the following above the Describe block(s):
1. A call to dot-source the core mocks and classes
2. A call to dot-source the appropriate Service mock and classes for the function being tested
#>

InModuleScope PSGSuite {
# Not importing the Core Mocks described above because we're testing some of that core
$ConfigDir = [System.IO.Path]::Combine("$env:BHProjectPath", "Tests", "2. Unit Tests", "Configuration")
Describe 'Get-PSGSuiteConfig mock tests' -Tag 'Configuration' {
Context 'When Get-PSGSuiteConfig retreives a config with only JSONServiceKey' {
$ConfigPSD1 = [System.IO.Path]::Combine($ConfigDir, "JSONServiceOnly.psd1")
$config = Get-PSGSuiteConfig -Path $ConfigPSD1 -PassThru -NoImport
It "Should return JSONServiceAccountKey" {
$config.JSONServiceAccountKey | Should -Not -BeNullOrEmpty
}
It "Should return ServiceAccountClientID as client_id from JSONServiceAccountKey" {
$config.ServiceAccountClientID | Should -Be '6789'
}
It "Should return AppEmail as client_email from JSONServiceAccountKey" {
$config.AppEmail | Should -Be 'service@psgsuite.io'
}
It "Should return AdminEmail as client_email from JSONServiceAccountKey" {
$config.AdminEmail | Should -Be 'service@psgsuite.io'
}
}
Context 'When Get-PSGSuiteConfig retreives a config with JSONServiceKey and AdminEmail' {
$ConfigPSD1 = [System.IO.Path]::Combine($ConfigDir, "JSONServiceAndAdminEmail.psd1")
$config = Get-PSGSuiteConfig -Path $ConfigPSD1 -PassThru -NoImport
It "Should return JSONServiceAccountKey" {
$config.JSONServiceAccountKey | Should -Not -BeNullOrEmpty
}
It "Should return ServiceAccountClientID as client_id from JSONServiceAccountKey" {
$config.ServiceAccountClientID | Should -Be '6789'
}
It "Should return AppEmail as client_email from JSONServiceAccountKey" {
$config.AppEmail | Should -Be 'service@psgsuite.io'
}
It "Should return AdminEmail from Config" {
$config.AdminEmail | Should -Be 'admin@psgsuite.io'
}
}
Context 'When Get-PSGSuiteConfig retreives a config with only AppEmail defined' {
$ConfigPSD1 = [System.IO.Path]::Combine($ConfigDir, "AppEmailOnly.psd1")
$config = Get-PSGSuiteConfig -Path $ConfigPSD1 -PassThru -NoImport
It "Should return AppEmail as from config" {
$config.AppEmail | Should -Be 'app@psgsuite.io'
}
It "Should return AdminEmail as AppEmail from config when no AppEmail present" {
$config.AdminEmail | Should -Be 'app@psgsuite.io'
}
}
Context 'When Get-PSGSuiteConfig retreives a config with only ClientSecrets defined' {
$ConfigPSD1 = [System.IO.Path]::Combine($ConfigDir, "ClientSecrets.psd1")
$config = Get-PSGSuiteConfig -Path $ConfigPSD1 -PassThru -NoImport
It "Should return ClientSecrets" {
$config.ClientSecrets | Should -Not -BeNullOrEmpty
}
It "Should return ServiceAccountClientID as installed.client_id from Client Secrets" {
$config.ServiceAccountClientID | Should -Be '123-abc.apps.googleusercontent.com'
}
}
}
}
Loading