conjur-api 4.19.1 → 4.20.0

Sign up to get free protection for your applications and to get access to all the features.
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