Commit ba799de
Changed files (6)
lib/saml/kit/certificate.rb
@@ -0,0 +1,52 @@
+module Saml
+ module Kit
+ class Certificate
+ attr_reader :value, :use
+
+ def initialize(value, use:)
+ @value = value
+ @use = use.downcase.to_sym
+ end
+
+ def fingerprint
+ Fingerprint.new(value)
+ end
+
+ def for?(use)
+ self.use == use.to_sym
+ end
+
+ def encryption?
+ :encryption == use
+ end
+
+ def signing?
+ :signing == use
+ end
+
+ def x509
+ OpenSSL::X509::Certificate.new(Base64.decode64(value))
+ end
+
+ def public_key
+ x509.public_key
+ end
+
+ def ==(other)
+ self.to_s == other.to_s
+ end
+
+ def eql?(other)
+ self == other
+ end
+
+ def hash
+ value.hash
+ end
+
+ def to_s
+ value
+ end
+ end
+ end
+end
lib/saml/kit/metadata.rb
@@ -30,20 +30,16 @@ module Saml
def certificates
@certificates ||= document.find_all("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
cert = item.at_xpath("./ds:KeyInfo/ds:X509Data/ds:X509Certificate", Xml::NAMESPACES).text
- {
- text: cert,
- fingerprint: Fingerprint.new(cert).algorithm(hash_algorithm),
- use: item.attribute('use').value.to_sym,
- }
+ Certificate.new(cert, use: item.attribute('use').value.to_sym)
end
end
def encryption_certificates
- certificates.find_all { |x| x[:use] == :encryption }
+ certificates.find_all(&:encryption?)
end
def signing_certificates
- certificates.find_all { |x| x[:use] == :signing }
+ certificates.find_all(&:signing?)
end
def services(type)
@@ -68,12 +64,8 @@ module Saml
end
def matches?(fingerprint, use: :signing)
- if :signing == use.to_sym
- hash_value = fingerprint.algorithm(hash_algorithm)
- signing_certificates.find do |signing_certificate|
- Saml::Kit.logger.debug [hash_value, signing_certificate[:fingerprint]].inspect
- hash_value == signing_certificate[:fingerprint]
- end
+ certificates.find do |certificate|
+ certificate.for?(use) && certificate.fingerprint == fingerprint
end
end
@@ -91,9 +83,7 @@ module Saml
def verify(algorithm, signature, data)
signing_certificates.find do |cert|
- x509 = OpenSSL::X509::Certificate.new(Base64.decode64(cert[:text]))
- public_key = x509.public_key
- public_key.verify(algorithm, signature, data)
+ cert.public_key.verify(algorithm, signature, data)
end
end
lib/saml/kit.rb
@@ -23,6 +23,7 @@ require "saml/kit/document"
require "saml/kit/authentication_request"
require "saml/kit/bindings"
+require "saml/kit/certificate"
require "saml/kit/configuration"
require "saml/kit/crypto"
require "saml/kit/cryptography"
spec/saml/certificate_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+RSpec.describe Saml::Kit::Certificate do
+ subject { described_class.new(Saml::Kit.configuration.stripped_signing_certificate, use: :signing) }
+
+ describe "#fingerprint" do
+ it 'returns a fingerprint' do
+ expect(subject.fingerprint).to be_instance_of(Saml::Kit::Fingerprint)
+ end
+ end
+end
spec/saml/identity_provider_metadata_spec.rb
@@ -21,7 +21,8 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
it { expect(subject.single_logout_services).to be_empty }
it do
fingerprint = "9F:74:13:3B:BC:5A:7B:8B:2D:4F:8B:EF:1E:88:EB:D1:AE:BC:19:BF:CA:19:C6:2F:0F:4B:31:1D:68:98:B0:1B"
- expect(subject.certificates).to match_array([use: :signing, text: certificate, fingerprint: fingerprint])
+ expect(subject.certificates).to match_array([Saml::Kit::Certificate.new(certificate, use: :signing)])
+ expect(subject.certificates.first.fingerprint.to_s).to eql(fingerprint)
end
it { expect(subject.attributes).to be_empty }
end
@@ -60,8 +61,8 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
end
it do
expect(subject.certificates).to match_array([
- { use: :signing, text: signing_certificate, fingerprint: "BE:12:70:84:AD:99:6A:58:28:2A:BC:DA:AB:E8:51:D3:FF:AB:58:30:E0:77:DB:23:57:15:01:B3:86:60:97:80" },
- { use: :encryption, text: encryption_certificate, fingerprint: "5C:51:0C:8A:6A:02:24:3C:9E:96:96:18:2E:37:65:8F:CC:EA:51:0E:2C:C5:3F:1D:72:47:11:D0:7B:95:26:1F" },
+ Saml::Kit::Certificate.new(signing_certificate, use: :signing),
+ Saml::Kit::Certificate.new(encryption_certificate, use: :encryption),
])
end
it { expect(subject.attributes).to be_present }
spec/saml/service_provider_metadata_spec.rb
@@ -10,20 +10,6 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
describe described_class::Builder do
let(:acs_url) { FFaker::Internet.http_url }
- <<-XML
-<?xml version="1.0" encoding="UTF-8"?>
-<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
- ID="_a94ad660-23cc-4491-8fe0-1429b7f5a6d8"
- entityID="https://service.dev/metadata">
- <md:SPSSODescriptor
- AuthnRequestsSigned="true"
- WantAssertionsSigned="true"
- protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
- <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
- <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://service.dev/acs" index="0" isDefault="true"/>
- </md:SPSSODescriptor>
-</md:EntityDescriptor>
- XML
it 'builds the service provider metadata' do
subject.entity_id = entity_id
subject.add_assertion_consumer_service(acs_url, binding: :http_post)
@@ -70,19 +56,9 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
end
it 'returns each of the certificates' do
- expected_sha256 = OpenSSL::Digest::SHA256.new.hexdigest(Saml::Kit.configuration.signing_x509.to_der)
- expected_encryption_sha256 = OpenSSL::Digest::SHA256.new.hexdigest(Saml::Kit.configuration.encryption_x509.to_der)
expect(subject.certificates).to match_array([
- {
- fingerprint: expected_sha256.upcase.scan(/../).join(":"),
- use: :signing,
- text: Saml::Kit.configuration.stripped_signing_certificate
- },
- {
- fingerprint: expected_encryption_sha256.upcase.scan(/../).join(":"),
- use: :encryption,
- text: Saml::Kit.configuration.stripped_encryption_certificate
- },
+ Saml::Kit::Certificate.new(Saml::Kit.configuration.stripped_signing_certificate, use: :signing),
+ Saml::Kit::Certificate.new(Saml::Kit.configuration.stripped_encryption_certificate, use: :encryption),
])
end