Skip to content

Commit fd5ad7e

Browse files
authored
Merge pull request #747 from johnnyshields/v2.x-remove-crypto-namespace
v2.x - Replace RubySaml::XML::Crypto namespace with RubySaml::XML
2 parents f54b49d + fb32a09 commit fd5ad7e

23 files changed

+278
-272
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,8 @@ to specify different certificates for each function.
585585
You may also globally set the SP signature and digest method, to be used in SP signing (functions 1 and 2 above):
586586

587587
```ruby
588-
settings.security[:digest_method] = RubySaml::XML::Crypto::SHA1
589-
settings.security[:signature_method] = RubySaml::XML::Crypto::RSA_SHA1
588+
settings.security[:digest_method] = RubySaml::XML::SHA1
589+
settings.security[:signature_method] = RubySaml::XML::RSA_SHA1
590590
```
591591

592592
#### Signing SP Metadata

UPGRADING.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ as before. This alias will be removed in RubySaml version `2.1.0`.
3232

3333
### Root "XMLSecurity" namespace changed to "RubySaml::XML"
3434

35-
RubySaml version `2.0.0` changes the namespace `RubySaml::XML::` to `RubySaml::XML::`. Please search your
36-
codebase for `RubySaml::XML::` and replace it as appropriate. In addition, you must replace direct usage of
35+
RubySaml version `2.0.0` changes the namespace `XMLSecurity::` to `RubySaml::XML::`. Please search your
36+
codebase for `XMLSecurity::` and replace it as appropriate. In addition, you must replace direct usage of
3737
`require 'xml_security'` with `require 'ruby_saml/xml'`.
3838

39-
For backward compatibility, the alias `XMLSecurity = RubySaml::XML` has been set, so `RubySaml::XML::` will still work
40-
as before. In addition, a shim file has been added so that `require 'xml_security'` continues to work.
41-
These aliases will be removed in RubySaml version `2.1.0`.
39+
For backward compatibility, if the constant `XMLSecurity` is not already defined by another gem, it will
40+
be aliased to `RubySaml::XML`. In addition, a shim file has been added so that `require 'xml_security'`
41+
continues to work. These aliases will be removed in RubySaml version `2.1.0`.
4242

4343
### Security: Change default hashing algorithm to SHA-256 (was SHA-1)
4444

@@ -54,9 +54,9 @@ you may set `RubySaml::Settings` as follows:
5454

5555
```ruby
5656
# Preserve RubySaml 1.x insecure SHA-1 behavior
57-
settings.idp_cert_fingerprint_algorithm = RubySaml::XML::Crypto::SHA1
58-
settings.security[:digest_method] = RubySaml::XML::Crypto::SHA1
59-
settings.security[:signature_method] = RubySaml::XML::Crypto::RSA_SHA1
57+
settings.idp_cert_fingerprint_algorithm = RubySaml::XML::SHA1
58+
settings.security[:digest_method] = RubySaml::XML::SHA1
59+
settings.security[:signature_method] = RubySaml::XML::RSA_SHA1
6060
```
6161

6262
### Behavior change of double_quote_xml_attribute_values setting

lib/ruby_saml/authrequest.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def create_params(settings, params={})
7474
relay_state: relay_state,
7575
sig_alg: params['SigAlg']
7676
)
77-
sign_algorithm = RubySaml::XML::Crypto.hash_algorithm(settings.get_sp_signature_method)
77+
sign_algorithm = RubySaml::XML.hash_algorithm(settings.get_sp_signature_method)
7878
signature = sp_signing_key.sign(sign_algorithm.new, url_string)
7979
params['Signature'] = encode(signature)
8080
end

lib/ruby_saml/idp_metadata_parser.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,12 @@ def certificates
393393

394394
# @return [String|nil] the fingerpint of the X509Certificate if it exists
395395
#
396-
def fingerprint(certificate, fingerprint_algorithm = RubySaml::XML::Crypto::SHA256)
396+
def fingerprint(certificate, fingerprint_algorithm = RubySaml::XML::SHA256)
397397
return unless certificate
398398

399399
cert = OpenSSL::X509::Certificate.new(Base64.decode64(certificate))
400400

401-
fingerprint_alg = RubySaml::XML::Crypto.hash_algorithm(fingerprint_algorithm).new
401+
fingerprint_alg = RubySaml::XML.hash_algorithm(fingerprint_algorithm).new
402402
fingerprint_alg.hexdigest(cert.to_der).upcase.scan(/../).join(":")
403403
end
404404

lib/ruby_saml/logoutrequest.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def create_params(settings, params={})
7272
relay_state: relay_state,
7373
sig_alg: params['SigAlg']
7474
)
75-
sign_algorithm = RubySaml::XML::Crypto.hash_algorithm(settings.get_sp_signature_method)
75+
sign_algorithm = RubySaml::XML.hash_algorithm(settings.get_sp_signature_method)
7676
signature = settings.get_sp_signing_key.sign(sign_algorithm.new, url_string)
7777
params['Signature'] = encode(signature)
7878
end

lib/ruby_saml/settings.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def get_fingerprint
126126
idp_cert_fingerprint || begin
127127
idp_cert = get_idp_cert
128128
if idp_cert
129-
fingerprint_alg = RubySaml::XML::Crypto.hash_algorithm(idp_cert_fingerprint_algorithm).new
129+
fingerprint_alg = RubySaml::XML.hash_algorithm(idp_cert_fingerprint_algorithm).new
130130
fingerprint_alg.hexdigest(idp_cert.to_der).upcase.scan(/../).join(":")
131131
end
132132
end
@@ -226,7 +226,7 @@ def get_binding(value)
226226
DEFAULTS = {
227227
assertion_consumer_service_binding: Utils::BINDINGS[:post],
228228
single_logout_service_binding: Utils::BINDINGS[:redirect],
229-
idp_cert_fingerprint_algorithm: RubySaml::XML::Crypto::SHA256,
229+
idp_cert_fingerprint_algorithm: RubySaml::XML::SHA256,
230230
message_max_bytesize: 250_000,
231231
soft: true,
232232
security: {
@@ -237,8 +237,8 @@ def get_binding(value)
237237
want_assertions_encrypted: false,
238238
want_name_id: false,
239239
metadata_signed: false,
240-
digest_method: RubySaml::XML::Crypto::SHA256,
241-
signature_method: RubySaml::XML::Crypto::RSA_SHA256,
240+
digest_method: RubySaml::XML::SHA256,
241+
signature_method: RubySaml::XML::RSA_SHA256,
242242
check_idp_cert_expiration: false,
243243
check_sp_cert_expiration: false,
244244
strict_audience_validation: false,
@@ -301,7 +301,7 @@ def get_sp_signature_method
301301
key_alg = 'ECDSA' if key_alg.casecmp('EC') == 0
302302

303303
begin
304-
RubySaml::XML::Crypto.const_get("#{key_alg}_#{hash_alg}".upcase)
304+
RubySaml::XML.const_get("#{key_alg}_#{hash_alg}".upcase)
305305
rescue NameError
306306
raise ArgumentError.new("Unsupported signature method#{" for #{key_alg_real} key" if key_alg_real}: #{sig_alg}")
307307
end
@@ -313,7 +313,7 @@ def get_sp_digest_method
313313
alg = digest_alg.to_s.match(/(?:\A|#)(sha\d+)\z/i)[1]
314314

315315
begin
316-
RubySaml::XML::Crypto.const_get(alg.upcase)
316+
RubySaml::XML.const_get(alg.upcase)
317317
rescue NameError
318318
raise ArgumentError.new("Unsupported digest method: #{digest_alg}")
319319
end

lib/ruby_saml/slo_logoutresponse.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def create_params(settings, request_id = nil, logout_message = nil, params = {},
8080
relay_state: relay_state,
8181
sig_alg: params['SigAlg']
8282
)
83-
sign_algorithm = RubySaml::XML::Crypto.hash_algorithm(settings.get_sp_signature_method)
83+
sign_algorithm = RubySaml::XML.hash_algorithm(settings.get_sp_signature_method)
8484
signature = sp_signing_key.sign(sign_algorithm.new, url_string)
8585
params['Signature'] = encode(signature)
8686
end

lib/ruby_saml/utils.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def escape_request_param(param, lowercase_url_encoding)
226226
#
227227
def verify_signature(params)
228228
cert, sig_alg, signature, query_string = params.values_at(:cert, :sig_alg, :signature, :query_string)
229-
signature_algorithm = RubySaml::XML::Crypto.hash_algorithm(sig_alg)
229+
signature_algorithm = RubySaml::XML.hash_algorithm(sig_alg)
230230
cert.public_key.verify(signature_algorithm.new, Base64.decode64(signature), query_string)
231231
end
232232

lib/ruby_saml/xml.rb

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,116 @@
11
# frozen_string_literal: true
22

3-
require 'ruby_saml/xml/crypto'
3+
require 'rexml/element'
4+
require 'openssl'
5+
require 'nokogiri'
6+
require 'digest/sha1'
7+
require 'digest/sha2'
8+
9+
module RubySaml
10+
# Utility module for working with XML.
11+
module XML
12+
extend self
13+
14+
# XML constants
15+
#
16+
# @api private
17+
C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#'
18+
DSIG = 'http://www.w3.org/2000/09/xmldsig#'
19+
RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
20+
RSA_SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224'
21+
RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
22+
RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
23+
RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
24+
DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'
25+
DSA_SHA256 = 'http://www.w3.org/2009/xmldsig11#dsa-sha256'
26+
ECDSA_SHA1 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1'
27+
ECDSA_SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224'
28+
ECDSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256'
29+
ECDSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384'
30+
ECDSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512'
31+
SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'
32+
SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#sha224'
33+
SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'
34+
SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384'
35+
SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'
36+
ENVELOPED_SIG = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
37+
38+
NOKOGIRI_OPTIONS = Nokogiri::XML::ParseOptions::STRICT |
39+
Nokogiri::XML::ParseOptions::NONET
40+
41+
# Find XML canonicalization algorithm
42+
#
43+
# @api private
44+
def canon_algorithm(element, default: true)
45+
case get_algorithm_attr(element)
46+
when %r{\Ahttp://www\.w3\.org/TR/2001/REC-xml-c14n-20010315#?(?:WithComments)?\z}i
47+
Nokogiri::XML::XML_C14N_1_0
48+
when %r{\Ahttp://www\.w3\.org/2006/12/xml-c14n11#?(?:WithComments)?\z}i
49+
Nokogiri::XML::XML_C14N_1_1
50+
when %r{\Ahttp://www\.w3\.org/2001/10/xml-exc-c14n#?(?:WithComments)?\z}i
51+
Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
52+
else
53+
Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0 if default
54+
end
55+
end
56+
57+
# Find XML signature algorithm
58+
#
59+
# @api private
60+
def signature_algorithm(element)
61+
alg = get_algorithm_attr(element)
62+
match_data = alg&.downcase&.match(/(?:\A|#)(rsa|dsa|ecdsa)-(sha\d+)\z/i) || {}
63+
key_alg = match_data[1]
64+
hash_alg = match_data[2]
65+
66+
key = case key_alg
67+
when 'rsa' then OpenSSL::PKey::RSA
68+
when 'dsa' then OpenSSL::PKey::DSA
69+
when 'ecdsa' then OpenSSL::PKey::EC
70+
else # rubocop:disable Lint/DuplicateBranch
71+
# TODO: raise ArgumentError.new("Invalid key algorithm: #{alg}")
72+
OpenSSL::PKey::RSA
73+
end
74+
75+
[key, hash_algorithm(hash_alg)]
76+
end
77+
78+
# Find XML digest hashing algorithm
79+
#
80+
# @api private
81+
def hash_algorithm(element)
82+
alg = get_algorithm_attr(element)
83+
hash_alg = alg&.downcase&.match(/(?:\A|[#-])(sha\d+)\z/i)&.[](1)
84+
85+
case hash_alg
86+
when 'sha1' then OpenSSL::Digest::SHA1
87+
when 'sha224' then OpenSSL::Digest::SHA224
88+
when 'sha256' then OpenSSL::Digest::SHA256
89+
when 'sha384' then OpenSSL::Digest::SHA384
90+
when 'sha512' then OpenSSL::Digest::SHA512
91+
else # rubocop:disable Lint/DuplicateBranch
92+
# TODO: raise ArgumentError.new("Invalid hash algorithm: #{alg}")
93+
OpenSSL::Digest::SHA256
94+
end
95+
end
96+
97+
private
98+
99+
def get_algorithm_attr(element)
100+
if element.is_a?(Nokogiri::XML::Element)
101+
element['Algorithm']
102+
elsif element.is_a?(REXML::Element)
103+
element.attribute('Algorithm').value
104+
elsif element
105+
element
106+
end
107+
end
108+
end
109+
end
110+
4111
require 'ruby_saml/xml/base_document'
5112
require 'ruby_saml/xml/document'
6113
require 'ruby_saml/xml/signed_document'
7114

8115
# @deprecated This alias adds compatibility with v1.x and will be removed in v2.1.0
9-
XMLSecurity = RubySaml::XML
116+
XMLSecurity = RubySaml::XML unless defined?(XMLSecurity)

lib/ruby_saml/xml/base_document.rb

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,26 @@
77
require 'openssl'
88
require 'digest/sha1'
99
require 'digest/sha2'
10-
require 'ruby_saml/xml/crypto'
1110

1211
module RubySaml
1312
module XML
1413
class BaseDocument < REXML::Document
1514
# TODO: This affects the global state
1615
REXML::Security.entity_expansion_limit = 0
1716

18-
# @deprecated Constants moved to Crypto module
19-
C14N = RubySaml::XML::Crypto::C14N
20-
DSIG = RubySaml::XML::Crypto::DSIG
21-
22-
NOKOGIRI_OPTIONS = Nokogiri::XML::ParseOptions::STRICT |
23-
Nokogiri::XML::ParseOptions::NONET
17+
# @deprecated Constants moved to RubySaml::XML module
18+
C14N = RubySaml::XML::C14N
19+
DSIG = RubySaml::XML::DSIG
20+
NOKOGIRI_OPTIONS = RubySaml::XML::NOKOGIRI_OPTIONS
2421

2522
# @deprecated Remove in v2.1.0
2623
def canon_algorithm(algorithm)
27-
RubySaml::XML::Crypto.canon_algorithm(algorithm)
24+
RubySaml::XML.canon_algorithm(algorithm)
2825
end
2926

3027
# @deprecated Remove in v2.1.0
3128
def algorithm(algorithm)
32-
RubySaml::XML::Crypto.hash_algorithm(algorithm)
29+
RubySaml::XML.hash_algorithm(algorithm)
3330
end
3431
end
3532
end

0 commit comments

Comments
 (0)