Skip to content

Commit e6ebb72

Browse files
committed
Add fingerprint algorithm support
1 parent a31b3e1 commit e6ebb72

File tree

5 files changed

+56
-9
lines changed

5 files changed

+56
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def saml_settings
116116
settings.idp_sso_target_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
117117
settings.idp_slo_target_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
118118
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
119+
settings.idp_cert_fingerprint_alg = "http://www.w3.org/2000/09/xmldsig#sha1"
119120
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
120121
121122
# Optional for most SAML IdPs

lib/onelogin/ruby-saml/response.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def validate(soft = true)
140140
validate_response_state(soft) &&
141141
validate_conditions(soft) &&
142142
validate_issuer(soft) &&
143-
document.validate_document(get_fingerprint, soft) &&
143+
document.validate_document(get_fingerprint, soft, :fingerprint_alg => settings.idp_cert_fingerprint_alg) &&
144144
validate_success_status(soft)
145145
end
146146

@@ -203,7 +203,8 @@ def xpath_first_from_signed_assertion(subelt=nil)
203203
def get_fingerprint
204204
if settings.idp_cert
205205
cert = OpenSSL::X509::Certificate.new(settings.idp_cert)
206-
Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(":")
206+
fingerprint_alg = XMLSecurity::BaseDocument.new.algorithm(settings.idp_cert_fingerprint_alg).new
207+
fingerprint_alg.hexdigest(cert.to_der).upcase.scan(/../).join(":")
207208
else
208209
settings.idp_cert_fingerprint
209210
end

lib/onelogin/ruby-saml/settings.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def initialize(overrides = {})
2323
attr_accessor :idp_slo_target_url
2424
attr_accessor :idp_cert
2525
attr_accessor :idp_cert_fingerprint
26+
attr_accessor :idp_cert_fingerprint_alg
2627
# SP Data
2728
attr_accessor :issuer
2829
attr_accessor :assertion_consumer_service_url
@@ -106,6 +107,7 @@ def get_sp_key
106107
DEFAULTS = {
107108
:assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST".freeze,
108109
:single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze,
110+
:idp_cert_fingerprint_alg => XMLSecurity::Document::SHA1,
109111
:compress_request => true,
110112
:compress_response => true,
111113
:security => {

lib/xml_security.rb

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def initialize(response, errors = [])
182182
extract_signed_element_id
183183
end
184184

185-
def validate_document(idp_cert_fingerprint, soft = true)
185+
def validate_document(idp_cert_fingerprint, soft = true, options = {})
186186
# get cert from response
187187
cert_element = REXML::XPath.first(self, "//ds:X509Certificate", { "ds"=>DSIG })
188188
unless cert_element
@@ -192,13 +192,18 @@ def validate_document(idp_cert_fingerprint, soft = true)
192192
raise OneLogin::RubySaml::ValidationError.new("Certificate element missing in response (ds:X509Certificate)")
193193
end
194194
end
195-
base64_cert = cert_element.text
196-
cert_text = Base64.decode64(base64_cert)
197-
cert = OpenSSL::X509::Certificate.new(cert_text)
195+
base64_cert = cert_element.text
196+
cert_text = Base64.decode64(base64_cert)
197+
cert = OpenSSL::X509::Certificate.new(cert_text)
198198

199-
# check cert matches registered idp cert
200-
fingerprint = Digest::SHA1.hexdigest(cert.to_der)
199+
if options[:fingerprint_alg]
200+
fingerprint_alg = XMLSecurity::BaseDocument.new.algorithm(options[:fingerprint_alg]).new
201+
else
202+
fingerprint_alg = OpenSSL::Digest::SHA1.new
203+
end
204+
fingerprint = fingerprint_alg.hexdigest(cert.to_der)
201205

206+
# check cert matches registered idp cert
202207
if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
203208
@errors << "Fingerprint mismatch"
204209
return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Fingerprint mismatch"))

test/xml_security_test.rb

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,45 @@ class XmlSecurityTest < Minitest::Test
7878
end
7979
end
8080

81-
describe "Algorithms" do
81+
describe "Fingerprint Algorithms" do
82+
let(:response_fingerprint_test) { OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha1, false)) }
83+
84+
it "validate using SHA1" do
85+
sha1_fingerprint = "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72"
86+
sha1_fingerprint_downcase = "f13c6b80905a030e6c913e5d15faddb016454872"
87+
88+
assert response_fingerprint_test.document.validate_document(sha1_fingerprint)
89+
assert response_fingerprint_test.document.validate_document(sha1_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA1)
90+
91+
assert response_fingerprint_test.document.validate_document(sha1_fingerprint_downcase)
92+
assert response_fingerprint_test.document.validate_document(sha1_fingerprint_downcase, true, :fingerprint_alg => XMLSecurity::Document::SHA1)
93+
sha1_fingerprint_downcase
94+
end
95+
96+
it "validate using SHA256" do
97+
sha256_fingerprint = "C4:C6:BD:41:EC:AD:57:97:CE:7B:7D:80:06:C3:E4:30:53:29:02:0B:DD:2D:47:02:9E:BD:85:AD:93:02:45:21"
98+
99+
assert !response_fingerprint_test.document.validate_document(sha256_fingerprint)
100+
assert response_fingerprint_test.document.validate_document(sha256_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA256)
101+
end
102+
103+
it "validate using SHA384" do
104+
sha384_fingerprint = "98:FE:17:90:31:E7:68:18:8A:65:4D:DA:F5:76:E2:09:97:BE:8B:E3:7E:AA:8D:63:64:7C:0C:38:23:9A:AC:A2:EC:CE:48:A6:74:4D:E0:4C:50:80:40:B4:8D:55:14:14"
105+
106+
assert !response_fingerprint_test.document.validate_document(sha384_fingerprint)
107+
assert response_fingerprint_test.document.validate_document(sha384_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA384)
108+
end
109+
110+
it "validate using SHA512" do
111+
sha512_fingerprint = "5A:AE:BA:D0:BA:9D:1E:25:05:01:1E:1A:C9:E9:FF:DB:ED:FA:6E:F7:52:EB:45:49:BD:DB:06:D8:A3:7E:CC:63:3A:04:A2:DD:DF:EE:61:05:D9:58:95:2A:77:17:30:4B:EB:4A:9F:48:4A:44:1C:D0:9E:0B:1E:04:77:FD:A3:D2"
112+
113+
assert !response_fingerprint_test.document.validate_document(sha512_fingerprint)
114+
assert response_fingerprint_test.document.validate_document(sha512_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA512)
115+
end
116+
117+
end
118+
119+
describe "Signature Algorithms" do
82120
it "validate using SHA1" do
83121
@document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha1, false))
84122
assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")

0 commit comments

Comments
 (0)