rails-auth 2.2.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c22c652d804b973313277d33b6c08dd0f3ae6389dfa0ebeaba73fd84488084b3
4
- data.tar.gz: 95f4c1eab88b2ee3f8f608682690e70c8ca3a4c1b9925b537f14d33c88b91f7c
3
+ metadata.gz: ebb7b8700e3c8719cdb65a37efa8e1234b79a35a43fba6dffcb9d427cbf9e2e7
4
+ data.tar.gz: 46e21ea3735dde1cf16c1242ca1117288bce5a4c4ef5cf0f3669e890fecc5124
5
5
  SHA512:
6
- metadata.gz: a78bb6b55dd36517e9fd325f433210d3367d2aab18541507ac9feb607cdc92c4f2ce4b26df69bdd093c918b98bfc8c37c75add8ce572a0eb07025d96f2bc95f7
7
- data.tar.gz: c5363dfa5f09bef450d827bdfa24226c4e080c47ff8c4b5c81da94192c834ac4d3fa97531d9dec11b5907949d249f59cf9856dd1b727f40d89b1ce2379ce60ac
6
+ metadata.gz: fcec7e972d73c52fdcaeef22da67dee25849efaddbf254964b3e73f5179e849ef1bd32e80c1f6520f5502884f27811c0b6bb66278923da67320b38cdfd42464b
7
+ data.tar.gz: 12a93fbdbfc37c44da69bdbb8b163554dd145364627fb689b5acc530a4ec176f6ac5ee2fa0b502ab594a998ce0fad8664e111aafdd268e0f04571f942d9ce6e1
@@ -0,0 +1,31 @@
1
+ name: CI - JRuby
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ java-version:
15
+ - 8
16
+ - 11
17
+
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+ - name: Set up Java
21
+ uses: actions/setup-java@v2
22
+ with:
23
+ distribution: temurin
24
+ java-version: ${{ matrix.java-version }}
25
+ - name: Set up Ruby
26
+ uses: ruby/setup-ruby@v1
27
+ with:
28
+ bundler-cache: true
29
+ ruby-version: jruby
30
+ - name: Run tests
31
+ run: bundle exec rake
@@ -0,0 +1,27 @@
1
+ name: CI - MRI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version:
15
+ - 2.6
16
+ - 2.7
17
+ - 3.0
18
+
19
+ steps:
20
+ - uses: actions/checkout@v2
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ bundler-cache: true
25
+ ruby-version: ${{ matrix.ruby-version }}
26
+ - name: Run tests
27
+ run: bundle exec rake
data/CHANGES.md CHANGED
@@ -1,3 +1,33 @@
1
+ ### 3.1.0 (2021-10-26)
2
+
3
+ * [#70](https://github.com/square/rails-auth/pull/70)
4
+ Support URL-encoded PEMs to support new Puma header requirements.
5
+ ([@drcapulet])
6
+
7
+ ### 3.0.0 (2020-08-10)
8
+
9
+ * [#68](https://github.com/square/rails-auth/pull/68)
10
+ Remove `ca_file` and `require_cert` options to the config builder as we no
11
+ longer verify the certificate chain.
12
+ ([@drcapulet])
13
+
14
+ * [#67](https://github.com/square/rails-auth/pull/67)
15
+ Remove `ca_file`, `require_cert`, and `truststore` options to X509 middleware
16
+ as we no longer verify the certificate chain.
17
+ ([@drcapulet])
18
+
19
+ ### 2.2.2 (2020-07-02)
20
+
21
+ * [#65](https://github.com/square/rails-auth/pull/65)
22
+ Fix error when passing `truststore` instead of `ca_file` to X509 middleware.
23
+ ([@drcapulet])
24
+
25
+ ### 2.2.1 (2020-01-08)
26
+
27
+ * [#63](https://github.com/square/rails-auth/pull/63)
28
+ Fix `FrozenError` in `permit` matcher description.
29
+ ([@drcapulet])
30
+
1
31
  ### 2.2.0 (2019-12-05)
2
32
 
3
33
  * [#55](https://github.com/square/rails-auth/pull/55)
@@ -31,22 +31,15 @@ module Rails
31
31
  def production(
32
32
  config,
33
33
  cert_filters: nil,
34
- require_cert: false,
35
- ca_file: nil,
36
34
  error_page: Rails.root.join("public/403.html"),
37
35
  monitor: nil
38
36
  )
39
- raise ArgumentError, "no cert_filters given but require_cert is true" if require_cert && !cert_filters
40
- raise ArgumentError, "no ca_file given but cert_filters were set" if cert_filters && !ca_file
41
-
42
37
  error_page_middleware(config, error_page)
43
38
 
44
39
  if cert_filters
45
40
  config.middleware.insert_before Rails::Auth::ACL::Middleware,
46
41
  Rails::Auth::X509::Middleware,
47
- require_cert: require_cert,
48
42
  cert_filters: cert_filters,
49
- ca_file: ca_file,
50
43
  logger: Rails.logger
51
44
  end
52
45
 
@@ -24,6 +24,7 @@ require "rails/auth/monitor/middleware"
24
24
 
25
25
  require "rails/auth/x509/certificate"
26
26
  require "rails/auth/x509/filter/pem"
27
+ require "rails/auth/x509/filter/pem_urlencoded"
27
28
  require "rails/auth/x509/filter/java" if defined?(JRUBY_VERSION)
28
29
  require "rails/auth/x509/matcher"
29
30
  require "rails/auth/x509/middleware"
@@ -6,9 +6,9 @@ RSpec::Matchers.define(:permit) do |env|
6
6
  credentials = Rails::Auth.credentials(env)
7
7
  message = "allow #{method}s by "
8
8
 
9
- return message << "unauthenticated clients" if credentials.count.zero?
9
+ return message + "unauthenticated clients" if credentials.count.zero?
10
10
 
11
- message << credentials.values.map(&:inspect).join(", ")
11
+ message + credentials.values.map(&:inspect).join(", ")
12
12
  end
13
13
 
14
14
  match { |acl| acl.match(env) }
@@ -3,6 +3,6 @@
3
3
  module Rails
4
4
  # Pluggable authentication and authorization for Rack/Rails
5
5
  module Auth
6
- VERSION = "2.2.0"
6
+ VERSION = "3.1.0"
7
7
  end
8
8
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Auth
5
+ module X509
6
+ module Filter
7
+ # Extract OpenSSL::X509::Certificates from Privacy Enhanced Mail (PEM) certificates
8
+ # that are URL encoded ($ssl_client_escaped_cert from Nginx).
9
+ class PemUrlencoded < Pem
10
+ def call(encoded_pem)
11
+ super(URI.decode_www_form_component(encoded_pem))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -3,29 +3,20 @@
3
3
  module Rails
4
4
  module Auth
5
5
  module X509
6
- # Raised when certificate verification is mandatory
7
- CertificateVerifyFailed = Class.new(NotAuthorizedError)
8
-
9
- # Validates X.509 client certificates and adds credential objects for valid
10
- # clients to the rack environment as env["rails-auth.credentials"]["x509"]
6
+ # Extracts X.509 client certificates and adds credential objects to the
7
+ # rack environment as env["rails-auth.credentials"]["x509"]
11
8
  class Middleware
12
9
  # Create a new X.509 Middleware object
13
10
  #
14
- # @param [Object] app next app in the Rack middleware chain
15
- # @param [Hash] cert_filters maps Rack environment names to cert extractors
16
- # @param [String] ca_file path to the CA bundle to verify client certs with
17
- # @param [OpenSSL::X509::Store] truststore (optional) provide your own truststore (for e.g. CRLs)
18
- # @param [Boolean] require_cert causes middleware to raise if certs are unverified
11
+ # @param [Object] app next app in the Rack middleware chain
12
+ # @param [Hash] cert_filters maps Rack environment names to cert extractors
13
+ # @param [Logger] logger place to log certificate extraction issues
19
14
  #
20
15
  # @return [Rails::Auth::X509::Middleware] new X509 middleware instance
21
- def initialize(app, cert_filters: {}, ca_file: nil, truststore: nil, require_cert: false, logger: nil)
22
- raise ArgumentError, "no ca_file given" unless ca_file
23
-
16
+ def initialize(app, cert_filters: {}, logger: nil)
24
17
  @app = app
25
- @logger = logger
26
- @truststore = truststore || OpenSSL::X509::Store.new.add_file(ca_file)
27
- @require_cert = require_cert
28
18
  @cert_filters = cert_filters
19
+ @logger = logger
29
20
 
30
21
  @cert_filters.each do |key, filter|
31
22
  next unless filter.is_a?(Symbol)
@@ -52,17 +43,9 @@ module Rails
52
43
  cert = extract_certificate_with_filter(filter, env[key])
53
44
  next unless cert
54
45
 
55
- if @truststore.verify(cert)
56
- log("Verified", cert)
57
- return Rails::Auth::X509::Certificate.new(cert)
58
- else
59
- log("Verify FAILED", cert)
60
- raise CertificateVerifyFailed, "verify failed: #{subject(cert)}" if @require_cert
61
- end
46
+ return Rails::Auth::X509::Certificate.new(cert)
62
47
  end
63
48
 
64
- raise CertificateVerifyFailed, "no client certificate in request" if @require_cert
65
-
66
49
  nil
67
50
  end
68
51
 
@@ -78,10 +61,6 @@ module Rails
78
61
  nil
79
62
  end
80
63
 
81
- def log(message, cert)
82
- @logger.debug("rails-auth: #{message} (#{subject(cert)})") if @logger
83
- end
84
-
85
64
  def subject(cert)
86
65
  cert.subject.to_a.map { |attr, data| "#{attr}=#{data}" }.join(",")
87
66
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe "RSpec ACL matchers", acl_spec: true do
4
- let(:example_certificate) { x509_certificate_hash(ou: "ponycopter") }
5
4
  let(:another_certificate) { x509_certificate_hash(ou: "derpderp") }
5
+ let(:example_certificate) { x509_certificate_hash(ou: "ponycopter") }
6
6
 
7
7
  subject do
8
8
  Rails::Auth::ACL.from_yaml(
@@ -18,5 +18,14 @@ RSpec.describe "RSpec ACL matchers", acl_spec: true do
18
18
  it { is_expected.to permit get_request(credentials: example_certificate) }
19
19
  it { is_expected.not_to permit get_request(credentials: another_certificate) }
20
20
  it { is_expected.not_to permit get_request }
21
+
22
+ it "has the correct description" do
23
+ expect(permit(get_request(credentials: example_certificate)).description)
24
+ .to eq('allow GETs by #<InstanceDouble(Rails::Auth::X509::Certificate) "OU=ponycopter">')
25
+ expect(permit(get_request(credentials: another_certificate)).description)
26
+ .to eq('allow GETs by #<InstanceDouble(Rails::Auth::X509::Certificate) "OU=derpderp">')
27
+ expect(permit(get_request).description)
28
+ .to eq("allow GETs by unauthenticated clients")
29
+ end
21
30
  end
22
31
  end
@@ -3,41 +3,32 @@
3
3
  require "logger"
4
4
 
5
5
  RSpec.describe Rails::Auth::X509::Middleware do
6
- let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
7
6
  let(:app) { ->(env) { [200, env, "Hello, world!"] } }
7
+ let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
8
8
 
9
- let(:valid_cert_pem) { cert_path("valid.crt").read }
10
- let(:bad_cert_pem) { cert_path("invalid.crt").read }
11
- let(:cert_required) { false }
12
- let(:cert_filter) { :pem }
13
- let(:example_key) { "X-SSL-Client-Cert" }
9
+ let(:cert_filter) { :pem }
10
+ let(:cert_pem) { cert_path("valid.crt").read }
11
+ let(:example_key) { "X-SSL-Client-Cert" }
14
12
 
15
13
  let(:middleware) do
16
14
  described_class.new(
17
15
  app,
18
- logger: Logger.new(STDERR),
19
- ca_file: cert_path("ca.crt").to_s,
20
16
  cert_filters: { example_key => cert_filter },
21
- require_cert: cert_required
17
+ logger: Logger.new(STDERR)
22
18
  )
23
19
  end
24
20
 
25
21
  context "certificate types" do
26
22
  describe "PEM certificates" do
27
23
  it "extracts Rails::Auth::X509::Certificate from a PEM certificate in the Rack environment" do
28
- _response, env = middleware.call(request.merge(example_key => valid_cert_pem))
24
+ _response, env = middleware.call(request.merge(example_key => cert_pem))
29
25
 
30
26
  credential = Rails::Auth.credentials(env).fetch("x509")
31
27
  expect(credential).to be_a Rails::Auth::X509::Certificate
32
28
  end
33
29
 
34
- it "ignores unverified certificates" do
35
- _response, env = middleware.call(request.merge(example_key => bad_cert_pem))
36
- expect(Rails::Auth.credentials(env)).to be_empty
37
- end
38
-
39
30
  it "normalizes abnormal whitespace" do
40
- _response, env = middleware.call(request.merge(example_key => valid_cert_pem.tr("\n", "\t")))
31
+ _response, env = middleware.call(request.merge(example_key => cert_pem.tr("\n", "\t")))
41
32
 
42
33
  credential = Rails::Auth.credentials(env).fetch("x509")
43
34
  expect(credential).to be_a Rails::Auth::X509::Certificate
@@ -46,11 +37,11 @@ RSpec.describe Rails::Auth::X509::Middleware do
46
37
 
47
38
  # :nocov:
48
39
  describe "Java certificates" do
49
- let(:example_key) { "javax.servlet.request.X509Certificate" }
50
40
  let(:cert_filter) { :java }
41
+ let(:example_key) { "javax.servlet.request.X509Certificate" }
51
42
 
52
43
  let(:java_cert) do
53
- ruby_cert = OpenSSL::X509::Certificate.new(valid_cert_pem)
44
+ ruby_cert = OpenSSL::X509::Certificate.new(cert_pem)
54
45
  input_stream = Java::JavaIO::ByteArrayInputStream.new(ruby_cert.to_der.to_java_bytes)
55
46
  java_cert_klass = Java::JavaSecurityCert::CertificateFactory.getInstance("X.509")
56
47
  java_cert_klass.generateCertificate(input_stream)
@@ -67,21 +58,4 @@ RSpec.describe Rails::Auth::X509::Middleware do
67
58
  end
68
59
  # :nocov:
69
60
  end
70
-
71
- describe "require_cert: true" do
72
- let(:cert_required) { true }
73
-
74
- it "functions normally for valid certificates" do
75
- _response, env = middleware.call(request.merge(example_key => valid_cert_pem))
76
-
77
- credential = Rails::Auth.credentials(env).fetch("x509")
78
- expect(credential).to be_a Rails::Auth::X509::Certificate
79
- end
80
-
81
- it "raises Rails::Auth::X509::CertificateVerifyFailed for unverified certificates" do
82
- expect do
83
- middleware.call(request.merge(example_key => bad_cert_pem))
84
- end.to raise_error Rails::Auth::X509::CertificateVerifyFailed
85
- end
86
- end
87
61
  end
@@ -95,20 +95,3 @@ valid_key_with_ext_path = File.join(cert_path, "valid_with_ext.key")
95
95
 
96
96
  File.write valid_cert_with_ext_path, valid_cert_with_ext.to_pem
97
97
  File.write valid_key_with_ext_path, valid_cert_with_ext.key_material.private_key.to_pem
98
-
99
- #
100
- # Create evil MitM self-signed certificate
101
- #
102
-
103
- self_signed_cert = CertificateAuthority::Certificate.new
104
- self_signed_cert.subject.common_name = "127.0.0.1"
105
- self_signed_cert.subject.organizational_unit = "ponycopter"
106
- self_signed_cert.serial_number.number = 2
107
- self_signed_cert.key_material.generate_key
108
- self_signed_cert.sign!
109
-
110
- self_signed_cert_path = File.join(cert_path, "invalid.crt")
111
- self_signed_key_path = File.join(cert_path, "invalid.key")
112
-
113
- File.write self_signed_cert_path, self_signed_cert.to_pem
114
- File.write self_signed_key_path, self_signed_cert.key_material.private_key.to_pem
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.2.0
4
+ version: 3.1.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: 2019-12-05 00:00:00.000000000 Z
11
+ date: 2021-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -67,10 +67,11 @@ executables: []
67
67
  extensions: []
68
68
  extra_rdoc_files: []
69
69
  files:
70
+ - ".github/workflows/jruby.yml"
71
+ - ".github/workflows/mri.yml"
70
72
  - ".gitignore"
71
73
  - ".rspec"
72
74
  - ".rubocop.yml"
73
- - ".travis.yml"
74
75
  - BUG-BOUNTY.md
75
76
  - CHANGES.md
76
77
  - CONDUCT.md
@@ -106,6 +107,7 @@ files:
106
107
  - lib/rails/auth/x509/certificate.rb
107
108
  - lib/rails/auth/x509/filter/java.rb
108
109
  - lib/rails/auth/x509/filter/pem.rb
110
+ - lib/rails/auth/x509/filter/pem_urlencoded.rb
109
111
  - lib/rails/auth/x509/matcher.rb
110
112
  - lib/rails/auth/x509/middleware.rb
111
113
  - lib/rails/auth/x509/subject_alt_name_extension.rb
@@ -152,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
154
  - !ruby/object:Gem::Version
153
155
  version: '0'
154
156
  requirements: []
155
- rubygems_version: 3.0.3
157
+ rubygems_version: 3.1.6
156
158
  signing_key:
157
159
  specification_version: 4
158
160
  summary: Modular resource-oriented authentication and authorization for Rails/Rack
data/.travis.yml DELETED
@@ -1,24 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- branches:
4
- only:
5
- - master
6
-
7
- before_install:
8
- - gem install bundler
9
-
10
- bundler_args: --without development
11
-
12
- rvm:
13
- - 2.4
14
- - 2.5
15
- - 2.6
16
- matrix:
17
- include:
18
- - rvm: jruby
19
- jdk: openjdk8
20
- env: JRUBY_OPTS="--debug" # for simplecov
21
- - rvm: jruby
22
- jdk: openjdk11
23
- env: JRUBY_OPTS="--debug" # for simplecov
24
- fast_finish: true