rails-auth 2.1.4 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +14 -1
- data/.travis.yml +8 -5
- data/BUG-BOUNTY.md +3 -3
- data/CHANGES.md +21 -2
- data/CONTRIBUTING.md +11 -10
- data/Gemfile +6 -5
- data/Guardfile +2 -0
- data/Rakefile +3 -1
- data/lib/rails/auth/acl.rb +4 -0
- data/lib/rails/auth/acl/matchers/allow_all.rb +3 -0
- data/lib/rails/auth/acl/middleware.rb +3 -0
- data/lib/rails/auth/acl/resource.rb +7 -5
- data/lib/rails/auth/config_builder.rb +4 -0
- data/lib/rails/auth/controller_methods.rb +4 -0
- data/lib/rails/auth/credentials.rb +2 -0
- data/lib/rails/auth/credentials/injector_middleware.rb +6 -2
- data/lib/rails/auth/env.rb +4 -3
- data/lib/rails/auth/error_page/debug_middleware.rb +1 -1
- data/lib/rails/auth/error_page/middleware.rb +3 -0
- data/lib/rails/auth/exceptions.rb +2 -0
- data/lib/rails/auth/helpers.rb +2 -0
- data/lib/rails/auth/installed_constraint.rb +2 -0
- data/lib/rails/auth/monitor/middleware.rb +2 -0
- data/lib/rails/auth/rack.rb +1 -0
- data/lib/rails/auth/rspec.rb +2 -0
- data/lib/rails/auth/rspec/helper_methods.rb +6 -5
- data/lib/rails/auth/rspec/matchers/acl_matchers.rb +2 -0
- data/lib/rails/auth/version.rb +1 -1
- data/lib/rails/auth/x509/certificate.rb +35 -5
- data/lib/rails/auth/x509/filter/java.rb +4 -12
- data/lib/rails/auth/x509/filter/pem.rb +2 -0
- data/lib/rails/auth/x509/matcher.rb +2 -0
- data/lib/rails/auth/x509/middleware.rb +4 -3
- data/lib/rails/auth/x509/subject_alt_name_extension.rb +29 -0
- data/rails-auth.gemspec +5 -4
- data/spec/rails/auth/acl/matchers/allow_all_spec.rb +2 -0
- data/spec/rails/auth/acl/middleware_spec.rb +2 -0
- data/spec/rails/auth/acl/resource_spec.rb +2 -0
- data/spec/rails/auth/acl_spec.rb +2 -0
- data/spec/rails/auth/controller_methods_spec.rb +2 -0
- data/spec/rails/auth/credentials/injector_middleware_spec.rb +15 -0
- data/spec/rails/auth/credentials_spec.rb +2 -0
- data/spec/rails/auth/env_spec.rb +2 -0
- data/spec/rails/auth/error_page/debug_middleware_spec.rb +2 -0
- data/spec/rails/auth/error_page/middleware_spec.rb +2 -0
- data/spec/rails/auth/monitor/middleware_spec.rb +2 -0
- data/spec/rails/auth/rspec/helper_methods_spec.rb +2 -0
- data/spec/rails/auth/rspec/matchers/acl_matchers_spec.rb +2 -0
- data/spec/rails/auth/x509/certificate_spec.rb +103 -20
- data/spec/rails/auth/x509/matcher_spec.rb +2 -0
- data/spec/rails/auth/x509/middleware_spec.rb +6 -2
- data/spec/rails/auth/x509/subject_alt_name_extension_spec.rb +39 -0
- data/spec/rails/auth_spec.rb +2 -0
- data/spec/spec_helper.rb +5 -3
- data/spec/support/claims_matcher.rb +2 -0
- data/spec/support/create_certs.rb +57 -2
- metadata +14 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c22c652d804b973313277d33b6c08dd0f3ae6389dfa0ebeaba73fd84488084b3
|
4
|
+
data.tar.gz: 95f4c1eab88b2ee3f8f608682690e70c8ca3a4c1b9925b537f14d33c88b91f7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a78bb6b55dd36517e9fd325f433210d3367d2aab18541507ac9feb607cdc92c4f2ce4b26df69bdd093c918b98bfc8c37c75add8ce572a0eb07025d96f2bc95f7
|
7
|
+
data.tar.gz: c5363dfa5f09bef450d827bdfa24226c4e080c47ff8c4b5c81da94192c834ac4d3fa97531d9dec11b5907949d249f59cf9856dd1b727f40d89b1ce2379ce60ac
|
data/.rubocop.yml
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
AllCops:
|
2
2
|
DisplayCopNames: true
|
3
|
+
TargetRubyVersion: 2.3
|
3
4
|
|
4
5
|
Style/StringLiterals:
|
5
6
|
EnforcedStyle: double_quotes
|
6
7
|
|
7
|
-
|
8
|
+
Layout/HashAlignment:
|
8
9
|
Enabled: false
|
9
10
|
|
11
|
+
Metrics/BlockLength:
|
12
|
+
ExcludedMethods: ['describe', 'context']
|
13
|
+
|
10
14
|
Metrics/ParameterLists:
|
11
15
|
Max: 5
|
12
16
|
CountKeywordArgs: false
|
@@ -22,3 +26,12 @@ Metrics/AbcSize:
|
|
22
26
|
|
23
27
|
Metrics/CyclomaticComplexity:
|
24
28
|
Max: 8
|
29
|
+
|
30
|
+
Naming/MethodParameterName:
|
31
|
+
MinNameLength: 2
|
32
|
+
|
33
|
+
Style/ModuleFunction:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/SafeNavigation:
|
37
|
+
Enabled: false
|
data/.travis.yml
CHANGED
@@ -10,12 +10,15 @@ before_install:
|
|
10
10
|
bundler_args: --without development
|
11
11
|
|
12
12
|
rvm:
|
13
|
-
- 2.
|
14
|
-
- 2.
|
15
|
-
- 2.
|
16
|
-
- 2.3.0
|
13
|
+
- 2.4
|
14
|
+
- 2.5
|
15
|
+
- 2.6
|
17
16
|
matrix:
|
18
17
|
include:
|
19
|
-
- rvm: jruby
|
18
|
+
- rvm: jruby
|
19
|
+
jdk: openjdk8
|
20
|
+
env: JRUBY_OPTS="--debug" # for simplecov
|
21
|
+
- rvm: jruby
|
22
|
+
jdk: openjdk11
|
20
23
|
env: JRUBY_OPTS="--debug" # for simplecov
|
21
24
|
fast_finish: true
|
data/BUG-BOUNTY.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
Serious about security
|
2
|
+
======================
|
3
3
|
|
4
4
|
Square recognizes the important contributions the security research community
|
5
5
|
can make. We therefore encourage reporting security issues with the code
|
6
6
|
contained in this repository.
|
7
7
|
|
8
8
|
If you believe you have discovered a security vulnerability, please follow the
|
9
|
-
guidelines at https://
|
9
|
+
guidelines at <https://bugcrowd.com/squareopensource>.
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
### 2.2.0 (2019-12-05)
|
2
|
+
|
3
|
+
* [#55](https://github.com/square/rails-auth/pull/55)
|
4
|
+
Allow dynamic injection of credentials.
|
5
|
+
([@drcapulet])
|
6
|
+
|
7
|
+
* [#59](https://github.com/square/rails-auth/pull/59)
|
8
|
+
Expose X.509 Subject Alternative Name extension
|
9
|
+
in the Rails::Auth::X509::Certificate and provide a convenience
|
10
|
+
method `spiffe_id` to expose [SPIFFE ID](https://spiffe.io).
|
11
|
+
([@mbyczkowski])
|
12
|
+
|
13
|
+
* [#57](https://github.com/square/rails-auth/pull/57)
|
14
|
+
Add support for latest versions of Ruby, JRuby and Bundler 2.
|
15
|
+
([@mbyczkowski])
|
16
|
+
|
1
17
|
### 2.1.4 (2018-07-12)
|
2
18
|
|
3
19
|
* [#51](https://github.com/square/rails-auth/pull/51)
|
@@ -184,6 +200,9 @@
|
|
184
200
|
* Vaporware release to claim the "rails-auth" gem name
|
185
201
|
|
186
202
|
|
187
|
-
[@tarcieri]: https://github.com/tarcieri
|
188
|
-
[@ewr]: https://github.com/ewr
|
189
203
|
[@drcapulet]: https://github.com/drcapulet
|
204
|
+
[@ewr]: https://github.com/ewr
|
205
|
+
[@mbyczkowski]: https://github.com/mbyczkowski
|
206
|
+
[@nerdrew]: https://github.com/nerdrew
|
207
|
+
[@tarcieri]: https://github.com/tarcieri
|
208
|
+
[@yellow-beard]: https://github.com/yellow-beard
|
data/CONTRIBUTING.md
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
|
1
|
+
# Contributing
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
our bases and makes sure you're eligible to contribute.
|
3
|
+
If you would like to contribute code to *rails-auth* you can do so through GitHub by
|
4
|
+
forking the repository and sending a pull request.
|
6
5
|
|
7
|
-
|
6
|
+
When submitting code, please make every effort to follow existing conventions
|
7
|
+
and style in order to keep the code as readable as possible. Please also make
|
8
|
+
sure all tests pass by running `bundle exec rspec spec`, and format your code
|
9
|
+
according to `rubocop` rules.
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
Before your code can be accepted into the project you must also sign the
|
12
|
+
Individual Contributor License Agreement. We use [cla-assistant.io][1] and you
|
13
|
+
will be prompted to sign once a pull request is opened.
|
12
14
|
|
13
|
-
[
|
14
|
-
[pull request]: https://github.com/square/rails-auth/pulls
|
15
|
+
[1]: https://cla-assistant.io/
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
group :development do
|
@@ -5,15 +7,14 @@ group :development do
|
|
5
7
|
end
|
6
8
|
|
7
9
|
group :development, :test do
|
10
|
+
gem "activesupport", "~> 4"
|
11
|
+
gem "certificate_authority", require: false
|
12
|
+
gem "coveralls", require: false
|
8
13
|
# Workaround for: https://github.com/bundler/bundler/pull/4650
|
9
14
|
gem "rack", "~> 1.x"
|
10
|
-
gem "activesupport", "~> 4"
|
11
|
-
|
12
15
|
gem "rake"
|
13
16
|
gem "rspec"
|
14
|
-
gem "rubocop", "0.
|
15
|
-
gem "coveralls", require: false
|
16
|
-
gem "certificate_authority", require: false
|
17
|
+
gem "rubocop", "0.77.0"
|
17
18
|
end
|
18
19
|
|
19
20
|
gemspec
|
data/Guardfile
CHANGED
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "bundler/gem_tasks"
|
2
4
|
require "rspec/core/rake_task"
|
3
5
|
require "rubocop/rake_task"
|
@@ -5,4 +7,4 @@ require "rubocop/rake_task"
|
|
5
7
|
RSpec::Core::RakeTask.new(:spec)
|
6
8
|
RuboCop::RakeTask.new
|
7
9
|
|
8
|
-
task default: %w
|
10
|
+
task default: %w[spec rubocop]
|
data/lib/rails/auth/acl.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Pull in default matchers
|
2
4
|
require "rails/auth/acl/matchers/allow_all"
|
3
5
|
|
@@ -17,7 +19,9 @@ module Rails
|
|
17
19
|
# @param [String] :yaml serialized YAML to load an ACL from
|
18
20
|
def self.from_yaml(yaml, **args)
|
19
21
|
require "yaml"
|
22
|
+
# rubocop:todo Security/YAMLLoad
|
20
23
|
new(YAML.load(yaml), **args)
|
24
|
+
# rubocop:enable Security/YAMLLoad
|
21
25
|
end
|
22
26
|
|
23
27
|
# @param [Array<Hash>] :acl Access Control List configuration
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
class ACL
|
@@ -7,6 +9,7 @@ module Rails
|
|
7
9
|
class AllowAll
|
8
10
|
def initialize(enabled)
|
9
11
|
raise ArgumentError, "enabled must be true/false" unless [true, false].include?(enabled)
|
12
|
+
|
10
13
|
@enabled = enabled
|
11
14
|
end
|
12
15
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
class ACL
|
@@ -25,6 +27,7 @@ module Rails
|
|
25
27
|
unless Rails::Auth.authorized?(env)
|
26
28
|
matcher_name = @acl.match(env)
|
27
29
|
raise NotAuthorizedError, "unauthorized request" unless matcher_name
|
30
|
+
|
28
31
|
Rails::Auth.set_allowed_by(env, "matcher:#{matcher_name}")
|
29
32
|
end
|
30
33
|
|
@@ -8,10 +8,10 @@ module Rails
|
|
8
8
|
attr_reader :http_methods, :path, :host, :matchers
|
9
9
|
|
10
10
|
# Valid HTTP methods
|
11
|
-
HTTP_METHODS = %w
|
11
|
+
HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK].freeze
|
12
12
|
|
13
13
|
# Options allowed for resource matchers
|
14
|
-
VALID_OPTIONS = %w
|
14
|
+
VALID_OPTIONS = %w[method path host].freeze
|
15
15
|
|
16
16
|
# @option :options [String] :method HTTP method allowed ("ALL" for all methods)
|
17
17
|
# @option :options [String] :path path to the resource (regex syntax allowed)
|
@@ -46,6 +46,7 @@ module Rails
|
|
46
46
|
#
|
47
47
|
def match(env)
|
48
48
|
return nil unless match!(env)
|
49
|
+
|
49
50
|
name, = @matchers.find { |_name, matcher| matcher.match(env) }
|
50
51
|
name
|
51
52
|
end
|
@@ -58,9 +59,10 @@ module Rails
|
|
58
59
|
# @return [Boolean] method and path *only* match the given environment
|
59
60
|
#
|
60
61
|
def match!(env)
|
61
|
-
return false unless @http_methods.include?(env["REQUEST_METHOD"
|
62
|
-
return false unless @path =~ env["PATH_INFO"
|
63
|
-
return false unless @host.nil? || @host =~ env["HTTP_HOST"
|
62
|
+
return false unless @http_methods.include?(env["REQUEST_METHOD"])
|
63
|
+
return false unless @path =~ env["PATH_INFO"]
|
64
|
+
return false unless @host.nil? || @host =~ env["HTTP_HOST"]
|
65
|
+
|
64
66
|
true
|
65
67
|
end
|
66
68
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
# Configures Rails::Auth middleware for use in a Rails application
|
@@ -49,6 +51,7 @@ module Rails
|
|
49
51
|
end
|
50
52
|
|
51
53
|
return unless monitor
|
54
|
+
|
52
55
|
config.middleware.insert_before Rails::Auth::ACL::Middleware,
|
53
56
|
Rails::Auth::Monitor::Middleware,
|
54
57
|
monitor
|
@@ -68,6 +71,7 @@ module Rails
|
|
68
71
|
Rails::Auth::ErrorPage::Middleware,
|
69
72
|
page_body: Pathname(error_page).read
|
70
73
|
when FalseClass, NilClass
|
74
|
+
nil
|
71
75
|
else raise TypeError, "bad error page mode: #{mode.inspect}"
|
72
76
|
end
|
73
77
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/hash_with_indifferent_access"
|
2
4
|
|
5
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
3
6
|
module Rails
|
4
7
|
module Auth
|
5
8
|
# Convenience methods designed to be included in an ActionController::Base subclass
|
@@ -18,3 +21,4 @@ module Rails
|
|
18
21
|
end
|
19
22
|
end
|
20
23
|
end
|
24
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
@@ -18,6 +18,7 @@ module Rails
|
|
18
18
|
|
19
19
|
def initialize(credentials = {})
|
20
20
|
raise TypeError, "expected Hash, got #{credentials.class}" unless credentials.is_a?(Hash)
|
21
|
+
|
21
22
|
@credentials = credentials
|
22
23
|
end
|
23
24
|
|
@@ -25,6 +26,7 @@ module Rails
|
|
25
26
|
return if @credentials.key?(type) && @credentials[type] == value
|
26
27
|
raise TypeError, "expected String for type, got #{type.class}" unless type.is_a?(String)
|
27
28
|
raise AlreadyAuthorizedError, "credential '#{type}' has already been set" if @credentials.key?(type)
|
29
|
+
|
28
30
|
@credentials[type] = value
|
29
31
|
end
|
30
32
|
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
class Credentials
|
4
6
|
# A middleware for injecting an arbitrary credentials hash into the Rack environment
|
5
7
|
# This is intended for development and testing purposes where you would like to
|
6
|
-
# simulate a given X.509 certificate being used in a request or user logged in
|
8
|
+
# simulate a given X.509 certificate being used in a request or user logged in.
|
9
|
+
# The credentials argument should either be a hash or a proc that returns one.
|
7
10
|
class InjectorMiddleware
|
8
11
|
def initialize(app, credentials)
|
9
12
|
@app = app
|
@@ -11,7 +14,8 @@ module Rails
|
|
11
14
|
end
|
12
15
|
|
13
16
|
def call(env)
|
14
|
-
|
17
|
+
credentials = @credentials.respond_to?(:call) ? @credentials.call(env) : @credentials
|
18
|
+
env[Rails::Auth::Env::CREDENTIALS_ENV_KEY] = credentials
|
15
19
|
@app.call(env)
|
16
20
|
end
|
17
21
|
end
|
data/lib/rails/auth/env.rb
CHANGED
@@ -5,13 +5,13 @@ module Rails
|
|
5
5
|
# Wrapper for Rack environments with Rails::Auth helpers
|
6
6
|
class Env
|
7
7
|
# Rack environment key for marking external authorization
|
8
|
-
AUTHORIZED_ENV_KEY = "rails-auth.authorized"
|
8
|
+
AUTHORIZED_ENV_KEY = "rails-auth.authorized"
|
9
9
|
|
10
10
|
# Rack environment key for storing what allowed the request
|
11
|
-
ALLOWED_BY_ENV_KEY = "rails-auth.allowed-by"
|
11
|
+
ALLOWED_BY_ENV_KEY = "rails-auth.allowed-by"
|
12
12
|
|
13
13
|
# Rack environment key for all rails-auth credentials
|
14
|
-
CREDENTIALS_ENV_KEY = "rails-auth.credentials"
|
14
|
+
CREDENTIALS_ENV_KEY = "rails-auth.credentials"
|
15
15
|
|
16
16
|
attr_reader :allowed_by, :credentials
|
17
17
|
|
@@ -44,6 +44,7 @@ module Rails
|
|
44
44
|
def allowed_by=(allowed_by)
|
45
45
|
raise AlreadyAuthorizedError, "already allowed by #{@allowed_by.inspect}" if @allowed_by
|
46
46
|
raise TypeError, "expected String for allowed_by, got #{allowed_by.class}" unless allowed_by.is_a?(String)
|
47
|
+
|
47
48
|
@allowed_by = allowed_by
|
48
49
|
end
|
49
50
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
module ErrorPage
|
@@ -32,6 +34,7 @@ module Rails
|
|
32
34
|
accept_format = env["HTTP_ACCEPT"]
|
33
35
|
return :json if accept_format && accept_format.downcase.start_with?("application/json")
|
34
36
|
return :json if env["PATH_INFO"] && env["PATH_INFO"].end_with?(".json")
|
37
|
+
|
35
38
|
nil
|
36
39
|
end
|
37
40
|
end
|
data/lib/rails/auth/helpers.rb
CHANGED
data/lib/rails/auth/rack.rb
CHANGED
data/lib/rails/auth/rspec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
module RSpec
|
@@ -12,6 +14,7 @@ module Rails
|
|
12
14
|
# NOTE: Credentials will be *cleared* after the block. Nesting is not allowed.
|
13
15
|
def with_credentials(credentials = {})
|
14
16
|
raise TypeError, "expected Hash of credentials, got #{credentials.class}" unless credentials.is_a?(Hash)
|
17
|
+
|
15
18
|
test_credentials.clear
|
16
19
|
|
17
20
|
credentials.each do |type, value|
|
@@ -24,8 +27,8 @@ module Rails
|
|
24
27
|
# Creates an Rails::Auth::X509::Certificate instance double
|
25
28
|
def x509_certificate(cn: nil, ou: nil)
|
26
29
|
subject = ""
|
27
|
-
subject
|
28
|
-
subject
|
30
|
+
subject += "CN=#{cn}" if cn
|
31
|
+
subject += "OU=#{ou}" if ou
|
29
32
|
|
30
33
|
instance_double(Rails::Auth::X509::Certificate, subject, cn: cn, ou: ou).tap do |certificate|
|
31
34
|
allow(certificate).to receive(:[]) do |key|
|
@@ -47,9 +50,7 @@ module Rails
|
|
47
50
|
path = self.class.description
|
48
51
|
|
49
52
|
# Warn if methods are improperly used
|
50
|
-
unless path.chars[0] == "/"
|
51
|
-
raise ArgumentError, "expected #{path} to start with '/'"
|
52
|
-
end
|
53
|
+
raise ArgumentError, "expected #{path} to start with '/'" unless path.chars[0] == "/"
|
53
54
|
|
54
55
|
env = {
|
55
56
|
"REQUEST_METHOD" => method,
|
data/lib/rails/auth/version.rb
CHANGED
@@ -18,7 +18,8 @@ module Rails
|
|
18
18
|
@certificate.subject.to_a.each do |name, data, _type|
|
19
19
|
@subject[name.freeze] = data.freeze
|
20
20
|
end
|
21
|
-
|
21
|
+
@subject_alt_names = SubjectAltNameExtension.new(certificate)
|
22
|
+
@subject_alt_names.freeze
|
22
23
|
@subject.freeze
|
23
24
|
end
|
24
25
|
|
@@ -27,23 +28,52 @@ module Rails
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def cn
|
30
|
-
@subject["CN"
|
31
|
+
@subject["CN"]
|
31
32
|
end
|
32
33
|
alias common_name cn
|
33
34
|
|
35
|
+
def dns_names
|
36
|
+
@subject_alt_names.dns_names
|
37
|
+
end
|
38
|
+
|
39
|
+
def ips
|
40
|
+
@subject_alt_names.ips
|
41
|
+
end
|
42
|
+
|
34
43
|
def ou
|
35
|
-
@subject["OU"
|
44
|
+
@subject["OU"]
|
36
45
|
end
|
37
46
|
alias organizational_unit ou
|
38
47
|
|
48
|
+
def uris
|
49
|
+
@subject_alt_names.uris
|
50
|
+
end
|
51
|
+
|
52
|
+
# According to the SPIFFE standard only one SPIFFE ID can exist in the URI
|
53
|
+
# SAN:
|
54
|
+
# (https://github.com/spiffe/spiffe/blob/master/standards/X509-SVID.md#2-spiffe-id)
|
55
|
+
#
|
56
|
+
# @return [String, nil] string containing SPIFFE ID if one is present
|
57
|
+
# in the certificate
|
58
|
+
def spiffe_id
|
59
|
+
uris.detect { |uri| uri.start_with?("spiffe://") }
|
60
|
+
end
|
61
|
+
|
39
62
|
# Generates inspectable attributes for debugging
|
40
63
|
#
|
41
64
|
# @return [Hash] hash containing parts of the certificate subject (cn, ou)
|
65
|
+
# and subject alternative name extension (uris, dns_names) as well
|
66
|
+
# as SPIFFE ID (spiffe_id), which is just a convenience since those
|
67
|
+
# are already included in the uris
|
42
68
|
def attributes
|
43
69
|
{
|
44
70
|
cn: cn,
|
45
|
-
|
46
|
-
|
71
|
+
dns_names: dns_names,
|
72
|
+
ips: ips,
|
73
|
+
ou: ou,
|
74
|
+
spiffe_id: spiffe_id,
|
75
|
+
uris: uris
|
76
|
+
}.reject { |_, v| v.nil? || v.empty? }
|
47
77
|
end
|
48
78
|
|
49
79
|
# Compare ourself to another object by ensuring that it has the same type
|
@@ -1,23 +1,15 @@
|
|
1
|
-
|
2
|
-
require "stringio"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Rails
|
5
4
|
module Auth
|
6
5
|
module X509
|
7
6
|
module Filter
|
8
|
-
# Extract OpenSSL::X509::Certificates from
|
7
|
+
# Extract OpenSSL::X509::Certificates from java.security.cert.Certificate
|
9
8
|
class Java
|
10
9
|
def call(certs)
|
11
|
-
return
|
12
|
-
OpenSSL::X509::Certificate.new(extract_der(certs[0])).freeze
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
10
|
+
return if certs.nil? || certs.empty?
|
16
11
|
|
17
|
-
|
18
|
-
stringio = StringIO.new
|
19
|
-
cert.derEncode(stringio.to_outputstream)
|
20
|
-
stringio.string
|
12
|
+
OpenSSL::X509::Certificate.new(certs[0].get_encoded).freeze
|
21
13
|
end
|
22
14
|
end
|
23
15
|
end
|
@@ -40,7 +40,7 @@ module Rails
|
|
40
40
|
|
41
41
|
def call(env)
|
42
42
|
credential = extract_credential(env)
|
43
|
-
Rails::Auth.add_credential(env, "x509"
|
43
|
+
Rails::Auth.add_credential(env, "x509", credential.freeze) if credential
|
44
44
|
|
45
45
|
@app.call(env)
|
46
46
|
end
|
@@ -62,6 +62,7 @@ module Rails
|
|
62
62
|
end
|
63
63
|
|
64
64
|
raise CertificateVerifyFailed, "no client certificate in request" if @require_cert
|
65
|
+
|
65
66
|
nil
|
66
67
|
end
|
67
68
|
|
@@ -72,8 +73,8 @@ module Rails
|
|
72
73
|
end
|
73
74
|
|
74
75
|
filter.call(raw_cert)
|
75
|
-
rescue =>
|
76
|
-
@logger.debug("rails-auth: Certificate error: #{
|
76
|
+
rescue StandardError => e
|
77
|
+
@logger.debug("rails-auth: Certificate error: #{e.class}: #{e.message}") if @logger
|
77
78
|
nil
|
78
79
|
end
|
79
80
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Auth
|
5
|
+
module X509
|
6
|
+
# Provides convenience methods for subjectAltName extension of X.509 certificates
|
7
|
+
class SubjectAltNameExtension
|
8
|
+
attr_reader :dns_names, :ips, :uris
|
9
|
+
|
10
|
+
DNS_REGEX = /^DNS:/i.freeze
|
11
|
+
IP_REGEX = /^IP( Address)?:/i.freeze
|
12
|
+
URI_REGEX = /^URI:/i.freeze
|
13
|
+
|
14
|
+
def initialize(certificate)
|
15
|
+
unless certificate.is_a?(OpenSSL::X509::Certificate)
|
16
|
+
raise TypeError, "expecting OpenSSL::X509::Certificate, got #{certificate.class}"
|
17
|
+
end
|
18
|
+
|
19
|
+
extension = certificate.extensions.detect { |ext| ext.oid == "subjectAltName" }
|
20
|
+
values = (extension&.value&.split(",") || []).map(&:strip)
|
21
|
+
|
22
|
+
@dns_names = values.grep(DNS_REGEX) { |v| v.sub(DNS_REGEX, "") }.freeze
|
23
|
+
@ips = values.grep(IP_REGEX) { |v| v.sub(IP_REGEX, "") }.freeze
|
24
|
+
@uris = values.grep(URI_REGEX) { |v| v.sub(URI_REGEX, "") }.freeze
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/rails-auth.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require "rails/auth/version"
|
5
6
|
|
@@ -25,10 +26,10 @@ Gem::Specification.new do |spec|
|
|
25
26
|
spec.bindir = "exe"
|
26
27
|
spec.require_paths = ["lib"]
|
27
28
|
|
28
|
-
spec.required_ruby_version = ">= 2.
|
29
|
+
spec.required_ruby_version = ">= 2.3.0"
|
29
30
|
|
30
31
|
spec.add_runtime_dependency "rack"
|
31
32
|
|
32
|
-
spec.add_development_dependency "bundler", "
|
33
|
+
spec.add_development_dependency "bundler", ">= 1.10", "< 3"
|
33
34
|
spec.add_development_dependency "rake", "~> 10.0"
|
34
35
|
end
|
data/spec/rails/auth/acl_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe Rails::Auth::Credentials::InjectorMiddleware do
|
2
4
|
let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
|
3
5
|
let(:app) { ->(env) { [200, env, "Hello, world!"] } }
|
@@ -8,4 +10,17 @@ RSpec.describe Rails::Auth::Credentials::InjectorMiddleware do
|
|
8
10
|
_response, env = middleware.call(request)
|
9
11
|
expect(env[Rails::Auth::Env::CREDENTIALS_ENV_KEY]).to eq credentials
|
10
12
|
end
|
13
|
+
|
14
|
+
context "with a proc for credentials" do
|
15
|
+
let(:credentials_proc) { instance_double(Proc) }
|
16
|
+
let(:middleware) { described_class.new(app, credentials_proc) }
|
17
|
+
|
18
|
+
it "overrides rails-auth credentials in the rack environment" do
|
19
|
+
expect(credentials_proc).to receive(:call).with(request).and_return(credentials)
|
20
|
+
|
21
|
+
_response, env = middleware.call(request)
|
22
|
+
|
23
|
+
expect(env[Rails::Auth::Env::CREDENTIALS_ENV_KEY]).to eq credentials
|
24
|
+
end
|
25
|
+
end
|
11
26
|
end
|
data/spec/rails/auth/env_spec.rb
CHANGED
@@ -1,38 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe Rails::Auth::X509::Certificate do
|
2
4
|
let(:example_cert) { OpenSSL::X509::Certificate.new(cert_path("valid.crt").read) }
|
5
|
+
let(:example_cert_with_extension) { OpenSSL::X509::Certificate.new(cert_path("valid_with_ext.crt").read) }
|
3
6
|
let(:example_certificate) { described_class.new(example_cert) }
|
7
|
+
let(:example_certificate_with_extension) { described_class.new(example_cert_with_extension) }
|
4
8
|
|
5
9
|
let(:example_cn) { "127.0.0.1" }
|
10
|
+
let(:example_dns_names) { %w[example.com exemplar.com somethingelse.com] }
|
11
|
+
let(:example_ips) { %w[0.0.0.0 127.0.0.1 192.168.1.1] }
|
6
12
|
let(:example_ou) { "ponycopter" }
|
13
|
+
let(:example_spiffe) { "spiffe://example.com/exemplar" }
|
14
|
+
let(:example_uris) { [example_spiffe, "https://www.example.com/page1", "https://www.example.com/page2"] }
|
15
|
+
|
16
|
+
describe "without extensions" do
|
17
|
+
describe "#[]" do
|
18
|
+
it "allows access to subject components via strings" do
|
19
|
+
expect(example_certificate["CN"]).to eq example_cn
|
20
|
+
expect(example_certificate["OU"]).to eq example_ou
|
21
|
+
end
|
7
22
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
23
|
+
it "allows access to subject components via symbols" do
|
24
|
+
expect(example_certificate[:cn]).to eq example_cn
|
25
|
+
expect(example_certificate[:ou]).to eq example_ou
|
26
|
+
end
|
12
27
|
end
|
13
28
|
|
14
|
-
it "
|
15
|
-
expect(example_certificate
|
16
|
-
expect(example_certificate[:ou]).to eq example_ou
|
29
|
+
it "knows its #cn" do
|
30
|
+
expect(example_certificate.cn).to eq example_cn
|
17
31
|
end
|
18
|
-
end
|
19
32
|
|
20
|
-
|
21
|
-
|
22
|
-
|
33
|
+
it "has no #dns_names" do
|
34
|
+
expect(example_certificate.dns_names).to be_empty
|
35
|
+
end
|
23
36
|
|
24
|
-
|
25
|
-
|
26
|
-
|
37
|
+
it "has no #ips" do
|
38
|
+
expect(example_certificate.ips).to be_empty
|
39
|
+
end
|
40
|
+
|
41
|
+
it "knows its #ou" do
|
42
|
+
expect(example_certificate.ou).to eq example_ou
|
43
|
+
end
|
27
44
|
|
28
|
-
|
29
|
-
|
45
|
+
it "has no #uris" do
|
46
|
+
expect(example_certificate.uris).to be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has no #spiffe_id" do
|
50
|
+
expect(example_certificate.spiffe_id).to be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "knows its attributes" do
|
54
|
+
expect(example_certificate.attributes).to eq(cn: example_cn, ou: example_ou)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "compares certificate objects by comparing their certificates" do
|
58
|
+
second_cert = OpenSSL::X509::Certificate.new(cert_path("valid.crt").read)
|
59
|
+
second_certificate = described_class.new(second_cert)
|
60
|
+
|
61
|
+
expect(example_certificate).to be_eql second_certificate
|
62
|
+
end
|
30
63
|
end
|
31
64
|
|
32
|
-
|
33
|
-
|
34
|
-
|
65
|
+
describe "with extensions" do
|
66
|
+
describe "#[]" do
|
67
|
+
it "allows access to subject components via strings" do
|
68
|
+
expect(example_certificate_with_extension["CN"]).to eq example_cn
|
69
|
+
expect(example_certificate_with_extension["OU"]).to eq example_ou
|
70
|
+
end
|
35
71
|
|
36
|
-
|
72
|
+
it "allows access to subject components via symbols" do
|
73
|
+
expect(example_certificate_with_extension[:cn]).to eq example_cn
|
74
|
+
expect(example_certificate_with_extension[:ou]).to eq example_ou
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "knows its #cn" do
|
79
|
+
expect(example_certificate_with_extension.cn).to eq example_cn
|
80
|
+
end
|
81
|
+
|
82
|
+
it "knows its #dns_names" do
|
83
|
+
expect(example_certificate_with_extension.dns_names).to eq example_dns_names
|
84
|
+
end
|
85
|
+
|
86
|
+
it "knows its #ips" do
|
87
|
+
expect(example_certificate_with_extension.ips).to eq example_ips
|
88
|
+
end
|
89
|
+
|
90
|
+
it "knows its #ou" do
|
91
|
+
expect(example_certificate_with_extension.ou).to eq example_ou
|
92
|
+
end
|
93
|
+
|
94
|
+
it "knows its #spiffe_id" do
|
95
|
+
expect(example_certificate_with_extension.spiffe_id).to eq example_spiffe
|
96
|
+
end
|
97
|
+
|
98
|
+
it "knows its #uris" do
|
99
|
+
expect(example_certificate_with_extension.uris).to eq example_uris
|
100
|
+
end
|
101
|
+
|
102
|
+
it "knows its attributes" do
|
103
|
+
expected_attrs = {
|
104
|
+
cn: example_cn,
|
105
|
+
dns_names: example_dns_names,
|
106
|
+
ips: example_ips,
|
107
|
+
ou: example_ou,
|
108
|
+
spiffe_id: example_spiffe,
|
109
|
+
uris: example_uris
|
110
|
+
}
|
111
|
+
expect(example_certificate_with_extension.attributes).to eq(expected_attrs)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "compares certificate objects by comparing their certificates" do
|
115
|
+
second_cert = OpenSSL::X509::Certificate.new(cert_path("valid_with_ext.crt").read)
|
116
|
+
second_certificate = described_class.new(second_cert)
|
117
|
+
|
118
|
+
expect(example_certificate_with_extension).to be_eql second_certificate
|
119
|
+
end
|
37
120
|
end
|
38
121
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "logger"
|
2
4
|
|
3
5
|
RSpec.describe Rails::Auth::X509::Middleware do
|
@@ -49,10 +51,12 @@ RSpec.describe Rails::Auth::X509::Middleware do
|
|
49
51
|
|
50
52
|
let(:java_cert) do
|
51
53
|
ruby_cert = OpenSSL::X509::Certificate.new(valid_cert_pem)
|
52
|
-
Java::
|
54
|
+
input_stream = Java::JavaIO::ByteArrayInputStream.new(ruby_cert.to_der.to_java_bytes)
|
55
|
+
java_cert_klass = Java::JavaSecurityCert::CertificateFactory.getInstance("X.509")
|
56
|
+
java_cert_klass.generateCertificate(input_stream)
|
53
57
|
end
|
54
58
|
|
55
|
-
it "extracts Rails::Auth::Credential::X509 from a
|
59
|
+
it "extracts Rails::Auth::Credential::X509 from a java.security.cert.Certificate" do
|
56
60
|
skip "JRuby only" unless defined?(JRUBY_VERSION)
|
57
61
|
|
58
62
|
_response, env = middleware.call(request.merge(example_key => [java_cert]))
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Rails::Auth::X509::SubjectAltNameExtension do
|
4
|
+
let(:example_cert) { OpenSSL::X509::Certificate.new(cert_path("valid.crt").read) }
|
5
|
+
let(:example_cert_with_extension) { OpenSSL::X509::Certificate.new(cert_path("valid_with_ext.crt").read) }
|
6
|
+
let(:extension_for_cert) { described_class.new(example_cert) }
|
7
|
+
let(:extension_for_cert_with_san) { described_class.new(example_cert_with_extension) }
|
8
|
+
let(:example_dns_names) { %w[example.com exemplar.com somethingelse.com] }
|
9
|
+
let(:example_ips) { %w[0.0.0.0 127.0.0.1 192.168.1.1] }
|
10
|
+
let(:example_uris) { %w[spiffe://example.com/exemplar https://www.example.com/page1 https://www.example.com/page2] }
|
11
|
+
|
12
|
+
describe "for cert without extensions" do
|
13
|
+
it "returns no DNS names" do
|
14
|
+
expect(extension_for_cert.dns_names).to be_empty
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns no IPs" do
|
18
|
+
expect(extension_for_cert.ips).to be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns no URIs" do
|
22
|
+
expect(extension_for_cert.uris).to be_empty
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "for cert with extensions" do
|
27
|
+
it "knows its DNS names" do
|
28
|
+
expect(extension_for_cert_with_san.dns_names).to eq example_dns_names
|
29
|
+
end
|
30
|
+
|
31
|
+
it "knows its IPs" do
|
32
|
+
expect(extension_for_cert_with_san.ips).to eq example_ips
|
33
|
+
end
|
34
|
+
|
35
|
+
it "knows its URIs" do
|
36
|
+
expect(extension_for_cert_with_san.uris).to eq example_uris
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/rails/auth_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "coveralls"
|
2
4
|
Coveralls.wear!
|
3
5
|
|
4
|
-
$LOAD_PATH.unshift File.expand_path("
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
5
7
|
require "rails/auth"
|
6
8
|
require "rails/auth/rspec"
|
7
9
|
require "support/create_certs"
|
@@ -11,11 +13,11 @@ require "pathname"
|
|
11
13
|
RSpec.configure(&:disable_monkey_patching!)
|
12
14
|
|
13
15
|
def cert_path(name)
|
14
|
-
Pathname.new(File.expand_path("
|
16
|
+
Pathname.new(File.expand_path("../tmp/certs", __dir__)).join(name)
|
15
17
|
end
|
16
18
|
|
17
19
|
def fixture_path(*args)
|
18
|
-
Pathname.new(File.expand_path("
|
20
|
+
Pathname.new(File.expand_path("fixtures", __dir__)).join(*args)
|
19
21
|
end
|
20
22
|
|
21
23
|
def env_for(method, path, host = "127.0.0.1")
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "certificate_authority"
|
2
4
|
require "fileutils"
|
3
5
|
|
4
|
-
cert_path = File.expand_path("
|
6
|
+
cert_path = File.expand_path("../../tmp/certs", __dir__)
|
5
7
|
FileUtils.mkdir_p(cert_path)
|
6
8
|
|
7
9
|
#
|
@@ -15,7 +17,7 @@ ca.serial_number.number = 1
|
|
15
17
|
ca.key_material.generate_key
|
16
18
|
ca.signing_entity = true
|
17
19
|
|
18
|
-
ca.sign! "extensions" => { "keyUsage" => { "usage" => %w
|
20
|
+
ca.sign! "extensions" => { "keyUsage" => { "usage" => %w[critical keyCertSign] } }
|
19
21
|
|
20
22
|
ca_cert_path = File.join(cert_path, "ca.crt")
|
21
23
|
ca_key_path = File.join(cert_path, "ca.key")
|
@@ -41,6 +43,59 @@ valid_key_path = File.join(cert_path, "valid.key")
|
|
41
43
|
File.write valid_cert_path, valid_cert.to_pem
|
42
44
|
File.write valid_key_path, valid_cert.key_material.private_key.to_pem
|
43
45
|
|
46
|
+
#
|
47
|
+
# Valid client certificate with extensions
|
48
|
+
#
|
49
|
+
|
50
|
+
valid_cert_with_ext = CertificateAuthority::Certificate.new
|
51
|
+
valid_cert_with_ext.subject.common_name = "127.0.0.1"
|
52
|
+
valid_cert_with_ext.subject.organizational_unit = "ponycopter"
|
53
|
+
valid_cert_with_ext.serial_number.number = 3
|
54
|
+
valid_cert_with_ext.key_material.generate_key
|
55
|
+
signing_profile = {
|
56
|
+
"extensions" => {
|
57
|
+
"basicConstraints" => {
|
58
|
+
"ca" => false
|
59
|
+
},
|
60
|
+
"crlDistributionPoints" => {
|
61
|
+
"uri" => "http://notme.com/other.crl"
|
62
|
+
},
|
63
|
+
"subjectKeyIdentifier" => {},
|
64
|
+
"authorityKeyIdentifier" => {},
|
65
|
+
"authorityInfoAccess" => {
|
66
|
+
"ocsp" => %w[http://youFillThisOut/ocsp/]
|
67
|
+
},
|
68
|
+
"keyUsage" => {
|
69
|
+
"usage" => %w[digitalSignature keyEncipherment dataEncipherment]
|
70
|
+
},
|
71
|
+
"extendedKeyUsage" => {
|
72
|
+
"usage" => %w[serverAuth clientAuth]
|
73
|
+
},
|
74
|
+
"subjectAltName" => {
|
75
|
+
"uris" => %w[spiffe://example.com/exemplar https://www.example.com/page1 https://www.example.com/page2],
|
76
|
+
"ips" => %w[0.0.0.0 127.0.0.1 192.168.1.1],
|
77
|
+
"dns_names" => %w[example.com exemplar.com somethingelse.com]
|
78
|
+
},
|
79
|
+
"certificatePolicies" => {
|
80
|
+
"policy_identifier" => "1.3.5.8",
|
81
|
+
"cps_uris" => %w[http://my.host.name/ http://my.your.name/],
|
82
|
+
"user_notice" => {
|
83
|
+
"explicit_text" => "Explicit Text Here",
|
84
|
+
"organization" => "Organization name",
|
85
|
+
"notice_numbers" => "1,2,3,4"
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
valid_cert_with_ext.parent = ca
|
91
|
+
valid_cert_with_ext.sign!(signing_profile)
|
92
|
+
|
93
|
+
valid_cert_with_ext_path = File.join(cert_path, "valid_with_ext.crt")
|
94
|
+
valid_key_with_ext_path = File.join(cert_path, "valid_with_ext.key")
|
95
|
+
|
96
|
+
File.write valid_cert_with_ext_path, valid_cert_with_ext.to_pem
|
97
|
+
File.write valid_key_with_ext_path, valid_cert_with_ext.key_material.private_key.to_pem
|
98
|
+
|
44
99
|
#
|
45
100
|
# Create evil MitM self-signed certificate
|
46
101
|
#
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -28,16 +28,22 @@ dependencies:
|
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.10'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '3'
|
34
37
|
type: :development
|
35
38
|
prerelease: false
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
37
40
|
requirements:
|
38
|
-
- - "
|
41
|
+
- - ">="
|
39
42
|
- !ruby/object:Gem::Version
|
40
43
|
version: '1.10'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3'
|
41
47
|
- !ruby/object:Gem::Dependency
|
42
48
|
name: rake
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,6 +108,7 @@ files:
|
|
102
108
|
- lib/rails/auth/x509/filter/pem.rb
|
103
109
|
- lib/rails/auth/x509/matcher.rb
|
104
110
|
- lib/rails/auth/x509/middleware.rb
|
111
|
+
- lib/rails/auth/x509/subject_alt_name_extension.rb
|
105
112
|
- rails-auth.gemspec
|
106
113
|
- spec/fixtures/example_acl.yml
|
107
114
|
- spec/rails/auth/acl/matchers/allow_all_spec.rb
|
@@ -120,6 +127,7 @@ files:
|
|
120
127
|
- spec/rails/auth/x509/certificate_spec.rb
|
121
128
|
- spec/rails/auth/x509/matcher_spec.rb
|
122
129
|
- spec/rails/auth/x509/middleware_spec.rb
|
130
|
+
- spec/rails/auth/x509/subject_alt_name_extension_spec.rb
|
123
131
|
- spec/rails/auth_spec.rb
|
124
132
|
- spec/spec_helper.rb
|
125
133
|
- spec/support/claims_matcher.rb
|
@@ -137,15 +145,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
137
145
|
requirements:
|
138
146
|
- - ">="
|
139
147
|
- !ruby/object:Gem::Version
|
140
|
-
version: 2.
|
148
|
+
version: 2.3.0
|
141
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
150
|
requirements:
|
143
151
|
- - ">="
|
144
152
|
- !ruby/object:Gem::Version
|
145
153
|
version: '0'
|
146
154
|
requirements: []
|
147
|
-
|
148
|
-
rubygems_version: 2.4.8
|
155
|
+
rubygems_version: 3.0.3
|
149
156
|
signing_key:
|
150
157
|
specification_version: 4
|
151
158
|
summary: Modular resource-oriented authentication and authorization for Rails/Rack
|