conjur-api 4.19.1 → 4.20.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 901ca102477411588107366adff9780e60eca7c2
4
- data.tar.gz: 710a9dc4be2dce8bb3f7130ade8120563ee61e19
3
+ metadata.gz: ebb00e2f94e68846848adb5a2cd1ab57ac5fc1a6
4
+ data.tar.gz: 56489be115c5c8204ab84fd2985e6041384af5be
5
5
  SHA512:
6
- metadata.gz: ad298e7f945003d44306c6b9eb8b90a072ccde560735b8a092b1581a7847a3efcecc37f4d16f33f272a2b8b5d5d0c655fe767e7ddcd67b643616ca7767519cc2
7
- data.tar.gz: 582dec6a6727e502be95af2b7024944e9ad9c260dc465710400d6e600af59a644b5df030264449b685831e064a7371a503cc11e2301ae4605c1f376cbd309427
6
+ metadata.gz: e03d90f9779f73f2fcdb366f72b5f23266072121a69e03c480be29796822e5048fb580fddb56a9b57c44c0a7084cd60de22b21f185f8e4c881aa1e1c678c05fd
7
+ data.tar.gz: 40b2f4d6c81f5c38a97917526e8dd8fd6176fb53d1bf53deaddd902ac59d264dafdb8c30449c3f95c397964cef18ba722ca897685b025132702b35010303d10d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # v4.20.0
2
+
3
+ * Add support for Host Factory functionality (replaces conjur-asset-host-factory plugin).
4
+ * Add support for sending audit events (replaces conjur-asset-audit-send plugin).
5
+ * Add support for variable expiration. Variable expiration is available in version 4.6 of the Conjur server.
6
+ * Add `Conjur::API` methods to querying service versions : `service_version`, `service_names`, `appliance_info`.
7
+ * Add `Conjur::API` method for querying server health: `appliance_health(remote_host=nil)`
8
+ * Support ISO8601 duration strings as arguments in variable expiration methods.
9
+ * Add support for CIDR restrictions
10
+
1
11
  # v4.19.1
2
12
 
3
13
  * BUGFIX: Allow Configuration to parse several certs in a string
data/Dockerfile ADDED
@@ -0,0 +1,4 @@
1
+ FROM ruby:1.9.3
2
+
3
+ RUN mkdir /src
4
+ WORKDIR /src
data/Gemfile CHANGED
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ #ruby=ruby-2.1.5
3
4
  #ruby-gemset=conjur-api
4
5
 
5
6
  # Specify your gem's dependencies in conjur-api.gemspec
data/conjur-api.gemspec CHANGED
@@ -21,10 +21,12 @@ Gem::Specification.new do |gem|
21
21
 
22
22
  gem.add_dependency 'rest-client', '~> 1.7', '>= 1.7.3'
23
23
  gem.add_dependency 'activesupport'
24
+ gem.add_dependency 'semantic'
24
25
 
25
26
  gem.add_development_dependency 'rake'
26
27
  gem.add_development_dependency 'spork'
27
28
  gem.add_development_dependency 'rspec', '~> 3'
29
+ gem.add_development_dependency 'rspec-expectations', '~> 3.4'
28
30
  gem.add_development_dependency 'webmock'
29
31
  gem.add_development_dependency 'ci_reporter_rspec'
30
32
  gem.add_development_dependency 'simplecov'
@@ -33,5 +35,6 @@ Gem::Specification.new do |gem|
33
35
  gem.add_development_dependency 'yard'
34
36
  gem.add_development_dependency 'redcarpet'
35
37
  gem.add_development_dependency 'timecop'
38
+ gem.add_development_dependency 'tins', '~> 1.6', '< 1.7.0'
36
39
  gem.add_development_dependency 'inch'
37
40
  end
data/jenkins.sh ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/bash -e
2
+
3
+ docker build -t api-ruby .
4
+
5
+ docker run --rm \
6
+ -v $PWD:/src \
7
+ api-ruby \
8
+ bash -c '''
9
+ bundle
10
+ bundle exec rake jenkins
11
+ '''
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013-2015 Conjur Inc.
1
+ # Copyright (C) 2013-2016 Conjur Inc.
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  # this software and associated documentation files (the "Software"), to deal in
@@ -19,6 +19,6 @@
19
19
 
20
20
  module Conjur
21
21
  class API
22
- VERSION = "4.19.1"
22
+ VERSION = "4.20.0"
23
23
  end
24
24
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013 Conjur Inc
2
+ # Copyright (C) 2013-2015 Conjur Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
5
  # this software and associated documentation files (the "Software"), to deal in
@@ -43,5 +43,32 @@ module Conjur
43
43
  def api
44
44
  Conjur::API.new_from_key login, api_key
45
45
  end
46
+
47
+ # Rotate this user's API key. You must have `update` permission on the user to do so.
48
+ #
49
+ # @note You will not be able to access the API key returned by this method later, so you should
50
+ # probably hang onto it it.
51
+ #
52
+ # @note You cannot rotate your own API key with this method. To do so, use `Conjur::API.rotate_api_key`
53
+ #
54
+ # @note This feature requires a Conjur appliance running version 4.6 or higher.
55
+ #
56
+ # @return [String] the new API key for this user.
57
+ def rotate_api_key
58
+ path = "users/api_key?id=#{fully_escape login}"
59
+ RestClient::Resource.new(Conjur::Authn::API.host, options)[path].put('').body
60
+ end
61
+
62
+ # Set login network restrictions for the user.
63
+ #
64
+ # @param [Array<String, IPAddr>] networks which allow logging in. Set to empty to remove restrictions
65
+ def set_cidr_restrictions networks
66
+ authn_user = RestClient::Resource.new(Conjur::Authn::API.host, options)\
67
+ ["users?id=#{fully_escape login}"]
68
+
69
+ # we need use JSON here to be able to PUT an empty array
70
+ params = { cidr: [*networks].map(&CIDR.method(:validate)).map(&:to_s) }
71
+ authn_user.put params.to_json, content_type: :json
72
+ end
46
73
  end
47
74
  end
data/lib/conjur/api.rb CHANGED
@@ -25,6 +25,7 @@ require 'conjur/cast'
25
25
  require 'conjur/configuration'
26
26
  require 'conjur/env'
27
27
  require 'conjur/base'
28
+ require 'conjur/exceptions'
28
29
  require 'conjur/build_from_response'
29
30
  require 'conjur/acts_as_resource'
30
31
  require 'conjur/acts_as_role'
@@ -40,7 +41,9 @@ require 'conjur/audit-api'
40
41
  require 'conjur/core-api'
41
42
  require 'conjur/layer-api'
42
43
  require 'conjur/pubkeys-api'
44
+ require 'conjur/host-factory-api'
43
45
  require 'conjur-api/version'
46
+ require 'conjur/api/info'
44
47
 
45
48
  # Monkey patch RestClient::Request so it always uses
46
49
  # :ssl_cert_store. (RestClient::Resource uses Request to send
@@ -82,6 +82,19 @@ module Conjur
82
82
  audit_event_feed "resources/#{CGI.escape cast(resource, :resourceid)}", options, &block
83
83
  end
84
84
 
85
+ # Send custom audit event
86
+ # @param input [String|Hash|Array] event or array of events (optionally serialized to JSON)
87
+ def audit_send input
88
+ json = if input.kind_of? String
89
+ input
90
+ elsif input.kind_of? Array or input.kind_of? Hash
91
+ input.to_json
92
+ else
93
+ raise ArgumentError, "Parameter should be either String, Hash or Array"
94
+ end
95
+ rest_api = RestClient::Resource.new(Conjur::Authz::API.host, credentials)["audit"]
96
+ rest_api.post json, content_type: "text/plain"
97
+ end
85
98
  #@!endgroup
86
99
 
87
100
  private
@@ -120,4 +133,4 @@ module Conjur
120
133
  JSON.parse response
121
134
  end
122
135
  end
123
- end
136
+ end
@@ -86,6 +86,7 @@ module Conjur
86
86
  JSON::parse(RestClient::Resource.new(Conjur::Authn::API.host)["users/#{fully_escape username}/authenticate"].post password, content_type: 'text/plain')
87
87
  end
88
88
 
89
+
89
90
  # Change a user's password. To do this, you must have the user's current password. This does not change or rotate
90
91
  # api keys. However, you *can* use the user's api key as the *current* password, if the user was not created
91
92
  # with a password.
@@ -102,6 +103,34 @@ module Conjur
102
103
  end
103
104
 
104
105
  #@!endgroup
106
+
107
+ #@!group Password and API key management
108
+
109
+ # Rotate the currently authenticated user's API key by generating and returning a new one.
110
+ # The old API key is no longer valid after calling this method. You must have the user's current
111
+ # API key or password to perform this operation. This method *does not* affect the user's password.
112
+ #
113
+ # @note If the user does not have a password, the returned API key will be the **only** way to authenticate as
114
+ # the user. Therefore, you'd best save it.
115
+ #
116
+ # @note This feature requires version 4.6 of the Conjur appliance.
117
+ #
118
+ # @param [String] username the name of the user whose password we want to change
119
+ # @param [String] password the user's current password *or* api key
120
+ # @return [String] the new API key for the user
121
+ def rotate_api_key username, password
122
+ if Conjur.log
123
+ Conjur.log << "Rotating API key for self (#{username})\n"
124
+ end
125
+
126
+ RestClient::Resource.new(
127
+ Conjur::Authn::API.host,
128
+ user: username,
129
+ password: password
130
+ )['users/api_key'].put('').body
131
+ end
132
+
133
+ #@!endgroup
105
134
  end
106
135
 
107
136
  # @api private
@@ -0,0 +1,93 @@
1
+ #
2
+ # Copyright (C) 2014 Conjur Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'conjur/host_factory'
22
+
23
+ module Conjur
24
+ class API
25
+ class << self
26
+ # Creates a host and returns the response Hash.
27
+ def host_factory_create_host token, id, options = {}
28
+ token = token.token if token.is_a?(HostFactoryToken)
29
+ http_options = {
30
+ headers: { authorization: %Q(Token token="#{token}") }
31
+ }
32
+ response = RestClient::Resource.new(Conjur::API.host_factory_asset_host, http_options)["hosts"].post(options.merge(id: id)).body
33
+ JSON.parse(response)
34
+ end
35
+ end
36
+
37
+ # Options:
38
+ # +layers+ list of host factory layers
39
+ # +roleid+ host factory role id
40
+ # +role+ host factory role. If this is provided, it is converted to roleid.
41
+ def create_host_factory(id, options = {})
42
+ if options[:layers]
43
+ options[:layers] = options[:layers].map do |layer|
44
+ if layer.is_a?(Conjur::Layer)
45
+ layer.id
46
+ elsif layer.is_a?(String)
47
+ layer
48
+ else
49
+ raise "Can't interpret layer #{layer}"
50
+ end
51
+ end
52
+ end
53
+ if role = options.delete(:role)
54
+ options[:roleid] = role.roleid
55
+ end
56
+ log do |logger|
57
+ logger << "Creating host_factory #{id}"
58
+ unless options.blank?
59
+ logger << " with options #{options.inspect}"
60
+ end
61
+ end
62
+ options ||= {}
63
+ options[:id] = id
64
+ resp = RestClient::Resource.new(Conjur::API.host_factory_asset_host, credentials).post(options)
65
+ Conjur::HostFactory.build_from_response(resp, credentials)
66
+ end
67
+
68
+ def host_factory id
69
+ Conjur::HostFactory.new(Conjur::API.host_factory_asset_host, credentials)[fully_escape(id)]
70
+ end
71
+
72
+ def revoke_host_factory_token token
73
+ token = token.token if token.is_a?(Conjur::HostFactoryToken)
74
+ RestClient::Resource.new(Conjur::API.host_factory_asset_host, credentials)["tokens/#{token}"].delete
75
+ end
76
+
77
+ def show_host_factory_token token
78
+ token = token.token if token.is_a?(Conjur::HostFactoryToken)
79
+ attrs = JSON.parse(RestClient::Resource.new(Conjur::API.host_factory_asset_host, credentials)["tokens/#{token}"].get.body)
80
+ Conjur::HostFactoryToken.new(Conjur::API.host_factory_asset_host, credentials)["tokens"][attrs['token']].tap do |token|
81
+ token.attributes = attrs
82
+ end
83
+ end
84
+
85
+ # Creates a Host and returns a Host object.
86
+ def host_factory_create_host token, id, options = {}
87
+ attributes = self.class.host_factory_create_host token, id, options
88
+ Conjur::Host.new(Conjur::API.core_asset_host, credentials)["hosts"][fully_escape attributes['id']].tap do |host|
89
+ host.attributes = attributes
90
+ end
91
+ end
92
+ end
93
+ end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2013 Conjur Inc
2
+ # Copyright (C) 2013-2015 Conjur Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
5
  # this software and associated documentation files (the "Software"), to deal in
@@ -78,6 +78,8 @@ module Conjur
78
78
  # a member of the owner role.
79
79
  #
80
80
  def create_host options = nil
81
+ options = options.merge \
82
+ cidr: [*options[:cidr]].map(&CIDR.method(:validate)).map(&:to_s) if options[:cidr]
81
83
  standard_create Conjur::Core::API.host, :host, nil, options
82
84
  end
83
85
 
@@ -104,4 +106,4 @@ module Conjur
104
106
 
105
107
  #@!endgroup
106
108
  end
107
- end
109
+ end
@@ -0,0 +1,126 @@
1
+ # Copyright (C) 2013-2016 Conjur Inc.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ # this software and associated documentation files (the "Software"), to deal in
5
+ # the Software without restriction, including without limitation the rights to
6
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ # the Software, and to permit persons to whom the Software is furnished to do so,
8
+ # subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
+ #
20
+ require 'semantic'
21
+ require 'semantic/core_ext'
22
+ module Conjur
23
+ class API
24
+ class << self
25
+
26
+ # Return the version of the given service presently running on the Conjur appliance.
27
+ #
28
+ # @example Check that the authn service is at least version 4.6
29
+ # if api.service_version('authn') >= '4.6.0'.to_version
30
+ # puts "Authn version is at least 4.6.0"
31
+ # end
32
+ #
33
+ # This feature is useful for determining whether the Conjur appliance has a particular feature.
34
+ #
35
+ # If the given service does not exist, this method will raise an exception. To retrieve a list of
36
+ # valid service names, you can use `Conjur::API.service_names`
37
+ #
38
+ # @param [String] service the name of the service.
39
+ # @return [Semantic::Version] the version of the service.
40
+ def service_version service
41
+ if (service_info = appliance_info['services'][service]).nil?
42
+ raise "Unknown service #{service} (services are #{service_names.join(', ')}."
43
+ else
44
+ # Pre-release versions are discarded, because they make testing harder:
45
+ # 2.0.0-p598 :004 > Semantic::Version.new("4.5.0") <= Semantic::Version.new("4.5.0-1")
46
+ # => false
47
+ major, minor, patch, pre = service_info['version'].split(/[.-]/)[0..3]
48
+ Semantic::Version.new "#{major}.#{minor}.#{patch}"
49
+ end
50
+ end
51
+
52
+ # Return an Array of valid service names for your appliance.
53
+ #
54
+ # @return [Array<String>] the names of services on the appliance.
55
+ def service_names
56
+ appliance_info['services'].keys
57
+ end
58
+
59
+ # Return a Hash containing various information about the Conjur appliance.
60
+ #
61
+ # If the appliance does not support this feature, raise Conjur::FeatureNotAvailable.
62
+ #
63
+ # @note This feature requires Conjur appliance version 4.6 or above.
64
+ #
65
+ # @return [Hash] various information about the Conjur appliance.
66
+ def appliance_info
67
+ JSON.parse(RestClient::Resource.new(appliance_info_url).get.body)
68
+ rescue RestClient::ResourceNotFound
69
+ raise Conjur::FeatureNotAvailable.new('Your appliance does not support the /info URL needed by Conjur::API.appliance_info (you need 4.6 or later)')
70
+ end
71
+
72
+ # Return a Hash containing health information for this appliance, or for another host.
73
+ #
74
+ # If the `remote_host` argument is provided, the health of that appliance is reported from
75
+ # the perspective of the appliance being queried (as specified by the `appliance_url` configuration
76
+ # variable).
77
+ #
78
+ # @note When called without an argument, this method requires a Conjur server running version 4.5 or later.
79
+ # When called with an argument, it requires 4.6 or later.
80
+ #
81
+ # @param [String, NilClass] remote_host a hostname for a remote host
82
+ # @return [Hash] the appliance health information.
83
+ def appliance_health remote_host=nil
84
+ remote_host.nil? ? own_health : remote_health(remote_host)
85
+ end
86
+
87
+ private
88
+
89
+
90
+ def remote_health host
91
+ JSON.parse(RestClient::Resource.new(remote_health_url(host)).get.body)
92
+ rescue RestClient::ResourceNotFound
93
+ raise Conjur::FeatureNotAvailable.new('Your appliance does not support the /remote_health/:host URL needed by Conjur::API.appliance_health (you need 4.6 or later)')
94
+ rescue RestClient::ExceptionWithResponse => ex
95
+ JSON.parse(ex.response.body)
96
+ end
97
+
98
+
99
+ def own_health
100
+ JSON.parse(RestClient::Resource.new(appliance_health_url).get.body)
101
+ rescue RestClient::ResourceNotFound
102
+ raise Conjur::FeatureNotAvailable.new('Your appliance does not support the /health URL needed by Conjur::API.appliance_health (you need 4.5 or later)')
103
+ rescue RestClient::ExceptionWithResponse => ex
104
+ JSON.parse(ex.response.body)
105
+ end
106
+
107
+ def remote_health_url host
108
+ raw_appliance_url "/remote_health/#{fully_escape host}"
109
+ end
110
+
111
+ def appliance_health_url
112
+ raw_appliance_url '/health'
113
+ end
114
+
115
+ def appliance_info_url
116
+ raw_appliance_url '/info'
117
+ end
118
+
119
+ def raw_appliance_url path
120
+ url = Conjur.configuration.appliance_url
121
+ raise "Conjur connection is not configured" unless url
122
+ url.gsub(%r{/api$}, path)
123
+ end
124
+ end
125
+ end
126
+ end