conjur-rack 1.4.0 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/Gemfile +7 -1
- data/conjur-rack.gemspec +7 -4
- data/jenkins.sh +12 -0
- data/lib/conjur/rack.rb +23 -0
- data/lib/conjur/rack/authenticator.rb +122 -51
- data/lib/conjur/rack/user.rb +71 -17
- data/lib/conjur/rack/version.rb +1 -1
- data/spec/rack/authenticator_spec.rb +155 -83
- data/spec/rack/path_prefix_spec.rb +3 -3
- data/spec/rack/user_spec.rb +115 -47
- data/spec/rack_spec.rb +49 -0
- data/spec/spec_helper.rb +36 -0
- metadata +47 -23
- data/.rvmrc +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ee85c177c59da73e229825170b3b8c34230e4e1
|
4
|
+
data.tar.gz: 7758e75373c0ccdfcb61539a33325795d5394600
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccec8cadd0827fbf5b298f57fa78aa32a7792a58d985c0ff54ee05b80c256e55c0a9c868a1432be4908d7314c9becefdcf812ed95aad28ec756e989ad250def2
|
7
|
+
data.tar.gz: 36e507e1714480f2c5e4f5ff9d3af63cca883f855fc2259e272c3ce45420dadc36e0cd64cbe926f6396d0d3793968f802df147950ac0db86c7b69bba3abd0b8d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
# v3.1.0
|
2
|
+
|
3
|
+
* Support for JWT Slosilo tokens.
|
4
|
+
|
5
|
+
# v3.0.0.pre
|
6
|
+
|
7
|
+
* Initial support for Conjur 5.
|
8
|
+
|
9
|
+
# v2.3.0
|
10
|
+
|
11
|
+
* Add TRUSTED_PROXIES support
|
12
|
+
|
13
|
+
# v2.2.0
|
14
|
+
|
15
|
+
* resolve 'own' token to CONJUR_ACCOUNT env var
|
16
|
+
* add #optional paths to Conjur::Rack authenticator
|
17
|
+
|
18
|
+
# v2.1.0
|
19
|
+
|
20
|
+
* Add handling for `Conjur-Audit-Roles` and `Conjur-Audit-Resources`
|
21
|
+
|
22
|
+
# v2.0.0
|
23
|
+
|
24
|
+
* Change `global_sudo?` to `global_elevate?`
|
25
|
+
|
1
26
|
# v1.4.0
|
2
27
|
|
3
28
|
* Add `validated_global_privilege` helper function to get the global privilege, if any, which has been submitted with the request and verified by the Conjur server.
|
data/Gemfile
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
+
# make sure github uses TLS
|
4
|
+
git_source(:github) { |name| "https://github.com/#{name}.git" }
|
5
|
+
|
6
|
+
#ruby=ruby-2.3.4
|
7
|
+
#ruby-gemset=conjur-rack
|
8
|
+
|
3
9
|
# Specify your gem's dependencies in conjur-rack.gemspec
|
4
10
|
gemspec
|
5
11
|
|
6
|
-
gem 'conjur-api', github: '
|
12
|
+
# gem 'conjur-api', github: 'cyberark/conjur-api-ruby', branch: 'master'
|
data/conjur-rack.gemspec
CHANGED
@@ -18,12 +18,15 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "slosilo"
|
22
|
-
spec.add_dependency "conjur-api", "
|
23
|
-
spec.add_dependency "rack"
|
21
|
+
spec.add_dependency "slosilo", "~> 2.1"
|
22
|
+
spec.add_dependency "conjur-api", "< 6"
|
23
|
+
spec.add_dependency "rack", '~> 1'
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.3"
|
26
26
|
spec.add_development_dependency "rake"
|
27
|
-
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
28
|
spec.add_development_dependency 'ci_reporter_rspec'
|
29
|
+
spec.add_development_dependency 'pry-byebug'
|
30
|
+
spec.add_development_dependency 'rspec-its'
|
31
|
+
|
29
32
|
end
|
data/jenkins.sh
ADDED
data/lib/conjur/rack.rb
CHANGED
@@ -1,3 +1,26 @@
|
|
1
1
|
require "conjur/rack/version"
|
2
2
|
require "conjur/rack/authenticator"
|
3
3
|
require "conjur/rack/path_prefix"
|
4
|
+
require 'ipaddr'
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
module TrustedProxies
|
8
|
+
|
9
|
+
def trusted_proxy?(ip)
|
10
|
+
trusted_proxies ? trusted_proxies.any? { |cidr| cidr.include?(ip) } : super
|
11
|
+
end
|
12
|
+
|
13
|
+
def trusted_proxies
|
14
|
+
@trusted_proxies || ENV['TRUSTED_PROXIES'].try do |proxies|
|
15
|
+
cidrs = Set.new(proxies.split(',') + ['127.0.0.1'])
|
16
|
+
@trusted_proxies = cidrs.collect {|cidr| IPAddr.new(cidr) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
module Rack
|
23
|
+
class Request
|
24
|
+
prepend TrustedProxies
|
25
|
+
end
|
26
|
+
end
|
@@ -2,36 +2,51 @@ require "conjur/rack/user"
|
|
2
2
|
|
3
3
|
module Conjur
|
4
4
|
module Rack
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def conjur_rack
|
8
|
+
Thread.current[:conjur_rack] ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def identity?
|
12
|
+
!conjur_rack[:identity].nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def user
|
16
|
+
User.new(identity[0], identity[1],
|
17
|
+
:privilege => privilege,
|
18
|
+
:remote_ip => remote_ip,
|
19
|
+
:audit_roles => audit_roles,
|
20
|
+
:audit_resources => audit_resources
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def identity
|
25
|
+
conjur_rack[:identity] or raise "No Conjur identity for current request"
|
26
|
+
end
|
27
|
+
|
28
|
+
# class attributes
|
29
|
+
[:privilege, :remote_ip, :audit_roles, :audit_resources].each do |a|
|
30
|
+
define_method(a) do
|
31
|
+
conjur_rack[a]
|
32
|
+
end
|
33
|
+
end
|
23
34
|
end
|
35
|
+
|
24
36
|
|
25
37
|
class Authenticator
|
26
38
|
class AuthorizationError < SecurityError
|
27
39
|
end
|
28
40
|
class SignatureError < SecurityError
|
29
41
|
end
|
42
|
+
class Forbidden < SecurityError
|
43
|
+
end
|
30
44
|
|
31
45
|
attr_reader :app, :options
|
32
46
|
|
33
47
|
# +options+:
|
34
|
-
# :except :: a list of request path patterns for which to skip authentication
|
48
|
+
# :except :: a list of request path patterns for which to skip authentication.
|
49
|
+
# :optional :: request path patterns for which authentication is optional.
|
35
50
|
def initialize app, options = {}
|
36
51
|
@app = app
|
37
52
|
@options = options
|
@@ -39,10 +54,13 @@ module Conjur
|
|
39
54
|
|
40
55
|
# threadsafe accessors, values are established explicitly below
|
41
56
|
def env; Thread.current[:rack_env] ; end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
57
|
+
|
58
|
+
# instance attributes
|
59
|
+
[:token, :account, :privilege, :remote_ip, :audit_roles, :audit_resources].each do |a|
|
60
|
+
define_method(a) do
|
61
|
+
conjur_rack[a]
|
62
|
+
end
|
63
|
+
end
|
46
64
|
|
47
65
|
def call rackenv
|
48
66
|
# never store request-specific variables as application attributes
|
@@ -50,13 +68,19 @@ module Conjur
|
|
50
68
|
if authenticate?
|
51
69
|
begin
|
52
70
|
identity = verify_authorization_and_get_identity # [token, account]
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
71
|
+
|
72
|
+
if identity
|
73
|
+
conjur_rack[:token] = identity[0]
|
74
|
+
conjur_rack[:account] = identity[1]
|
75
|
+
conjur_rack[:identity] = identity
|
76
|
+
conjur_rack[:privilege] = http_privilege
|
77
|
+
conjur_rack[:remote_ip] = http_remote_ip
|
78
|
+
conjur_rack[:audit_roles] = http_audit_roles
|
79
|
+
conjur_rack[:audit_resources] = http_audit_resources
|
80
|
+
end
|
59
81
|
|
82
|
+
rescue Forbidden
|
83
|
+
return error 403, $!.message
|
60
84
|
rescue SecurityError, RestClient::Exception
|
61
85
|
return error 401, $!.message
|
62
86
|
end
|
@@ -65,61 +89,108 @@ module Conjur
|
|
65
89
|
@app.call rackenv
|
66
90
|
ensure
|
67
91
|
Thread.current[:rack_env] = nil
|
68
|
-
Thread.current[:
|
69
|
-
Thread.current[:conjur_rack_token] = nil
|
70
|
-
Thread.current[:conjur_rack_account] = nil
|
71
|
-
Thread.current[:conjur_rack_privilege] = nil
|
72
|
-
Thread.current[:conjur_rack_remote_ip] = nil
|
92
|
+
Thread.current[:conjur_rack] = {}
|
73
93
|
end
|
74
94
|
end
|
75
95
|
|
76
96
|
protected
|
77
97
|
|
98
|
+
def conjur_rack
|
99
|
+
Conjur::Rack.conjur_rack
|
100
|
+
end
|
101
|
+
|
78
102
|
def validate_token_and_get_account token
|
79
|
-
failure = SignatureError.new("
|
103
|
+
failure = SignatureError.new("Unauthorized: Invalid token")
|
80
104
|
raise failure unless (signer = Slosilo.token_signer token)
|
81
|
-
|
82
|
-
|
105
|
+
if signer == 'own'
|
106
|
+
ENV['CONJUR_ACCOUNT'] or raise failure
|
107
|
+
else
|
108
|
+
raise failure unless signer =~ /\Aauthn:(.+)\z/
|
109
|
+
$1
|
110
|
+
end
|
83
111
|
end
|
84
112
|
|
85
113
|
def error status, message
|
86
114
|
[status, { 'Content-Type' => 'text/plain', 'Content-Length' => message.length.to_s }, [message] ]
|
87
115
|
end
|
116
|
+
|
117
|
+
def parsed_token
|
118
|
+
token = http_authorization.to_s[/^Token token="(.*)"/, 1]
|
119
|
+
token = token && JSON.parse(Base64.decode64(token))
|
120
|
+
token = Slosilo::JWT token rescue token
|
121
|
+
rescue JSON::ParserError
|
122
|
+
raise AuthorizationError.new("Malformed authorization token")
|
123
|
+
end
|
88
124
|
|
125
|
+
RECOGNIZED_CLAIMS = [
|
126
|
+
'iat', 'exp', # recognized by Slosilo
|
127
|
+
'cidr', 'sub',
|
128
|
+
'iss', 'aud', 'jti' # RFC 7519, not handled but recognized
|
129
|
+
].freeze
|
130
|
+
|
89
131
|
def verify_authorization_and_get_identity
|
90
|
-
if
|
91
|
-
|
92
|
-
|
93
|
-
|
132
|
+
if token = parsed_token
|
133
|
+
begin
|
134
|
+
account = validate_token_and_get_account token
|
135
|
+
if token.respond_to?(:claims)
|
136
|
+
claims = token.claims
|
137
|
+
raise AuthorizationError, "token contains unrecognized claims" unless \
|
138
|
+
(claims.keys.map(&:to_s) - RECOGNIZED_CLAIMS).empty?
|
139
|
+
if (cidr = claims['cidr'])
|
140
|
+
raise Forbidden, "IP address rejected" unless \
|
141
|
+
cidr.map(&IPAddr.method(:new)).any? { |c| c.include? http_remote_ip }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
return [token, account]
|
145
|
+
end
|
94
146
|
else
|
95
|
-
|
147
|
+
path = http_path
|
148
|
+
if optional_paths.find{|p| p.match(path)}.nil?
|
149
|
+
raise AuthorizationError.new("Authorization missing")
|
150
|
+
else
|
151
|
+
nil
|
152
|
+
end
|
96
153
|
end
|
97
154
|
end
|
98
155
|
|
99
156
|
def authenticate?
|
157
|
+
path = http_path
|
100
158
|
if options[:except]
|
101
159
|
options[:except].find{|p| p.match(path)}.nil?
|
102
160
|
else
|
103
161
|
true
|
104
162
|
end
|
105
163
|
end
|
106
|
-
|
107
|
-
def conjur_privilege
|
108
|
-
env['HTTP_X_CONJUR_PRIVILEGE']
|
109
|
-
end
|
110
164
|
|
111
|
-
def
|
165
|
+
def optional_paths
|
166
|
+
options[:optional] || []
|
167
|
+
end
|
168
|
+
|
169
|
+
def http_authorization
|
112
170
|
env['HTTP_AUTHORIZATION']
|
113
171
|
end
|
114
|
-
|
115
|
-
def
|
172
|
+
|
173
|
+
def http_privilege
|
174
|
+
env['HTTP_X_CONJUR_PRIVILEGE']
|
175
|
+
end
|
176
|
+
|
177
|
+
def http_remote_ip
|
116
178
|
require 'rack/request'
|
117
179
|
::Rack::Request.new(env).ip
|
118
180
|
end
|
119
|
-
|
120
|
-
def
|
181
|
+
|
182
|
+
def http_audit_roles
|
183
|
+
env['HTTP_CONJUR_AUDIT_ROLES']
|
184
|
+
end
|
185
|
+
|
186
|
+
def http_audit_resources
|
187
|
+
env['HTTP_CONJUR_AUDIT_RESOURCES']
|
188
|
+
end
|
189
|
+
|
190
|
+
def http_path
|
121
191
|
[ env['SCRIPT_NAME'], env['PATH_INFO'] ].join
|
122
192
|
end
|
193
|
+
|
123
194
|
end
|
124
195
|
end
|
125
196
|
end
|
data/lib/conjur/rack/user.rb
CHANGED
@@ -2,25 +2,32 @@ require 'conjur/api'
|
|
2
2
|
|
3
3
|
module Conjur
|
4
4
|
module Rack
|
5
|
+
# Token data can be a string (which is the user login), or a Hash.
|
6
|
+
# If it's a hash, it should contain the user login keyed by the string 'login'.
|
7
|
+
# The rest of the payload is available as +attributes+.
|
5
8
|
class User
|
6
|
-
|
9
|
+
attr_reader :token, :account, :privilege, :remote_ip, :audit_roles, :audit_resources
|
7
10
|
|
8
|
-
def initialize(token, account,
|
11
|
+
def initialize(token, account, options = {})
|
9
12
|
@token = token
|
10
13
|
@account = account
|
11
|
-
|
12
|
-
|
14
|
+
# Third argument used to be the name of privilege, be
|
15
|
+
# backwards compatible:
|
16
|
+
if options.respond_to?(:to_str)
|
17
|
+
@privilege = options
|
18
|
+
else
|
19
|
+
@privilege = options[:privilege]
|
20
|
+
@remote_ip = options[:remote_ip]
|
21
|
+
@audit_roles = options[:audit_roles]
|
22
|
+
@audit_resources = options[:audit_resources]
|
23
|
+
end
|
13
24
|
end
|
14
25
|
|
15
26
|
# This file was accidently calling account conjur_account,
|
16
27
|
# I'm adding an alias in case that's going on anywhere else.
|
17
28
|
# -- Jon
|
18
29
|
alias :conjur_account :account
|
19
|
-
alias :conjur_account= :account=
|
20
|
-
|
21
|
-
def new_association(cls, params = {})
|
22
|
-
cls.new params.merge({userid: login})
|
23
|
-
end
|
30
|
+
# alias :conjur_account= :account=
|
24
31
|
|
25
32
|
# Returns the global privilege which was present on the request, if and only
|
26
33
|
# if the user actually has that privilege.
|
@@ -41,13 +48,21 @@ module Conjur
|
|
41
48
|
validated_global_privilege == "reveal"
|
42
49
|
end
|
43
50
|
|
44
|
-
# True if and only if the user has valid global '
|
45
|
-
def
|
46
|
-
validated_global_privilege == "
|
51
|
+
# True if and only if the user has valid global 'elevate' privilege.
|
52
|
+
def global_elevate?
|
53
|
+
validated_global_privilege == "elevate"
|
47
54
|
end
|
48
55
|
|
49
56
|
def login
|
50
|
-
|
57
|
+
parse_token
|
58
|
+
|
59
|
+
@login
|
60
|
+
end
|
61
|
+
|
62
|
+
def attributes
|
63
|
+
parse_token
|
64
|
+
|
65
|
+
@attributes || {}
|
51
66
|
end
|
52
67
|
|
53
68
|
def roleid
|
@@ -63,17 +78,56 @@ module Conjur
|
|
63
78
|
def role
|
64
79
|
api.role(roleid)
|
65
80
|
end
|
66
|
-
|
81
|
+
|
82
|
+
def audit_resources
|
83
|
+
Conjur::API.decode_audit_ids(@audit_resources) if @audit_resources
|
84
|
+
end
|
85
|
+
|
86
|
+
def audit_roles
|
87
|
+
Conjur::API.decode_audit_ids(@audit_roles) if @audit_roles
|
88
|
+
end
|
89
|
+
|
67
90
|
def api(cls = Conjur::API)
|
68
91
|
args = [ token ]
|
69
92
|
args.push remote_ip if remote_ip
|
70
93
|
api = cls.new_from_token(*args)
|
71
|
-
if privilege
|
72
|
-
|
94
|
+
api = api.with_privilege(privilege) if privilege
|
95
|
+
api = api.with_audit_resources(audit_resources) if audit_resources
|
96
|
+
api = api.with_audit_roles(audit_roles) if audit_roles
|
97
|
+
|
98
|
+
api
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def parse_token
|
104
|
+
return if @login
|
105
|
+
|
106
|
+
@token = Slosilo::JWT token
|
107
|
+
load_jwt token
|
108
|
+
rescue ArgumentError
|
109
|
+
if data = token['data']
|
110
|
+
return load_legacy data
|
73
111
|
else
|
74
|
-
|
112
|
+
raise "malformed token"
|
75
113
|
end
|
76
114
|
end
|
115
|
+
|
116
|
+
def load_legacy data
|
117
|
+
if data.is_a?(String)
|
118
|
+
@login = token['data']
|
119
|
+
elsif data.is_a?(Hash)
|
120
|
+
@attributes = token['data'].clone
|
121
|
+
@login = @attributes.delete('login') or raise "No 'login' field in token data"
|
122
|
+
else
|
123
|
+
raise "Expecting String or Hash token data, got #{data.class.name}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def load_jwt jwt
|
128
|
+
@attributes = jwt.claims.merge (jwt.header || {}) # just pass all the info
|
129
|
+
@login = jwt.claims['sub'] or raise "No 'sub' field in claims"
|
130
|
+
end
|
77
131
|
end
|
78
132
|
end
|
79
133
|
end
|
data/lib/conjur/rack/version.rb
CHANGED
@@ -3,107 +3,179 @@ require 'spec_helper'
|
|
3
3
|
require 'conjur/rack/authenticator'
|
4
4
|
|
5
5
|
describe Conjur::Rack::Authenticator do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
{
|
16
|
-
'HTTP_AUTHORIZATION' => "Token token=\"#{basic_64}\""
|
17
|
-
}.tap do |e|
|
18
|
-
e['HTTP_X_CONJUR_PRIVILEGE'] = privilege if privilege
|
19
|
-
e['HTTP_X_FORWARDED_FOR'] = remote_ip if remote_ip
|
20
|
-
end
|
6
|
+
include_context "with authenticator"
|
7
|
+
|
8
|
+
describe "#call" do
|
9
|
+
context "to an unprotected path" do
|
10
|
+
let(:except) { [ /^\/foo/ ] }
|
11
|
+
let(:env) { { 'SCRIPT_NAME' => '', 'PATH_INFO' => '/foo/bar' } }
|
12
|
+
before {
|
13
|
+
options[:except] = except
|
14
|
+
expect(app).to receive(:call).with(env).and_return app
|
21
15
|
}
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
context "
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
it 'launches app' do
|
35
|
-
app.should_receive(:call).with(env).and_return app
|
36
|
-
call.should == app
|
16
|
+
context "without authorization" do
|
17
|
+
it "proceeds" do
|
18
|
+
expect(call).to eq(app)
|
19
|
+
expect(Conjur::Rack.identity?).to be(false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
context "with authorization" do
|
23
|
+
include_context "with authorization"
|
24
|
+
it "ignores the authorization" do
|
25
|
+
expect(call).to eq(app)
|
26
|
+
expect(Conjur::Rack.identity?).to be(false)
|
37
27
|
end
|
28
|
+
end
|
29
|
+
end
|
38
30
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
it_should_behave_like 'returns User built from token'
|
31
|
+
context "to a protected path" do
|
32
|
+
let(:env) { { 'SCRIPT_NAME' => '/pathname' } }
|
33
|
+
context "without authorization" do
|
34
|
+
it "returns a 401 error" do
|
35
|
+
expect(call).to return_http 401, "Authorization missing"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
context "with Conjur authorization" do
|
39
|
+
include_context "with authorization"
|
40
|
+
|
41
|
+
context "with CIDR restriction" do
|
42
|
+
let(:claims) { { 'sub' => 'test-user', 'cidr' => %w(192.168.2.0/24 2001:db8::/32) } }
|
43
|
+
let(:token) { Slosilo::JWT.new(claims) }
|
44
|
+
before do
|
45
|
+
allow(subject).to receive_messages \
|
46
|
+
parsed_token: token,
|
47
|
+
http_remote_ip: remote_ip
|
48
|
+
end
|
49
|
+
|
50
|
+
%w(10.0.0.2 fdda:5cc1:23:4::1f).each do |addr|
|
51
|
+
context "with address #{addr} out of range" do
|
52
|
+
let(:remote_ip) { addr }
|
53
|
+
it "returns 403" do
|
54
|
+
expect(call).to return_http 403, "IP address rejected"
|
55
|
+
end
|
65
56
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
57
|
+
end
|
58
|
+
|
59
|
+
%w(192.168.2.3 2001:db8::22).each do |addr|
|
60
|
+
context "with address #{addr} in range" do
|
61
|
+
let(:remote_ip) { addr }
|
62
|
+
it "passes the request" do
|
63
|
+
expect(call.login).to eq 'test-user'
|
64
|
+
end
|
70
65
|
end
|
71
66
|
end
|
67
|
+
end
|
72
68
|
|
73
|
-
|
74
|
-
|
69
|
+
context "of a valid token" do
|
70
|
+
it 'launches app' do
|
71
|
+
expect(app).to receive(:call).with(env).and_return app
|
72
|
+
expect(call).to eq(app)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
context "of an invalid token" do
|
76
|
+
it "returns a 401 error" do
|
77
|
+
allow(Slosilo).to receive(:token_signer).and_return(nil)
|
78
|
+
expect(call).to return_http 401, "Unauthorized: Invalid token"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
context "of a token invalid for authn" do
|
82
|
+
it "returns a 401 error" do
|
83
|
+
allow(Slosilo).to receive(:token_signer).and_return('a-totally-different-key')
|
84
|
+
expect(call).to return_http 401, "Unauthorized: Invalid token"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
context "of 'own' token" do
|
88
|
+
it "returns ENV['CONJUR_ACCOUNT']" do
|
89
|
+
expect(ENV).to receive(:[]).with("CONJUR_ACCOUNT").and_return("test-account")
|
90
|
+
expect(app).to receive(:call) do |*args|
|
91
|
+
expect(Conjur::Rack.identity?).to be(true)
|
92
|
+
expect(Conjur::Rack.user.account).to eq('test-account')
|
93
|
+
:done
|
94
|
+
end
|
95
|
+
allow(Slosilo).to receive(:token_signer).and_return('own')
|
96
|
+
expect(call).to eq(:done)
|
97
|
+
end
|
98
|
+
it "requires ENV['CONJUR_ACCOUNT']" do
|
99
|
+
expect(ENV).to receive(:[]).with("CONJUR_ACCOUNT").and_return(nil)
|
100
|
+
allow(Slosilo).to receive(:token_signer).and_return('own')
|
101
|
+
expect(call).to return_http 401, "Unauthorized: Invalid token"
|
75
102
|
end
|
76
103
|
end
|
77
104
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
105
|
+
|
106
|
+
context "with junk in token" do
|
107
|
+
let(:env) { { 'HTTP_AUTHORIZATION' => 'Token token="open sesame"' } }
|
108
|
+
it "returns 401" do
|
109
|
+
expect(call).to return_http 401, "Malformed authorization token"
|
82
110
|
end
|
83
111
|
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
112
|
+
|
113
|
+
context "with JSON junk in token" do
|
114
|
+
let(:env) { { 'HTTP_AUTHORIZATION' => 'Token token="eyJmb28iOiAiYmFyIn0="' } }
|
115
|
+
before do
|
116
|
+
allow(Slosilo).to receive(:token_signer).and_return(nil)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns 401" do
|
120
|
+
expect(call).to return_http 401, "Unauthorized: Invalid token"
|
88
121
|
end
|
89
122
|
end
|
90
123
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
124
|
+
context "to an optional path" do
|
125
|
+
let(:optional) { [ /^\/foo/ ] }
|
126
|
+
let(:env) { { 'SCRIPT_NAME' => '', 'PATH_INFO' => '/foo/bar' } }
|
127
|
+
before {
|
128
|
+
options[:optional] = optional
|
129
|
+
}
|
130
|
+
context "without authorization" do
|
131
|
+
it "proceeds" do
|
132
|
+
expect(app).to receive(:call) do |*args|
|
133
|
+
expect(Conjur::Rack.identity?).to be(false)
|
134
|
+
:done
|
135
|
+
end
|
136
|
+
expect(call).to eq(:done)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
context "with authorization" do
|
140
|
+
include_context "with authorization"
|
141
|
+
it "processes the authorization" do
|
142
|
+
expect(app).to receive(:call) do |*args|
|
143
|
+
expect(Conjur::Rack.identity?).to be(true)
|
144
|
+
:done
|
145
|
+
end
|
146
|
+
expect(call).to eq(:done)
|
147
|
+
end
|
97
148
|
end
|
98
149
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
150
|
+
|
151
|
+
RSpec::Matchers.define :return_http do |status, message|
|
152
|
+
match do |actual|
|
153
|
+
status, headers, body = actual
|
154
|
+
expect(status).to eq status
|
155
|
+
expect(headers).to eq "Content-Type" => "text/plain", "Content-Length" => message.length.to_s
|
156
|
+
expect(body.join).to eq message
|
106
157
|
end
|
107
158
|
end
|
108
159
|
end
|
160
|
+
|
161
|
+
# protected internal methods
|
162
|
+
|
163
|
+
describe '#verify_authorization_and_get_identity' do
|
164
|
+
it "accepts JWT tokens without CIDR restrictions" do
|
165
|
+
mock_jwt sub: 'user'
|
166
|
+
expect { subject.send :verify_authorization_and_get_identity }.to_not raise_error
|
167
|
+
end
|
168
|
+
|
169
|
+
it "rejects JWT tokens with unrecognized claims" do
|
170
|
+
mock_jwt extra: 'field'
|
171
|
+
expect { subject.send :verify_authorization_and_get_identity }.to raise_error \
|
172
|
+
Conjur::Rack::Authenticator::AuthorizationError
|
173
|
+
end
|
174
|
+
|
175
|
+
def mock_jwt claims
|
176
|
+
token = Slosilo::JWT.new(claims).add_signature(alg: 'none') {}
|
177
|
+
allow(subject).to receive(:parsed_token) { token }
|
178
|
+
allow(Slosilo).to receive(:token_signer).with(token).and_return 'authn:test'
|
179
|
+
end
|
180
|
+
end
|
109
181
|
end
|
@@ -17,21 +17,21 @@ describe Conjur::Rack::PathPrefix do
|
|
17
17
|
context "/api/hosts" do
|
18
18
|
let(:path) { "/api/hosts" }
|
19
19
|
it "matches" do
|
20
|
-
app.
|
20
|
+
expect(app).to receive(:call).with({ 'PATH_INFO' => '/hosts' }).and_return app
|
21
21
|
call
|
22
22
|
end
|
23
23
|
end
|
24
24
|
context "/api" do
|
25
25
|
let(:path) { "/api" }
|
26
26
|
it "doesn't erase the path completely" do
|
27
|
-
app.
|
27
|
+
expect(app).to receive(:call).with({ 'PATH_INFO' => '/' }).and_return app
|
28
28
|
call
|
29
29
|
end
|
30
30
|
end
|
31
31
|
context "with non-matching prefix" do
|
32
32
|
let(:path) { "/hosts" }
|
33
33
|
it "doesn't match" do
|
34
|
-
app.
|
34
|
+
expect(app).to receive(:call).with({ 'PATH_INFO' => '/hosts' }).and_return app
|
35
35
|
call
|
36
36
|
end
|
37
37
|
end
|
data/spec/rack/user_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'conjur/rack/user'
|
2
3
|
|
3
4
|
describe Conjur::Rack::User do
|
4
5
|
let(:login){ 'admin' }
|
@@ -6,41 +7,50 @@ describe Conjur::Rack::User do
|
|
6
7
|
let(:account){ 'acct' }
|
7
8
|
let(:privilege) { nil }
|
8
9
|
let(:remote_ip) { nil }
|
10
|
+
let(:audit_roles) { nil }
|
11
|
+
let(:audit_resources) { nil }
|
9
12
|
|
10
|
-
subject{
|
13
|
+
subject(:user) {
|
14
|
+
described_class.new(token, account,
|
15
|
+
:privilege => privilege,
|
16
|
+
:remote_ip => remote_ip,
|
17
|
+
:audit_roles => audit_roles,
|
18
|
+
:audit_resources => audit_resources
|
19
|
+
)
|
20
|
+
}
|
11
21
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
it "aliases setter for account to conjur_account" do
|
18
|
-
subject.conjur_account = "changed!"
|
19
|
-
subject.account.should == "changed!"
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#new_assocation' do
|
23
|
-
let(:associate){ Class.new }
|
24
|
-
let(:params){{foo: 'bar'}}
|
25
|
-
it "calls cls.new with params including userid: login" do
|
26
|
-
associate.should_receive(:new).with(params.merge(userid: subject.login))
|
27
|
-
subject.new_association(associate, params)
|
28
|
-
end
|
22
|
+
it 'provides field accessors' do
|
23
|
+
expect(user.token).to eq token
|
24
|
+
expect(user.account).to eq account
|
25
|
+
expect(user.conjur_account).to eq account
|
26
|
+
expect(user.login).to eq login
|
29
27
|
end
|
30
28
|
|
31
29
|
describe '#roleid' do
|
32
30
|
let(:login){ tokens.join('/') }
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
|
32
|
+
context "when login contains one token" do
|
33
|
+
let(:tokens) { %w(foobar) }
|
34
|
+
|
35
|
+
it "is expanded to account:user:token" do
|
36
|
+
expect(subject.roleid).to eq "#{account}:user:foobar"
|
37
|
+
end
|
36
38
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
|
40
|
+
context "when login contains two tokens" do
|
41
|
+
let(:tokens) { %w(foo bar) }
|
42
|
+
|
43
|
+
it "is expanded to account:first:second" do
|
44
|
+
expect(subject.roleid).to eq "#{account}:foo:bar"
|
45
|
+
end
|
40
46
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
|
48
|
+
context "when login contains three tokens" do
|
49
|
+
let(:tokens) { %w(foo bar baz) }
|
50
|
+
|
51
|
+
it "is expanded to account:first:second/third" do
|
52
|
+
expect(subject.roleid).to eq "#{account}:foo:bar/baz"
|
53
|
+
end
|
44
54
|
end
|
45
55
|
end
|
46
56
|
|
@@ -48,13 +58,13 @@ describe Conjur::Rack::User do
|
|
48
58
|
let(:roleid){ 'the role id' }
|
49
59
|
let(:api){ double('conjur api') }
|
50
60
|
before do
|
51
|
-
subject.
|
52
|
-
subject.
|
61
|
+
allow(subject).to receive(:roleid).and_return roleid
|
62
|
+
allow(subject).to receive(:api).and_return api
|
53
63
|
end
|
54
64
|
|
55
65
|
it 'passes roleid to api.role' do
|
56
|
-
api.
|
57
|
-
subject.role.
|
66
|
+
expect(api).to receive(:role).with(roleid).and_return 'the role'
|
67
|
+
expect(subject.role).to eq('the role')
|
58
68
|
end
|
59
69
|
end
|
60
70
|
|
@@ -63,19 +73,19 @@ describe Conjur::Rack::User do
|
|
63
73
|
let(:privilege) { "reveal" }
|
64
74
|
let(:api){ Conjur::API.new_from_token "the-token" }
|
65
75
|
before do
|
66
|
-
subject.
|
76
|
+
allow(subject).to receive(:api).and_return(api)
|
67
77
|
end
|
68
78
|
it "checks the API function global_privilege_permitted?" do
|
69
|
-
api.
|
70
|
-
resource.
|
71
|
-
expect(subject.global_reveal?).to
|
79
|
+
expect(api).to receive(:resource).with("!:!:conjur").and_return(resource = double(:resource))
|
80
|
+
expect(resource).to receive(:permitted?).with("reveal").and_return(true)
|
81
|
+
expect(subject.global_reveal?).to be true
|
72
82
|
# The result is cached
|
73
83
|
subject.global_reveal?
|
74
84
|
end
|
75
85
|
end
|
76
86
|
context "without a global privilege" do
|
77
87
|
it "simply returns nil" do
|
78
|
-
expect(subject.global_reveal?).to
|
88
|
+
expect(subject.global_reveal?).to be false
|
79
89
|
end
|
80
90
|
end
|
81
91
|
end
|
@@ -84,38 +94,96 @@ describe Conjur::Rack::User do
|
|
84
94
|
context "when given a class" do
|
85
95
|
let(:cls){ double('API class') }
|
86
96
|
it "calls cls.new_from_token with its token" do
|
87
|
-
cls.
|
88
|
-
subject.api(cls).
|
97
|
+
expect(cls).to receive(:new_from_token).with(token).and_return 'the api'
|
98
|
+
expect(subject.api(cls)).to eq('the api')
|
89
99
|
end
|
90
100
|
end
|
91
101
|
context 'when not given args' do
|
92
102
|
shared_examples_for "builds the api" do
|
93
|
-
|
94
|
-
subject.api.should == 'the api'
|
95
|
-
}
|
103
|
+
its(:api) { should == 'the api' }
|
96
104
|
end
|
97
105
|
|
98
106
|
context "with no extra args" do
|
99
107
|
before {
|
100
|
-
Conjur::API.
|
108
|
+
expect(Conjur::API).to receive(:new_from_token).with(token).and_return('the api')
|
101
109
|
}
|
102
110
|
it_should_behave_like "builds the api"
|
103
111
|
end
|
104
112
|
context "with remote_ip" do
|
105
113
|
let(:remote_ip) { "the-ip" }
|
106
114
|
before {
|
107
|
-
Conjur::API.
|
115
|
+
expect(Conjur::API).to receive(:new_from_token).with(token, 'the-ip').and_return('the api')
|
108
116
|
}
|
109
117
|
it_should_behave_like "builds the api"
|
110
118
|
end
|
111
119
|
context "with privilege" do
|
112
|
-
let(:privilege) { "
|
120
|
+
let(:privilege) { "elevate" }
|
121
|
+
before {
|
122
|
+
expect(Conjur::API).to receive(:new_from_token).with(token).and_return(api = double(:api))
|
123
|
+
expect(api).to receive(:with_privilege).with("elevate").and_return('the api')
|
124
|
+
}
|
125
|
+
it_should_behave_like "builds the api"
|
126
|
+
end
|
127
|
+
|
128
|
+
context "with audit resource" do
|
129
|
+
let (:audit_resources) { 'food:bacon' }
|
113
130
|
before {
|
114
|
-
Conjur::API.
|
115
|
-
expect(api).to receive(:
|
131
|
+
expect(Conjur::API).to receive(:new_from_token).with(token).and_return(api = double(:api))
|
132
|
+
expect(api).to receive(:with_audit_resources).with(['food:bacon']).and_return('the api')
|
116
133
|
}
|
117
134
|
it_should_behave_like "builds the api"
|
118
135
|
end
|
136
|
+
|
137
|
+
context "with audit roles" do
|
138
|
+
let (:audit_roles) { 'user:cook' }
|
139
|
+
before {
|
140
|
+
expect(Conjur::API).to receive(:new_from_token).with(token).and_return(api = double(:api))
|
141
|
+
expect(api).to receive(:with_audit_roles).with(['user:cook']).and_return('the api')
|
142
|
+
}
|
143
|
+
it_should_behave_like "builds the api"
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "with invalid type payload" do
|
150
|
+
let(:token){ { "data" => :alice } }
|
151
|
+
it "raises an error on trying to access the content" do
|
152
|
+
expect{ subject.login }.to raise_error("Expecting String or Hash token data, got Symbol")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "with hash payload" do
|
157
|
+
let(:token){ { "data" => { "login" => "alice", "capabilities" => { "fry" => "bacon" } } } }
|
158
|
+
|
159
|
+
it "processes the login and attributes" do
|
160
|
+
original_token = token.deep_dup
|
161
|
+
|
162
|
+
expect(subject.login).to eq('alice')
|
163
|
+
expect(subject.attributes).to eq({"capabilities" => { "fry" => "bacon" }})
|
164
|
+
|
165
|
+
expect(token).to eq original_token
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "with JWT token" do
|
170
|
+
let(:token) { {"protected"=>"eyJhbGciOiJ0ZXN0IiwidHlwIjoiSldUIn0=",
|
171
|
+
"payload"=>"eyJzdWIiOiJhbGljZSIsImlhdCI6MTUwNDU1NDI2NX0=",
|
172
|
+
"signature"=>"dGVzdHNpZw=="} }
|
173
|
+
|
174
|
+
it "processes the login and attributes" do
|
175
|
+
original_token = token.deep_dup
|
176
|
+
|
177
|
+
expect(subject.login).to eq('alice')
|
178
|
+
|
179
|
+
# TODO: should we only pass unrecognized attrs here?
|
180
|
+
expect(subject.attributes).to eq \
|
181
|
+
'alg' => 'test',
|
182
|
+
'iat' => 1504554265,
|
183
|
+
'sub' => 'alice',
|
184
|
+
'typ' => 'JWT'
|
185
|
+
|
186
|
+
expect(token).to eq original_token
|
119
187
|
end
|
120
188
|
end
|
121
|
-
end
|
189
|
+
end
|
data/spec/rack_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conjur/rack'
|
3
|
+
|
4
|
+
describe Conjur::Rack do
|
5
|
+
describe '.user' do
|
6
|
+
include_context "with authorization"
|
7
|
+
let(:stubuser) { double :stubuser }
|
8
|
+
before do
|
9
|
+
allow(Conjur::Rack::User).to receive(:new)
|
10
|
+
.with(token, 'someacc', {:privilege => privilege, :remote_ip => remote_ip, :audit_roles => audit_roles, :audit_resources => audit_resources})
|
11
|
+
.and_return(stubuser)
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when called in app context' do
|
15
|
+
shared_examples_for :returns_user do
|
16
|
+
it "returns user built from token" do
|
17
|
+
expect(call).to eq stubuser
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include_examples :returns_user
|
22
|
+
|
23
|
+
context 'with X-Conjur-Privilege' do
|
24
|
+
let(:privilege) { "elevate" }
|
25
|
+
include_examples :returns_user
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with X-Forwarded-For' do
|
29
|
+
let(:remote_ip) { "66.0.0.1" }
|
30
|
+
include_examples :returns_user
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with Conjur-Audit-Roles' do
|
34
|
+
let (:audit_roles) { 'user%3Acook' }
|
35
|
+
include_examples :returns_user
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with Conjur-Audit-Resources' do
|
39
|
+
let (:audit_resources) { 'food%3Abacon' }
|
40
|
+
include_examples :returns_user
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises error if called out of app context" do
|
46
|
+
expect { Conjur::Rack.user }.to raise_error('No Conjur identity for current request')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,8 +4,44 @@ $:.unshift File.join(File.dirname(__FILE__), "lib")
|
|
4
4
|
|
5
5
|
# Allows loading of an environment config based on the environment
|
6
6
|
require 'rspec'
|
7
|
+
require 'rspec/its'
|
7
8
|
require 'securerandom'
|
9
|
+
require 'slosilo'
|
8
10
|
|
9
11
|
RSpec.configure do |config|
|
10
12
|
end
|
11
13
|
|
14
|
+
RSpec.shared_context "with authenticator" do
|
15
|
+
let(:options) { {} }
|
16
|
+
let(:app) { double(:app) }
|
17
|
+
subject(:authenticator) { Conjur::Rack::Authenticator.new(app, options) }
|
18
|
+
let(:call) { authenticator.call env }
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.shared_context "with authorization" do
|
22
|
+
include_context "with authenticator"
|
23
|
+
let(:token_signer) { "authn:someacc" }
|
24
|
+
let(:audit_resources) { nil }
|
25
|
+
let(:privilege) { nil }
|
26
|
+
let(:remote_ip) { nil }
|
27
|
+
let(:audit_roles) { nil }
|
28
|
+
|
29
|
+
before do
|
30
|
+
allow(app).to receive(:call) { Conjur::Rack.user }
|
31
|
+
allow(Slosilo).to receive(:token_signer).and_return(token_signer)
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:env) do
|
35
|
+
{
|
36
|
+
'HTTP_AUTHORIZATION' => "Token token=\"#{basic_64}\""
|
37
|
+
}.tap do |e|
|
38
|
+
e['HTTP_X_CONJUR_PRIVILEGE'] = privilege if privilege
|
39
|
+
e['HTTP_X_FORWARDED_FOR'] = remote_ip if remote_ip
|
40
|
+
e['HTTP_CONJUR_AUDIT_ROLES'] = audit_roles if audit_roles
|
41
|
+
e['HTTP_CONJUR_AUDIT_RESOURCES'] = audit_resources if audit_resources
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:basic_64) { Base64.strict_encode64(token.to_json) }
|
46
|
+
let(:token) { { "data" => "foobar" } }
|
47
|
+
end
|
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conjur-rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Gilpin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slosilo
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: conjur-api
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "<"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '6'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "<"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,22 +86,44 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
90
|
-
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
91
95
|
- !ruby/object:Gem::Version
|
92
|
-
version: '
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ci_reporter_rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
93
104
|
type: :development
|
94
105
|
prerelease: false
|
95
106
|
version_requirements: !ruby/object:Gem::Requirement
|
96
107
|
requirements:
|
97
108
|
- - ">="
|
98
109
|
- !ruby/object:Gem::Version
|
99
|
-
version: '
|
100
|
-
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry-byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
101
116
|
- !ruby/object:Gem::Version
|
102
|
-
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'
|
103
125
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
126
|
+
name: rspec-its
|
105
127
|
requirement: !ruby/object:Gem::Requirement
|
106
128
|
requirements:
|
107
129
|
- - ">="
|
@@ -123,13 +145,13 @@ extra_rdoc_files: []
|
|
123
145
|
files:
|
124
146
|
- ".gitignore"
|
125
147
|
- ".project"
|
126
|
-
- ".rvmrc"
|
127
148
|
- CHANGELOG.md
|
128
149
|
- Gemfile
|
129
150
|
- LICENSE.txt
|
130
151
|
- README.md
|
131
152
|
- Rakefile
|
132
153
|
- conjur-rack.gemspec
|
154
|
+
- jenkins.sh
|
133
155
|
- lib/conjur/rack.rb
|
134
156
|
- lib/conjur/rack/authenticator.rb
|
135
157
|
- lib/conjur/rack/path_prefix.rb
|
@@ -138,6 +160,7 @@ files:
|
|
138
160
|
- spec/rack/authenticator_spec.rb
|
139
161
|
- spec/rack/path_prefix_spec.rb
|
140
162
|
- spec/rack/user_spec.rb
|
163
|
+
- spec/rack_spec.rb
|
141
164
|
- spec/spec_helper.rb
|
142
165
|
homepage: http://github.com/conjurinc/conjur-rack
|
143
166
|
licenses:
|
@@ -159,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
182
|
version: '0'
|
160
183
|
requirements: []
|
161
184
|
rubyforge_project:
|
162
|
-
rubygems_version: 2.
|
185
|
+
rubygems_version: 2.6.13
|
163
186
|
signing_key:
|
164
187
|
specification_version: 4
|
165
188
|
summary: Rack authenticator and basic User struct
|
@@ -167,4 +190,5 @@ test_files:
|
|
167
190
|
- spec/rack/authenticator_spec.rb
|
168
191
|
- spec/rack/path_prefix_spec.rb
|
169
192
|
- spec/rack/user_spec.rb
|
193
|
+
- spec/rack_spec.rb
|
170
194
|
- spec/spec_helper.rb
|
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm use --create 2.0.0@conjur-rack
|