azure-key-vault 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +119 -0
- data/Guardfile +19 -0
- data/README.md +20 -0
- data/Rakefile +19 -0
- data/azurekeyvault.gemspec +32 -0
- data/lib/key_vault.rb +9 -0
- data/lib/key_vault/auth.rb +53 -0
- data/lib/key_vault/client.rb +69 -0
- data/lib/key_vault/exceptions.rb +8 -0
- data/lib/key_vault/url.rb +37 -0
- data/lib/key_vault/version.rb +4 -0
- data/spec/key_vault/auth_spec.rb +64 -0
- data/spec/key_vault/client_spec.rb +97 -0
- data/spec/key_vault/url_spec.rb +40 -0
- data/spec/key_vault/version_spec.rb +7 -0
- data/spec/spec_helper.rb +1 -0
- metadata +228 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 14f95ef2cb7bf5a35564eaf2cdcabdfe2021ae82c70dd216d2b414aabcc08b00
|
4
|
+
data.tar.gz: ed2933a058f17415caacf02ccac98d5d63ee9dda71dbebd6fa577caf5fc44bb6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5823c8f29e088da5ceafe4907884af4fa7a018de9e0dceac1fcfe27d16b2e84787bdc34bfe4eff31ab1cf781e0558c9efa345d3b7430092ffb3d2f20f42f17ae
|
7
|
+
data.tar.gz: bc90aa686f941a5a78c86b55230966d33045e1d4622fd22d9280f9eb679d7f382a18adaff2fb97ff70935d146cb44f07fea510da73f82dd05d037ae9ce51fd51
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
azure-key-vault (0.0.15)
|
5
|
+
json_pure (~> 2.1)
|
6
|
+
rest-client (~> 2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
ast (2.3.0)
|
12
|
+
coderay (1.1.2)
|
13
|
+
diff-lcs (1.3)
|
14
|
+
domain_name (0.5.20170404)
|
15
|
+
unf (>= 0.0.5, < 1.0.0)
|
16
|
+
ffi (1.9.18)
|
17
|
+
formatador (0.2.5)
|
18
|
+
guard (2.14.2)
|
19
|
+
formatador (>= 0.2.4)
|
20
|
+
listen (>= 2.7, < 4.0)
|
21
|
+
lumberjack (>= 1.0.12, < 2.0)
|
22
|
+
nenv (~> 0.1)
|
23
|
+
notiffany (~> 0.0)
|
24
|
+
pry (>= 0.9.12)
|
25
|
+
shellany (~> 0.0)
|
26
|
+
thor (>= 0.18.1)
|
27
|
+
guard-bundler (2.1.0)
|
28
|
+
bundler (~> 1.0)
|
29
|
+
guard (~> 2.2)
|
30
|
+
guard-compat (~> 1.1)
|
31
|
+
guard-compat (1.2.1)
|
32
|
+
guard-rdoc (1.0.3)
|
33
|
+
guard
|
34
|
+
guard-rspec (4.7.3)
|
35
|
+
guard (~> 2.1)
|
36
|
+
guard-compat (~> 1.1)
|
37
|
+
rspec (>= 2.99.0, < 4.0)
|
38
|
+
http-cookie (1.0.3)
|
39
|
+
domain_name (~> 0.5)
|
40
|
+
json_pure (2.1.0)
|
41
|
+
listen (3.1.5)
|
42
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
43
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
44
|
+
ruby_dep (~> 1.2)
|
45
|
+
lumberjack (1.0.12)
|
46
|
+
method_source (0.9.0)
|
47
|
+
mime-types (3.1)
|
48
|
+
mime-types-data (~> 3.2015)
|
49
|
+
mime-types-data (3.2016.0521)
|
50
|
+
nenv (0.3.0)
|
51
|
+
netrc (0.11.0)
|
52
|
+
notiffany (0.1.1)
|
53
|
+
nenv (~> 0.1)
|
54
|
+
shellany (~> 0.0)
|
55
|
+
parallel (1.12.1)
|
56
|
+
parser (2.4.0.2)
|
57
|
+
ast (~> 2.3)
|
58
|
+
powerpack (0.1.1)
|
59
|
+
pry (0.11.3)
|
60
|
+
coderay (~> 1.1.0)
|
61
|
+
method_source (~> 0.9.0)
|
62
|
+
rainbow (3.0.0)
|
63
|
+
rake (10.4.2)
|
64
|
+
rb-fsevent (0.10.2)
|
65
|
+
rb-inotify (0.9.10)
|
66
|
+
ffi (>= 0.5.0, < 2)
|
67
|
+
rb-readline (0.5.5)
|
68
|
+
rdoc (4.3.0)
|
69
|
+
rest-client (2.0.2)
|
70
|
+
http-cookie (>= 1.0.2, < 2.0)
|
71
|
+
mime-types (>= 1.16, < 4.0)
|
72
|
+
netrc (~> 0.8)
|
73
|
+
rspec (3.7.0)
|
74
|
+
rspec-core (~> 3.7.0)
|
75
|
+
rspec-expectations (~> 3.7.0)
|
76
|
+
rspec-mocks (~> 3.7.0)
|
77
|
+
rspec-core (3.7.0)
|
78
|
+
rspec-support (~> 3.7.0)
|
79
|
+
rspec-expectations (3.7.0)
|
80
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
81
|
+
rspec-support (~> 3.7.0)
|
82
|
+
rspec-mocks (3.7.0)
|
83
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
84
|
+
rspec-support (~> 3.7.0)
|
85
|
+
rspec-support (3.7.0)
|
86
|
+
rubocop (0.52.1)
|
87
|
+
parallel (~> 1.10)
|
88
|
+
parser (>= 2.4.0.2, < 3.0)
|
89
|
+
powerpack (~> 0.1)
|
90
|
+
rainbow (>= 2.2.2, < 4.0)
|
91
|
+
ruby-progressbar (~> 1.7)
|
92
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
93
|
+
ruby-progressbar (1.9.0)
|
94
|
+
ruby_dep (1.5.0)
|
95
|
+
shellany (0.0.1)
|
96
|
+
thor (0.20.0)
|
97
|
+
unf (0.1.4)
|
98
|
+
unf_ext
|
99
|
+
unf_ext (0.0.7.4)
|
100
|
+
unicode-display_width (1.3.0)
|
101
|
+
|
102
|
+
PLATFORMS
|
103
|
+
ruby
|
104
|
+
|
105
|
+
DEPENDENCIES
|
106
|
+
azure-key-vault!
|
107
|
+
bundler (~> 1.12)
|
108
|
+
guard
|
109
|
+
guard-bundler
|
110
|
+
guard-rdoc
|
111
|
+
guard-rspec
|
112
|
+
rake (~> 10.0)
|
113
|
+
rb-readline
|
114
|
+
rdoc (~> 4.2)
|
115
|
+
rspec (~> 3.0)
|
116
|
+
rubocop
|
117
|
+
|
118
|
+
BUNDLED WITH
|
119
|
+
1.12.5
|
data/Guardfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
## Uncomment and set this to only include directories you want to watch
|
2
|
+
# directories %w(lib config test spec features) \
|
3
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
4
|
+
interactor :off
|
5
|
+
|
6
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
7
|
+
watch(%r{^spec/.+_spec\.rb$})
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
9
|
+
end
|
10
|
+
|
11
|
+
guard :rdoc, main: 'README.md' do
|
12
|
+
#watch('README.md')
|
13
|
+
watch(%r{^README.md|lib/.+\.rb$}) { |m | ['lib', 'README.md'] }
|
14
|
+
end
|
15
|
+
|
16
|
+
guard :bundler do
|
17
|
+
watch('Gemfile')
|
18
|
+
watch(%r{^(.+\.gemspec)$})
|
19
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# azure-key-vault
|
2
|
+
Ruby wrapper for Azure Key Vault REST API
|
3
|
+
|
4
|
+
## Examples
|
5
|
+
|
6
|
+
### Get an access token
|
7
|
+
`bearer_token = KeyVault::Auth.new(tenant_id, client_id, client_secret).bearer_token`
|
8
|
+
|
9
|
+
### Get client for and existing Azure Key Vault
|
10
|
+
`vault = KeyVault::Client.new(vault_name, bearer_token)`
|
11
|
+
|
12
|
+
or
|
13
|
+
|
14
|
+
`vault = KeyVault::Client.new(vault_name, bearer_token, api_version: '<other _api_version>')`
|
15
|
+
|
16
|
+
### Get the most recent version of a secret
|
17
|
+
`vault.get_secret(secret_name)`
|
18
|
+
|
19
|
+
### Get a specific version of a secret
|
20
|
+
`vault.get_secret(secret_name, secret_version)`
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
rescue LoadError
|
12
|
+
# no rspec available
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'doc'
|
17
|
+
rdoc.main = 'README.md'
|
18
|
+
rdoc.rdoc_files.include('README.md', 'lib')
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- mode: ruby; -*-
|
2
|
+
$LOAD_PATH.unshift 'lib'
|
3
|
+
require 'key_vault/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'azure-key-vault'
|
7
|
+
s.version = KeyVault::VERSION.split(/[-+]/, 2).first
|
8
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
9
|
+
s.summary = 'Ruby Client for Azure Key Vault'
|
10
|
+
s.homepage = 'https://github.com/MikeAScott/azure-key-vault'
|
11
|
+
s.email = 'mike.scott2@hiscox.com'
|
12
|
+
s.authors = ['Mike Scott']
|
13
|
+
s.has_rdoc = false
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = (%x[git ls-files]).split($RS) - %w[.gitignore]
|
17
|
+
s.require_paths = %w[lib]
|
18
|
+
|
19
|
+
s.add_runtime_dependency 'json_pure', '~>2.1'
|
20
|
+
s.add_runtime_dependency 'rest-client', '~>2.0'
|
21
|
+
|
22
|
+
s.add_development_dependency 'bundler', '~> 1.12'
|
23
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
24
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
25
|
+
s.add_development_dependency 'rdoc', '~> 4.2'
|
26
|
+
s.add_development_dependency 'rubocop'
|
27
|
+
s.add_development_dependency 'rb-readline'
|
28
|
+
s.add_development_dependency 'guard'
|
29
|
+
s.add_development_dependency 'guard-rspec'
|
30
|
+
s.add_development_dependency 'guard-rdoc'
|
31
|
+
s.add_development_dependency 'guard-bundler'
|
32
|
+
end
|
data/lib/key_vault.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
module KeyVault
|
4
|
+
# Authenticater for Azure Key Vault
|
5
|
+
class Auth
|
6
|
+
# Create authenticator using Azure principal
|
7
|
+
# ==== Parameters:
|
8
|
+
# +tenant_id+:: Azure tenant id
|
9
|
+
# +client_id+:: Azure client id or (key)
|
10
|
+
# +client_secret+:: Azure client secret
|
11
|
+
def initialize(tenant_id, client_id, client_secret)
|
12
|
+
@tenant_id = tenant_id
|
13
|
+
@client_id = client_id
|
14
|
+
@client_secret = client_secret
|
15
|
+
end
|
16
|
+
|
17
|
+
# Authenticates with Azure using OAUTH 2.0
|
18
|
+
# ==== Returns:
|
19
|
+
# A string containing the bearer token for insertion into request headers
|
20
|
+
# ==== Raises:
|
21
|
+
# +ArgumentError+:: If the authentication request format is invalid
|
22
|
+
# +KeyVault::Unauthorized+:: If authentication fails authorization
|
23
|
+
def bearer_token
|
24
|
+
result = RestClient::Request.execute(method: :post,
|
25
|
+
url: url,
|
26
|
+
payload: body,
|
27
|
+
headers: headers)
|
28
|
+
token_resp = JSON.parse(result)
|
29
|
+
"Bearer #{token_resp['access_token']}"
|
30
|
+
rescue RestClient::BadRequest
|
31
|
+
raise ArgumentError, 'Could not authenticate to Azure (Bad Request)'
|
32
|
+
rescue RestClient::Unauthorized
|
33
|
+
raise KeyVault::Unauthorized
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def headers
|
39
|
+
{ 'Content-Type' => 'application/x-www-form-urlencoded' }
|
40
|
+
end
|
41
|
+
|
42
|
+
def url
|
43
|
+
"https://login.windows.net/#{@tenant_id}/oauth2/token"
|
44
|
+
end
|
45
|
+
|
46
|
+
def body
|
47
|
+
{ 'grant_type' => 'client_credentials',
|
48
|
+
'client_id' => @client_id,
|
49
|
+
'client_secret' => @client_secret,
|
50
|
+
'resource' => 'https://vault.azure.net' }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'key_vault/auth'
|
2
|
+
require 'key_vault/url'
|
3
|
+
require 'key_vault/exceptions'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module KeyVault
|
8
|
+
# Client for Azure Key Vault
|
9
|
+
#
|
10
|
+
# Allows creation and retrieval of secrets from Azure Key Vault
|
11
|
+
#
|
12
|
+
# *N.B.* Secret names can contain only contain alphanumerics or hyphens.
|
13
|
+
# Any 'invalid' characters will be translated into hyphens.
|
14
|
+
class Client
|
15
|
+
# version of the Azure REST API being used
|
16
|
+
attr_reader :api_version
|
17
|
+
|
18
|
+
# Create client for a key vault
|
19
|
+
#
|
20
|
+
# ==== Parameters:
|
21
|
+
# +vault_name+:: The name of the key vault
|
22
|
+
# +bearer_token+:: The token obtained from #KeyVault::Auth
|
23
|
+
# +api_version+:: (*optional*) Version of the azure REST API to use.
|
24
|
+
# Defaults to +DEFAULT_API_VERSION+
|
25
|
+
def initialize(vault_name, bearer_token, api_version: DEFAULT_API_VERSION)
|
26
|
+
@vault_name = vault_name
|
27
|
+
@api_version = api_version || DEFAULT_API_VERSION
|
28
|
+
@bearer_token = bearer_token
|
29
|
+
@vault_url = Url.new(@vault_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Retrieves secret from key vault as a string
|
33
|
+
#
|
34
|
+
# ==== Parameters:
|
35
|
+
# +secret_name+:: Name of the secret (alphanumeric with hyphens)
|
36
|
+
# +secret_version+:: (*optional*) Version of the secret to retrieve.
|
37
|
+
# Defaults to latest version
|
38
|
+
# ==== Returns:
|
39
|
+
# A string containing the secret value or nil if not found
|
40
|
+
def get_secret(secret_name, secret_version = nil)
|
41
|
+
url = @vault_url.get_url(clean(secret_name), secret_version, @api_version)
|
42
|
+
headers = { 'Authorization' => @bearer_token }
|
43
|
+
response = RestClient.get(url, headers)
|
44
|
+
JSON.parse(response)['value']
|
45
|
+
rescue RestClient::NotFound
|
46
|
+
return nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adds a secret to key vault
|
50
|
+
#
|
51
|
+
# ==== Parameters:
|
52
|
+
# +secret_name+:: Name of the secret (alphanumeric with hyphens)
|
53
|
+
# +secret_value+:: Value of the secret as a string
|
54
|
+
def create_secret(secret_name, secret_value)
|
55
|
+
url = @vault_url.get_url(clean(secret_name), nil, @api_version)
|
56
|
+
body = @vault_url.get_body(secret_value)
|
57
|
+
headers = { 'Content-Type' => 'application/json',
|
58
|
+
'Authorization' => @bearer_token }
|
59
|
+
RestClient.put(url, body, headers)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Replaces non alphanumerics with hyphens
|
65
|
+
def clean(name)
|
66
|
+
name.gsub(/[^a-zA-Z0-9-]/, '-')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module KeyVault
|
2
|
+
# Helper for Key Vault URL's and REST document bodies
|
3
|
+
# :category: Internal
|
4
|
+
class Url
|
5
|
+
# Creates URL for keyvault from +bearer_token+ and +vault_name+
|
6
|
+
def initialize(vault_name)
|
7
|
+
@vault_name = vault_name
|
8
|
+
end
|
9
|
+
|
10
|
+
# Gets URL for the secret
|
11
|
+
def get_url(secret_name, version, api_version)
|
12
|
+
base_url = format(base_secret_url,
|
13
|
+
vault_name: CGI.escape(@vault_name),
|
14
|
+
secret_name: CGI.escape(secret_name))
|
15
|
+
base_url << "/#{version}" if version
|
16
|
+
base_url << get_api_version_string(api_version)
|
17
|
+
base_url
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns +secret_value+ as a json doc
|
21
|
+
def get_body(secret_value)
|
22
|
+
{ 'value' => secret_value }.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Returns url for the key vault
|
28
|
+
def base_secret_url
|
29
|
+
'https://%<vault_name>s.vault.azure.net/secrets/%<secret_name>s'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns api_version url parameter
|
33
|
+
def get_api_version_string(api_version)
|
34
|
+
"?api-version=#{api_version}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe KeyVault::Auth do
|
3
|
+
let(:tenant_id) {'the-tenant-id'}
|
4
|
+
let(:client_id) {'the-client-id'}
|
5
|
+
let(:client_secret) {'the-client-secret'}
|
6
|
+
|
7
|
+
describe('#new') do
|
8
|
+
it 'requires tenant_id, client_id and client_secret' do
|
9
|
+
auth = KeyVault::Auth.new(tenant_id,client_id, client_secret)
|
10
|
+
expect(auth).not_to be_nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.bearer_token' do
|
15
|
+
subject(:auth) { KeyVault::Auth.new(tenant_id,client_id, client_secret) }
|
16
|
+
let(:auth_url) { "https://login.windows.net/#{tenant_id}/oauth2/token" }
|
17
|
+
let(:access_token) { 'theaccesstoken' }
|
18
|
+
let(:auth_response) { %Q[{
|
19
|
+
"token_type":"Bearer",
|
20
|
+
"some_other_params":"...",
|
21
|
+
"resource":"https://vault.azure.net",
|
22
|
+
"access_token":"#{access_token}"
|
23
|
+
}] }
|
24
|
+
|
25
|
+
let(:rest_request) do
|
26
|
+
class_double('RestClient::Request')
|
27
|
+
.as_stubbed_const(:transfer_nested_constants => true)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'authenticates with Microsoft OAUTH' do
|
31
|
+
expect(rest_request).to receive(:execute).and_return(auth_response)
|
32
|
+
auth.bearer_token
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'raises argument error if bad request is returned' do
|
36
|
+
expect(rest_request).to receive(:execute).and_raise(RestClient::BadRequest)
|
37
|
+
expect{auth.bearer_token}.to raise_error(ArgumentError)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises custom Unauthorized exception if unauthorized' do
|
41
|
+
expect(rest_request).to receive(:execute).and_raise(RestClient::Unauthorized)
|
42
|
+
expect{auth.bearer_token}.to raise_error(KeyVault::Unauthorized)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'posts credentials in the request payload' do
|
46
|
+
auth_body_with_credentials = {
|
47
|
+
'grant_type' => 'client_credentials',
|
48
|
+
'client_id' => client_id,
|
49
|
+
'client_secret' => client_secret,
|
50
|
+
'resource' => 'https://vault.azure.net'
|
51
|
+
}
|
52
|
+
expect(rest_request).to receive(:execute)
|
53
|
+
.with(hash_including(method: :post, payload: auth_body_with_credentials))
|
54
|
+
.and_return(auth_response)
|
55
|
+
auth.bearer_token
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns the access_token as bearer token' do
|
59
|
+
expect(rest_request).to receive(:execute).and_return(auth_response)
|
60
|
+
expect(auth.bearer_token).to eq("Bearer #{access_token}")
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe KeyVault::Client do
|
3
|
+
subject(:client) { KeyVault::Client.new(vault_name, bearer_token) }
|
4
|
+
let(:vault_name) { 'the-vault' }
|
5
|
+
let(:bearer_token) { 'Bearer tokenvalue' }
|
6
|
+
|
7
|
+
describe '#new' do
|
8
|
+
it 'requires vault_name and bearer_token' do
|
9
|
+
client = KeyVault::Client.new(vault_name, bearer_token)
|
10
|
+
expect(client).not_to be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'defaults api_version' do
|
14
|
+
client = KeyVault::Client.new(vault_name, bearer_token)
|
15
|
+
expect(client.api_version).to eq KeyVault::DEFAULT_API_VERSION
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'allows setting of api_version' do
|
19
|
+
client = KeyVault::Client.new(vault_name, bearer_token,
|
20
|
+
api_version: '2015-06-01')
|
21
|
+
expect(client.api_version).to eq '2015-06-01'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '.get_secret' do
|
26
|
+
let(:secret_name) { 'the-secret' }
|
27
|
+
let(:secret_value) { 'top secret' }
|
28
|
+
let(:api_version) { KeyVault::DEFAULT_API_VERSION }
|
29
|
+
let(:secret_url) { "https://#{vault_name}.vault.azure.net/secrets/#{secret_name}?api-version=#{api_version}" }
|
30
|
+
let(:valid_response) do
|
31
|
+
<<-RESPONSE
|
32
|
+
{
|
33
|
+
"value": "#{secret_value}",
|
34
|
+
"contentType": "String",
|
35
|
+
"id": "https://#{vault_name}.vault.azure.net/secrets/#{secret_name}/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
36
|
+
"attributes": {
|
37
|
+
"enabled": true,
|
38
|
+
"created": 1512680041,
|
39
|
+
"updated": 1512680041,
|
40
|
+
"recoveryLevel": "Purgeable"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
RESPONSE
|
44
|
+
end
|
45
|
+
let(:rest_request) do
|
46
|
+
class_double('RestClient')
|
47
|
+
.as_stubbed_const(transfer_nested_constants: true)
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when secret_version is not supplied' do
|
51
|
+
it 'requests GET from secret url' do
|
52
|
+
expect(rest_request).to receive(:get)
|
53
|
+
.with(secret_url, 'Authorization' => bearer_token )
|
54
|
+
.and_return(valid_response)
|
55
|
+
client.get_secret secret_name
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns secret value from response' do
|
59
|
+
expect(rest_request).to receive(:get)
|
60
|
+
.and_return(valid_response)
|
61
|
+
returned_secret = client.get_secret secret_name
|
62
|
+
expect(returned_secret).to eq secret_value
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns nil if secret not found' do
|
66
|
+
expect(rest_request).to receive(:get).and_raise(RestClient::NotFound)
|
67
|
+
returned_secret = client.get_secret 'not-a-secret'
|
68
|
+
expect(returned_secret).to be_nil
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when secret_version is supplied' do
|
74
|
+
let(:secret_version) { 'abcdef' }
|
75
|
+
let(:secret_url) { "https://#{vault_name}.vault.azure.net/secrets/#{secret_name}/#{secret_version}?api-version=#{api_version}" }
|
76
|
+
it 'requests that version of the secret' do
|
77
|
+
expect(rest_request).to receive(:get)
|
78
|
+
.with(secret_url, 'Authorization' => bearer_token)
|
79
|
+
.and_return(valid_response)
|
80
|
+
client.get_secret(secret_name, secret_version)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when secret name has non alphanumerics' do
|
85
|
+
let(:secret_name_with_invalid_chars) { 'a secret::with!#&$chars-and-1234567890' }
|
86
|
+
let(:secret_name) { 'a-secret--with----chars-and-1234567890' }
|
87
|
+
it 'translates them to and spaces to hyphens' do
|
88
|
+
expect(rest_request).to receive(:get)
|
89
|
+
.with(secret_url, 'Authorization' => bearer_token)
|
90
|
+
.and_return(valid_response)
|
91
|
+
client.get_secret secret_name_with_invalid_chars
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe KeyVault::Url do
|
4
|
+
subject(:key_vault_url) { KeyVault::Url.new('the-vault-name') }
|
5
|
+
|
6
|
+
describe '#new' do
|
7
|
+
it 'requires a vault name' do
|
8
|
+
key_vault_url = KeyVault::Url.new('a-vault-name')
|
9
|
+
expect(key_vault_url).not_to be_nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.get_url' do
|
14
|
+
let(:secret_name) { 'the-secret-name' }
|
15
|
+
let(:secret_version) { '1234-1234-1234-1234' }
|
16
|
+
let(:api_version) { '2015-08-20' }
|
17
|
+
let(:correct_url) { "https://the-vault-name.vault.azure.net/secrets/#{secret_name}/#{secret_version}?api-version=#{api_version}" }
|
18
|
+
|
19
|
+
it 'gets url containing the vault and secret names' do
|
20
|
+
expect(key_vault_url.get_url(secret_name, secret_version, api_version))
|
21
|
+
.to eq correct_url
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when names in the URL need escaping' do
|
25
|
+
let(:url) { KeyVault::Url.new('the vault name') }
|
26
|
+
let(:encoded_url) { "https://the+vault+name.vault.azure.net/secrets/secret%3A%3Akey/#{secret_version}?api-version=#{api_version}" }
|
27
|
+
it 'URL encodes the URL' do
|
28
|
+
expect(url.get_url('secret::key', secret_version, api_version))
|
29
|
+
.to eq encoded_url
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.get_body' do
|
35
|
+
let(:correct_body) { { 'value' => 'the_secret_value' }.to_json }
|
36
|
+
it 'gets the secret value as json' do
|
37
|
+
expect(key_vault_url.get_body('the_secret_value')).to eq correct_body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'key_vault'
|
metadata
ADDED
@@ -0,0 +1,228 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: azure-key-vault
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.15
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Scott
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-01-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json_pure
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rdoc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rb-readline
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: guard
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: guard-rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: guard-rdoc
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: guard-bundler
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description:
|
182
|
+
email: mike.scott2@hiscox.com
|
183
|
+
executables: []
|
184
|
+
extensions: []
|
185
|
+
extra_rdoc_files: []
|
186
|
+
files:
|
187
|
+
- Gemfile
|
188
|
+
- Gemfile.lock
|
189
|
+
- Guardfile
|
190
|
+
- README.md
|
191
|
+
- Rakefile
|
192
|
+
- azurekeyvault.gemspec
|
193
|
+
- lib/key_vault.rb
|
194
|
+
- lib/key_vault/auth.rb
|
195
|
+
- lib/key_vault/client.rb
|
196
|
+
- lib/key_vault/exceptions.rb
|
197
|
+
- lib/key_vault/url.rb
|
198
|
+
- lib/key_vault/version.rb
|
199
|
+
- spec/key_vault/auth_spec.rb
|
200
|
+
- spec/key_vault/client_spec.rb
|
201
|
+
- spec/key_vault/url_spec.rb
|
202
|
+
- spec/key_vault/version_spec.rb
|
203
|
+
- spec/spec_helper.rb
|
204
|
+
homepage: https://github.com/MikeAScott/azure-key-vault
|
205
|
+
licenses:
|
206
|
+
- MIT
|
207
|
+
metadata: {}
|
208
|
+
post_install_message:
|
209
|
+
rdoc_options: []
|
210
|
+
require_paths:
|
211
|
+
- lib
|
212
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
213
|
+
requirements:
|
214
|
+
- - ">="
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
version: '0'
|
217
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
requirements: []
|
223
|
+
rubyforge_project:
|
224
|
+
rubygems_version: 2.7.6
|
225
|
+
signing_key:
|
226
|
+
specification_version: 4
|
227
|
+
summary: Ruby Client for Azure Key Vault
|
228
|
+
test_files: []
|