conjur-rack 1.4.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +44 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +7 -1
- data/Jenkinsfile +63 -0
- data/LICENSE.txt +1 -1
- data/README.md +3 -5
- data/conjur-rack.gemspec +9 -6
- data/lib/conjur/rack/authenticator.rb +122 -51
- data/lib/conjur/rack/user.rb +80 -18
- data/lib/conjur/rack/version.rb +1 -1
- data/lib/conjur/rack.rb +23 -0
- data/publish.sh +7 -0
- data/spec/rack/authenticator_spec.rb +155 -83
- data/spec/rack/path_prefix_spec.rb +3 -3
- data/spec/rack/user_spec.rb +165 -65
- data/spec/rack_spec.rb +49 -0
- data/spec/spec_helper.rb +36 -0
- data/test.sh +12 -0
- metadata +56 -30
- data/.rvmrc +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bc0ff03755a64c04c14e15a5648c01484872315ac6e04904815ed93a115a569e
|
4
|
+
data.tar.gz: e7fd818c8efff7d6037c632117d8f73e021c185ebf5bebc08feeae75e88d72e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55a29ba4ee7e25e26514298c780c77a779252168419b516efc238af619a58a809faea7ba2664130876a43ad3d74929394f473532054c6b83dc16651f7141291b
|
7
|
+
data.tar.gz: e27d9e5cb3e26bbf5bef707dfb51e1509b1957f9a26a54b12467e046160f3097e6a776247f308364a8f5a7a8dd904e02f8a00d112c24c81c7ef2772cc0c3402c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,47 @@
|
|
1
|
+
# unreleased version
|
2
|
+
|
3
|
+
# v5.0.0
|
4
|
+
|
5
|
+
* Support Ruby 3.
|
6
|
+
* Bump `slosilo` to v3.0 with ruby 3.
|
7
|
+
* Remove pinned `bundler` version, use default system bundler.
|
8
|
+
|
9
|
+
# v4.2.0
|
10
|
+
|
11
|
+
* Bump `slosilo` to v2.2 in order to be FIPS compliant
|
12
|
+
|
13
|
+
# v4.0.0
|
14
|
+
|
15
|
+
* Bump `rack` to v2, `bundler` to v1.16 in gemspec
|
16
|
+
* Add Jenkinsfile to project
|
17
|
+
* Ignore headers such as Conjur-Privilege or Conjur-Audit if they're not
|
18
|
+
supported by the API (instead of erroring out).
|
19
|
+
|
20
|
+
# v3.1.0
|
21
|
+
|
22
|
+
* Support for JWT Slosilo tokens.
|
23
|
+
|
24
|
+
# v3.0.0.pre
|
25
|
+
|
26
|
+
* Initial support for Conjur 5.
|
27
|
+
|
28
|
+
# v2.3.0
|
29
|
+
|
30
|
+
* Add TRUSTED_PROXIES support
|
31
|
+
|
32
|
+
# v2.2.0
|
33
|
+
|
34
|
+
* resolve 'own' token to CONJUR_ACCOUNT env var
|
35
|
+
* add #optional paths to Conjur::Rack authenticator
|
36
|
+
|
37
|
+
# v2.1.0
|
38
|
+
|
39
|
+
* Add handling for `Conjur-Audit-Roles` and `Conjur-Audit-Resources`
|
40
|
+
|
41
|
+
# v2.0.0
|
42
|
+
|
43
|
+
* Change `global_sudo?` to `global_elevate?`
|
44
|
+
|
1
45
|
# v1.4.0
|
2
46
|
|
3
47
|
* 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/CONTRIBUTING.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
For general contribution and community guidelines, please see the [community repo](https://github.com/cyberark/community).
|
4
|
+
|
5
|
+
## Contributing Workflow
|
6
|
+
|
7
|
+
1. [Fork the project](https://help.github.com/en/github/getting-started-with-github/fork-a-repo)
|
8
|
+
2. [Clone your fork](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository)
|
9
|
+
3. Make local changes to your fork by editing files
|
10
|
+
3. [Commit your changes](https://help.github.com/en/github/managing-files-in-a-repository/adding-a-file-to-a-repository-using-the-command-line)
|
11
|
+
4. [Push your local changes to the remote server](https://help.github.com/en/github/using-git/pushing-commits-to-a-remote-repository)
|
12
|
+
5. [Create new Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork)
|
13
|
+
|
14
|
+
From here your pull request will be reviewed and once you've responded to all
|
15
|
+
feedback it will be merged into the project. Congratulations, you're a
|
16
|
+
contributor!
|
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-3.0
|
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/Jenkinsfile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
pipeline {
|
2
|
+
agent { label 'executor-v2' }
|
3
|
+
|
4
|
+
options {
|
5
|
+
timestamps()
|
6
|
+
buildDiscarder(logRotator(daysToKeepStr: '30'))
|
7
|
+
}
|
8
|
+
|
9
|
+
stages {
|
10
|
+
stage('Run tests') {
|
11
|
+
steps {
|
12
|
+
sh './test.sh'
|
13
|
+
|
14
|
+
junit 'spec/reports/*.xml'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
// Only publish to RubyGems if the HEAD is
|
19
|
+
// tagged with the same version as in version.rb
|
20
|
+
stage('Publish to RubyGems') {
|
21
|
+
agent { label 'executor-v2' }
|
22
|
+
|
23
|
+
when {
|
24
|
+
expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') }
|
25
|
+
branch "master"
|
26
|
+
expression {
|
27
|
+
def exitCode = sh returnStatus: true, script: ''' set +x
|
28
|
+
echo "Determining if publishing is requested..."
|
29
|
+
|
30
|
+
VERSION=`cat lib/conjur/rack/version.rb | grep VERSION | sed 's/.* "//;s/"//'`
|
31
|
+
echo Declared version: $VERSION
|
32
|
+
|
33
|
+
# Jenkins git plugin is broken and always fetches with `--no-tags`
|
34
|
+
# (or `--tags`, neither of which is what you want), so tags end up
|
35
|
+
# not being fetched. Try to fix that.
|
36
|
+
# (Unfortunately this fetches all remote heads, so we may have to find
|
37
|
+
# another solution for bigger repos.)
|
38
|
+
git fetch -q
|
39
|
+
|
40
|
+
# note when tag not found git rev-parse will just print its name
|
41
|
+
TAG=`git rev-list -n 1 "v$VERSION" 2>/dev/null || :`
|
42
|
+
echo Tag v$VERSION: $TAG
|
43
|
+
|
44
|
+
HEAD=`git rev-parse HEAD`
|
45
|
+
echo HEAD: $HEAD
|
46
|
+
|
47
|
+
test "$HEAD" = "$TAG"
|
48
|
+
'''
|
49
|
+
return exitCode == 0
|
50
|
+
}
|
51
|
+
}
|
52
|
+
steps {
|
53
|
+
sh './publish.sh'
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
post {
|
59
|
+
always {
|
60
|
+
cleanupAndNotify(currentBuild.currentResult)
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -22,8 +22,6 @@ TODO: Write usage instructions here
|
|
22
22
|
|
23
23
|
## Contributing
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create new Pull Request
|
25
|
+
We welcome contributions of all kinds to this repository. For instructions on
|
26
|
+
how to get started and descriptions of our development workflows, please see our
|
27
|
+
[contributing guide](CONTRIBUTING.md).
|
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"
|
24
|
-
|
25
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
21
|
+
spec.add_dependency "slosilo", "~> 3.0"
|
22
|
+
spec.add_dependency "conjur-api", "< 6"
|
23
|
+
spec.add_dependency "rack", "~> 2"
|
24
|
+
|
26
25
|
spec.add_development_dependency "rake"
|
27
|
-
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "activesupport", "< 7"
|
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
|
@@ -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.
|
@@ -30,7 +37,9 @@ module Conjur
|
|
30
37
|
# actually have that privilege according to the Conjur server.
|
31
38
|
def validated_global_privilege
|
32
39
|
unless @validated_global_privilege
|
33
|
-
@privilege = nil
|
40
|
+
@privilege = nil unless @privilege &&
|
41
|
+
api.respond_to?(:global_privilege_permitted?) &&
|
42
|
+
api.global_privilege_permitted?(@privilege)
|
34
43
|
@validated_global_privilege = true
|
35
44
|
end
|
36
45
|
@privilege
|
@@ -41,13 +50,21 @@ module Conjur
|
|
41
50
|
validated_global_privilege == "reveal"
|
42
51
|
end
|
43
52
|
|
44
|
-
# True if and only if the user has valid global '
|
45
|
-
def
|
46
|
-
validated_global_privilege == "
|
53
|
+
# True if and only if the user has valid global 'elevate' privilege.
|
54
|
+
def global_elevate?
|
55
|
+
validated_global_privilege == "elevate"
|
47
56
|
end
|
48
57
|
|
49
58
|
def login
|
50
|
-
|
59
|
+
parse_token
|
60
|
+
|
61
|
+
@login
|
62
|
+
end
|
63
|
+
|
64
|
+
def attributes
|
65
|
+
parse_token
|
66
|
+
|
67
|
+
@attributes || {}
|
51
68
|
end
|
52
69
|
|
53
70
|
def roleid
|
@@ -63,17 +80,62 @@ module Conjur
|
|
63
80
|
def role
|
64
81
|
api.role(roleid)
|
65
82
|
end
|
66
|
-
|
83
|
+
|
84
|
+
def audit_resources
|
85
|
+
Conjur::API.decode_audit_ids(@audit_resources) if @audit_resources
|
86
|
+
end
|
87
|
+
|
88
|
+
def audit_roles
|
89
|
+
Conjur::API.decode_audit_ids(@audit_roles) if @audit_roles
|
90
|
+
end
|
91
|
+
|
67
92
|
def api(cls = Conjur::API)
|
68
93
|
args = [ token ]
|
69
94
|
args.push remote_ip if remote_ip
|
70
95
|
api = cls.new_from_token(*args)
|
71
|
-
|
72
|
-
|
96
|
+
|
97
|
+
# These are features not present in some API versions.
|
98
|
+
# Test for them and only apply if it makes sense. Ignore otherwise.
|
99
|
+
%i(privilege audit_resources audit_roles).each do |feature|
|
100
|
+
meth = "with_#{feature}".intern
|
101
|
+
if api.respond_to?(meth) && (value = send(feature))
|
102
|
+
api = api.send meth, value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
api
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
def parse_token
|
112
|
+
return if @login
|
113
|
+
|
114
|
+
@token = Slosilo::JWT token
|
115
|
+
load_jwt token
|
116
|
+
rescue ArgumentError
|
117
|
+
if data = token['data']
|
118
|
+
return load_legacy data
|
73
119
|
else
|
74
|
-
|
120
|
+
raise "malformed token"
|
75
121
|
end
|
76
122
|
end
|
123
|
+
|
124
|
+
def load_legacy data
|
125
|
+
if data.is_a?(String)
|
126
|
+
@login = token['data']
|
127
|
+
elsif data.is_a?(Hash)
|
128
|
+
@attributes = token['data'].clone
|
129
|
+
@login = @attributes.delete('login') or raise "No 'login' field in token data"
|
130
|
+
else
|
131
|
+
raise "Expecting String or Hash token data, got #{data.class.name}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def load_jwt jwt
|
136
|
+
@attributes = jwt.claims.merge (jwt.header || {}) # just pass all the info
|
137
|
+
@login = jwt.claims['sub'] or raise "No 'sub' field in claims"
|
138
|
+
end
|
77
139
|
end
|
78
140
|
end
|
79
141
|
end
|
data/lib/conjur/rack/version.rb
CHANGED
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
|
data/publish.sh
ADDED