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.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +14 -1
  3. data/.travis.yml +8 -5
  4. data/BUG-BOUNTY.md +3 -3
  5. data/CHANGES.md +21 -2
  6. data/CONTRIBUTING.md +11 -10
  7. data/Gemfile +6 -5
  8. data/Guardfile +2 -0
  9. data/Rakefile +3 -1
  10. data/lib/rails/auth/acl.rb +4 -0
  11. data/lib/rails/auth/acl/matchers/allow_all.rb +3 -0
  12. data/lib/rails/auth/acl/middleware.rb +3 -0
  13. data/lib/rails/auth/acl/resource.rb +7 -5
  14. data/lib/rails/auth/config_builder.rb +4 -0
  15. data/lib/rails/auth/controller_methods.rb +4 -0
  16. data/lib/rails/auth/credentials.rb +2 -0
  17. data/lib/rails/auth/credentials/injector_middleware.rb +6 -2
  18. data/lib/rails/auth/env.rb +4 -3
  19. data/lib/rails/auth/error_page/debug_middleware.rb +1 -1
  20. data/lib/rails/auth/error_page/middleware.rb +3 -0
  21. data/lib/rails/auth/exceptions.rb +2 -0
  22. data/lib/rails/auth/helpers.rb +2 -0
  23. data/lib/rails/auth/installed_constraint.rb +2 -0
  24. data/lib/rails/auth/monitor/middleware.rb +2 -0
  25. data/lib/rails/auth/rack.rb +1 -0
  26. data/lib/rails/auth/rspec.rb +2 -0
  27. data/lib/rails/auth/rspec/helper_methods.rb +6 -5
  28. data/lib/rails/auth/rspec/matchers/acl_matchers.rb +2 -0
  29. data/lib/rails/auth/version.rb +1 -1
  30. data/lib/rails/auth/x509/certificate.rb +35 -5
  31. data/lib/rails/auth/x509/filter/java.rb +4 -12
  32. data/lib/rails/auth/x509/filter/pem.rb +2 -0
  33. data/lib/rails/auth/x509/matcher.rb +2 -0
  34. data/lib/rails/auth/x509/middleware.rb +4 -3
  35. data/lib/rails/auth/x509/subject_alt_name_extension.rb +29 -0
  36. data/rails-auth.gemspec +5 -4
  37. data/spec/rails/auth/acl/matchers/allow_all_spec.rb +2 -0
  38. data/spec/rails/auth/acl/middleware_spec.rb +2 -0
  39. data/spec/rails/auth/acl/resource_spec.rb +2 -0
  40. data/spec/rails/auth/acl_spec.rb +2 -0
  41. data/spec/rails/auth/controller_methods_spec.rb +2 -0
  42. data/spec/rails/auth/credentials/injector_middleware_spec.rb +15 -0
  43. data/spec/rails/auth/credentials_spec.rb +2 -0
  44. data/spec/rails/auth/env_spec.rb +2 -0
  45. data/spec/rails/auth/error_page/debug_middleware_spec.rb +2 -0
  46. data/spec/rails/auth/error_page/middleware_spec.rb +2 -0
  47. data/spec/rails/auth/monitor/middleware_spec.rb +2 -0
  48. data/spec/rails/auth/rspec/helper_methods_spec.rb +2 -0
  49. data/spec/rails/auth/rspec/matchers/acl_matchers_spec.rb +2 -0
  50. data/spec/rails/auth/x509/certificate_spec.rb +103 -20
  51. data/spec/rails/auth/x509/matcher_spec.rb +2 -0
  52. data/spec/rails/auth/x509/middleware_spec.rb +6 -2
  53. data/spec/rails/auth/x509/subject_alt_name_extension_spec.rb +39 -0
  54. data/spec/rails/auth_spec.rb +2 -0
  55. data/spec/spec_helper.rb +5 -3
  56. data/spec/support/claims_matcher.rb +2 -0
  57. data/spec/support/create_certs.rb +57 -2
  58. metadata +14 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6d86f415a45113f3337b8446a3b5b271682c6a4d
4
- data.tar.gz: 79c560e82cb196908a94b836697398af20a04ad0
2
+ SHA256:
3
+ metadata.gz: c22c652d804b973313277d33b6c08dd0f3ae6389dfa0ebeaba73fd84488084b3
4
+ data.tar.gz: 95f4c1eab88b2ee3f8f608682690e70c8ca3a4c1b9925b537f14d33c88b91f7c
5
5
  SHA512:
6
- metadata.gz: b030ade8c37b4f91fba160037f8f951ce8729884dc18fd1d6d038464b7b8a9af10bb38934d1d1f4bdf8672ef66425555abf49e12af8c603e2bf80c5dbc7e03c6
7
- data.tar.gz: 0c0a1c9edd16819f0ab1ed10b5e98d734193fb14151586e2ab752088c706074fdb3d98cfa027635be16dc79bb7d3ec94c4f2e0be3de3f0252a3c0d0eb1fffab9
6
+ metadata.gz: a78bb6b55dd36517e9fd325f433210d3367d2aab18541507ac9feb607cdc92c4f2ce4b26df69bdd093c918b98bfc8c37c75add8ce572a0eb07025d96f2bc95f7
7
+ data.tar.gz: c5363dfa5f09bef450d827bdfa24226c4e080c47ff8c4b5c81da94192c834ac4d3fa97531d9dec11b5907949d249f59cf9856dd1b727f40d89b1ce2379ce60ac
@@ -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
- Style/ModuleFunction:
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
@@ -10,12 +10,15 @@ before_install:
10
10
  bundler_args: --without development
11
11
 
12
12
  rvm:
13
- - 2.0.0
14
- - 2.1.10
15
- - 2.2.4
16
- - 2.3.0
13
+ - 2.4
14
+ - 2.5
15
+ - 2.6
17
16
  matrix:
18
17
  include:
19
- - rvm: jruby-9.0.5.0
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
@@ -1,9 +1,9 @@
1
- Break me and win a prize!
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://hackerone.com/square-open-source
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
@@ -1,14 +1,15 @@
1
- ### Sign the CLA
1
+ # Contributing
2
2
 
3
- Any contributors to the master *rails-auth* repository must sign the
4
- [Individual Contributor License Agreement (CLA)]. It's a short form that covers
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
- ### Submitting a Pull Request
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
- When you have a change you'd like to see in the master repository, send a
10
- [pull request]. Before we merge your request, we'll make sure you're in the list
11
- of people who have signed a CLA.
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
- [Individual Contributor License Agreement (CLA)]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
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.38.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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  guard :rspec, cmd: "bundle exec rspec" do
2
4
  watch(%r{^spec/.+_spec\.rb$})
3
5
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
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(spec rubocop)
10
+ task default: %w[spec rubocop]
@@ -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(GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK).freeze
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(method path host).freeze
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".freeze])
62
- return false unless @path =~ env["PATH_INFO".freeze]
63
- return false unless @host.nil? || @host =~ env["HTTP_HOST".freeze]
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
- env[Rails::Auth::Env::CREDENTIALS_ENV_KEY] = @credentials
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
@@ -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".freeze
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".freeze
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".freeze
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
 
@@ -26,7 +26,7 @@ module Rails
26
26
 
27
27
  @app = app
28
28
  @acl = acl
29
- @erb = ERB.new(File.read(File.expand_path("../debug_page.html.erb", __FILE__))).freeze
29
+ @erb = ERB.new(File.read(File.expand_path("debug_page.html.erb", __dir__))).freeze
30
30
  end
31
31
 
32
32
  def call(env)
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Auth
3
5
  # Base class of all Rails::Auth errors
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  # Modular resource-based authentication and authorization for Rails/Rack
3
5
  module Auth
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Auth
3
5
  # Rails constraint to make sure the ACLs have been installed
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Auth
3
5
  module Monitor
@@ -27,3 +27,4 @@ require "rails/auth/x509/filter/pem"
27
27
  require "rails/auth/x509/filter/java" if defined?(JRUBY_VERSION)
28
28
  require "rails/auth/x509/matcher"
29
29
  require "rails/auth/x509/middleware"
30
+ require "rails/auth/x509/subject_alt_name_extension"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rails/auth/rspec/helper_methods"
2
4
  require "rails/auth/rspec/matchers/acl_matchers"
3
5
 
@@ -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 << "CN=#{cn}" if cn
28
- subject << "OU=#{ou}" if ou
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,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec::Matchers.define(:permit) do |env|
2
4
  description do
3
5
  method = env["REQUEST_METHOD"]
@@ -3,6 +3,6 @@
3
3
  module Rails
4
4
  # Pluggable authentication and authorization for Rack/Rails
5
5
  module Auth
6
- VERSION = "2.1.4".freeze
6
+ VERSION = "2.2.0"
7
7
  end
8
8
  end
@@ -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".freeze]
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".freeze]
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
- ou: ou
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
- require "java"
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 Java's sun.security.x509.X509CertImpl
7
+ # Extract OpenSSL::X509::Certificates from java.security.cert.Certificate
9
8
  class Java
10
9
  def call(certs)
11
- return unless certs
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
- def extract_der(cert)
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Auth
3
5
  module X509
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rails
2
4
  module Auth
3
5
  module X509
@@ -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".freeze, credential.freeze) if credential
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 => ex
76
- @logger.debug("rails-auth: Certificate error: #{ex.class}: #{ex.message}") if @logger
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
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
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.0.0"
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", "~> 1.10"
33
+ spec.add_development_dependency "bundler", ">= 1.10", "< 3"
33
34
  spec.add_development_dependency "rake", "~> 10.0"
34
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::ACL::Matchers::AllowAll do
2
4
  let(:matcher) { described_class.new(enabled) }
3
5
  let(:example_env) { env_for(:get, "/") }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "logger"
2
4
 
3
5
  RSpec.describe Rails::Auth::ACL::Middleware do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::ACL::Resource do
2
4
  let(:example_method) { "GET" }
3
5
  let(:another_method) { "POST" }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::ACL do
2
4
  let(:example_config) { fixture_path("example_acl.yml").read }
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::ControllerMethods do
2
4
  let(:controller_class) do
3
5
  Class.new do
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::Credentials do
2
4
  let(:rack_env) { Rack::MockRequest.env_for("https://www.example.com") }
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::Env do
2
4
  let(:rack_env) { Rack::MockRequest.env_for("https://www.example.com") }
3
5
  let(:example_authority) { "some-authority" }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::ErrorPage::DebugMiddleware do
2
4
  let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::ErrorPage::Middleware do
2
4
  let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
3
5
  let(:error_page) { "<h1> Unauthorized!!! </h1>" }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth::Monitor::Middleware do
2
4
  let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "ostruct"
2
4
 
3
5
  RSpec.describe Rails::Auth::RSpec::HelperMethods, acl_spec: true do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe "RSpec ACL matchers", acl_spec: true do
2
4
  let(:example_certificate) { x509_certificate_hash(ou: "ponycopter") }
3
5
  let(:another_certificate) { x509_certificate_hash(ou: "derpderp") }
@@ -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
- describe "#[]" do
9
- it "allows access to subject components via strings" do
10
- expect(example_certificate["CN"]).to eq example_cn
11
- expect(example_certificate["OU"]).to eq example_ou
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 "allows access to subject components via symbols" do
15
- expect(example_certificate[:cn]).to eq example_cn
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
- it "knows its #cn" do
21
- expect(example_certificate.cn).to eq example_cn
22
- end
33
+ it "has no #dns_names" do
34
+ expect(example_certificate.dns_names).to be_empty
35
+ end
23
36
 
24
- it "knows its #ou" do
25
- expect(example_certificate.ou).to eq example_ou
26
- end
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
- it "knows its attributes" do
29
- expect(example_certificate.attributes).to eq(cn: example_cn, ou: example_ou)
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
- it "compares certificate objects by comparing their certificates" do
33
- second_cert = OpenSSL::X509::Certificate.new(cert_path("valid.crt").read)
34
- second_certificate = described_class.new(second_cert)
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
- expect(example_certificate).to be_eql second_certificate
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
  RSpec.describe Rails::Auth::X509::Matcher do
2
4
  let(:example_cert) { OpenSSL::X509::Certificate.new(cert_path("valid.crt").read) }
3
5
  let(:example_certificate) { Rails::Auth::X509::Certificate.new(example_cert) }
@@ -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::SunSecurityX509::X509CertImpl.new(ruby_cert.to_der.to_java_bytes)
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 Java::SunSecurityX509::X509CertImpl" do
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Rails::Auth do
2
4
  it "has a version number" do
3
5
  expect(Rails::Auth::VERSION).not_to be nil
@@ -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("../../lib", __FILE__)
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("../../tmp/certs", __FILE__)).join(name)
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("../fixtures", __FILE__)).join(*args)
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,4 +1,6 @@
1
1
  # A strawman matcher for claims-based credentials for use in tests
2
+ # frozen_string_literal: true
3
+
2
4
  class ClaimsMatcher
3
5
  def initialize(options)
4
6
  @options = options
@@ -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("../../../tmp/certs", __FILE__)
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(critical keyCertSign) } }
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.1.4
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: 2018-07-17 00:00:00.000000000 Z
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.0.0
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
- rubyforge_project:
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