rails-auth 2.1.2 → 2.2.2
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 +45 -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 +5 -1
- data/lib/rails/auth/controller_methods.rb +4 -0
- data/lib/rails/auth/credentials.rb +3 -1
- 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 +3 -1
- 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 +4 -2
- 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 +10 -1
- data/lib/rails/auth/x509/matcher.rb +2 -0
- data/lib/rails/auth/x509/middleware.rb +11 -9
- 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 +12 -1
- 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 +13 -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
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,
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define(:permit) do |env|
|
2
4
|
description do
|
3
5
|
method = env["REQUEST_METHOD"]
|
4
6
|
credentials = Rails::Auth.credentials(env)
|
5
7
|
message = "allow #{method}s by "
|
6
8
|
|
7
|
-
return message
|
9
|
+
return message + "unauthenticated clients" if credentials.count.zero?
|
8
10
|
|
9
|
-
message
|
11
|
+
message + credentials.values.map(&:inspect).join(", ")
|
10
12
|
end
|
11
13
|
|
12
14
|
match { |acl| acl.match(env) }
|
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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rails
|
2
4
|
module Auth
|
3
5
|
module X509
|
@@ -5,7 +7,14 @@ module Rails
|
|
5
7
|
# Extract OpenSSL::X509::Certificates from Privacy Enhanced Mail (PEM) certificates
|
6
8
|
class Pem
|
7
9
|
def call(pem)
|
8
|
-
|
10
|
+
# Normalize the whitespace in the certificate to the exact format
|
11
|
+
# certificates are normally formatted in otherwise parsing with fail
|
12
|
+
# with a 'nested asn1 error'. split(" ") handles sequential whitespace
|
13
|
+
# characters like \t, \n, and space.
|
14
|
+
OpenSSL::X509::Certificate.new(pem.split(" ").instance_eval do
|
15
|
+
[[self[0], self[1]].join(" "), self[2...-2], [self[-2], self[-1]].join(" ")]
|
16
|
+
.flatten.join("\n")
|
17
|
+
end).freeze
|
9
18
|
end
|
10
19
|
end
|
11
20
|
end
|
@@ -12,20 +12,21 @@ module Rails
|
|
12
12
|
# Create a new X.509 Middleware object
|
13
13
|
#
|
14
14
|
# @param [Object] app next app in the Rack middleware chain
|
15
|
-
# @param [Hash] cert_filters maps Rack environment names to cert extractors
|
16
15
|
# @param [String] ca_file path to the CA bundle to verify client certs with
|
17
|
-
# @param [
|
16
|
+
# @param [Hash] cert_filters maps Rack environment names to cert extractors
|
17
|
+
# @param [Logger] logger place to log verification successes & failures
|
18
18
|
# @param [Boolean] require_cert causes middleware to raise if certs are unverified
|
19
|
+
# @param [OpenSSL::X509::Store] truststore (optional) provide your own truststore (for e.g. CRLs)
|
19
20
|
#
|
20
21
|
# @return [Rails::Auth::X509::Middleware] new X509 middleware instance
|
21
|
-
def initialize(app,
|
22
|
-
raise ArgumentError, "no ca_file given" unless ca_file
|
22
|
+
def initialize(app, ca_file: nil, cert_filters: {}, logger: nil, require_cert: false, truststore: nil)
|
23
|
+
raise ArgumentError, "no ca_file or truststore given" unless ca_file || truststore
|
23
24
|
|
24
25
|
@app = app
|
26
|
+
@cert_filters = cert_filters
|
25
27
|
@logger = logger
|
26
|
-
@truststore = truststore || OpenSSL::X509::Store.new.add_file(ca_file)
|
27
28
|
@require_cert = require_cert
|
28
|
-
@
|
29
|
+
@truststore = truststore || OpenSSL::X509::Store.new.add_file(ca_file)
|
29
30
|
|
30
31
|
@cert_filters.each do |key, filter|
|
31
32
|
next unless filter.is_a?(Symbol)
|
@@ -40,7 +41,7 @@ module Rails
|
|
40
41
|
|
41
42
|
def call(env)
|
42
43
|
credential = extract_credential(env)
|
43
|
-
Rails::Auth.add_credential(env, "x509"
|
44
|
+
Rails::Auth.add_credential(env, "x509", credential.freeze) if credential
|
44
45
|
|
45
46
|
@app.call(env)
|
46
47
|
end
|
@@ -62,6 +63,7 @@ module Rails
|
|
62
63
|
end
|
63
64
|
|
64
65
|
raise CertificateVerifyFailed, "no client certificate in request" if @require_cert
|
66
|
+
|
65
67
|
nil
|
66
68
|
end
|
67
69
|
|
@@ -72,8 +74,8 @@ module Rails
|
|
72
74
|
end
|
73
75
|
|
74
76
|
filter.call(raw_cert)
|
75
|
-
rescue =>
|
76
|
-
@logger.debug("rails-auth: Certificate error: #{
|
77
|
+
rescue StandardError => e
|
78
|
+
@logger.debug("rails-auth: Certificate error: #{e.class}: #{e.message}") if @logger
|
77
79
|
nil
|
78
80
|
end
|
79
81
|
|
@@ -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,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe "RSpec ACL matchers", acl_spec: true do
|
2
|
-
let(:example_certificate) { x509_certificate_hash(ou: "ponycopter") }
|
3
4
|
let(:another_certificate) { x509_certificate_hash(ou: "derpderp") }
|
5
|
+
let(:example_certificate) { x509_certificate_hash(ou: "ponycopter") }
|
4
6
|
|
5
7
|
subject do
|
6
8
|
Rails::Auth::ACL.from_yaml(
|
@@ -16,5 +18,14 @@ RSpec.describe "RSpec ACL matchers", acl_spec: true do
|
|
16
18
|
it { is_expected.to permit get_request(credentials: example_certificate) }
|
17
19
|
it { is_expected.not_to permit get_request(credentials: another_certificate) }
|
18
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
|
19
30
|
end
|
20
31
|
end
|
@@ -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
|