Skip to content

Commit 026607b

Browse files
authored
Merge pull request #758 from johnnyshields/v2.x-decryption-refactor
v2.x - Nokogiri Refactor Part 5: Extract out RubySaml::XML::Decryptor + Decoder
2 parents c937868 + 75c8a0e commit 026607b

36 files changed

+1120
-792
lines changed

lib/ruby_saml/authrequest.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ def create_params(settings, params={})
5151

5252
Logging.debug "Created AuthnRequest: #{request}"
5353

54-
request = deflate(request) if binding_redirect
55-
base64_request = encode(request)
54+
base64_request = RubySaml::XML::Decoder.encode_message(request, compress: binding_redirect)
5655
request_params = {"SAMLRequest" => base64_request}
5756
sp_signing_key = settings.get_sp_signing_key
5857

@@ -66,7 +65,7 @@ def create_params(settings, params={})
6665
)
6766
sign_algorithm = RubySaml::XML.hash_algorithm(settings.get_sp_signature_method)
6867
signature = sp_signing_key.sign(sign_algorithm.new, url_string)
69-
params['Signature'] = encode(signature)
68+
params['Signature'] = Base64.strict_encode64(signature)
7069
end
7170

7271
params.each_pair do |key, value|
@@ -88,8 +87,8 @@ def create_xml_document(settings)
8887
time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
8988
assign_uuid(settings)
9089
root_attributes = {
91-
'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol',
92-
'xmlns:saml' => 'urn:oasis:names:tc:SAML:2.0:assertion',
90+
'xmlns:samlp' => RubySaml::XML::NS_PROTOCOL,
91+
'xmlns:saml' => RubySaml::XML::NS_ASSERTION,
9392
'ID' => uuid,
9493
'IssueInstant' => time,
9594
'Version' => '2.0',

lib/ruby_saml/error_handling.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
require "ruby_saml/validation_error"
3+
require 'ruby_saml/validation_error'
44

55
module RubySaml
66
module ErrorHandling
@@ -9,10 +9,10 @@ module ErrorHandling
99
# Append the cause to the errors array, and based on the value of soft, return false or raise
1010
# an exception. soft_override is provided as a means of overriding the object's notion of
1111
# soft for just this invocation.
12-
def append_error(error_msg, soft_override = nil)
12+
def append_error(error_msg, soft_override = false) # rubocop:disable Style/OptionalBooleanParameter
1313
@errors << error_msg
1414

15-
unless soft_override.nil? ? soft : soft_override
15+
unless soft_override || (respond_to?(:soft) && soft)
1616
raise ValidationError.new(error_msg)
1717
end
1818

lib/ruby_saml/idp_metadata_parser.rb

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,20 @@ module RubySaml
1111
# make sure to validate it properly before use it in a parse_remote method.
1212
# Read the `Security warning` section of the README.md file to get more info
1313
class IdpMetadataParser
14-
module SamlMetadata
15-
module Vocabulary
16-
METADATA = "urn:oasis:names:tc:SAML:2.0:metadata"
17-
DSIG = "http://www.w3.org/2000/09/xmldsig#"
18-
NAME_FORMAT = "urn:oasis:names:tc:SAML:2.0:attrname-format:*"
19-
SAML_ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
20-
end
21-
22-
NAMESPACE = {
23-
"md" => Vocabulary::METADATA,
24-
"NameFormat" => Vocabulary::NAME_FORMAT,
25-
"saml" => Vocabulary::SAML_ASSERTION,
26-
"ds" => Vocabulary::DSIG
27-
}.freeze
28-
end
14+
NAMESPACES = {
15+
"ds" => RubySaml::XML::DSIG,
16+
"md" => RubySaml::XML::NS_METADATA,
17+
"saml" => RubySaml::XML::NS_ASSERTION
18+
}.freeze
2919

30-
include SamlMetadata::Vocabulary
3120
attr_reader :document
3221
attr_reader :response
3322
attr_reader :options
3423

3524
# fetch IdP descriptors from a metadata document
3625
def self.get_idps(noko_document, only_entity_id = nil)
3726
path = "//md:EntityDescriptor#{"[@entityID=\"#{only_entity_id}\"]" if only_entity_id}/md:IDPSSODescriptor"
38-
noko_document.xpath(path, SamlMetadata::NAMESPACE)
27+
noko_document.xpath(path, NAMESPACES)
3928
end
4029

4130
# Parse the Identity Provider metadata and update the settings with the
@@ -272,7 +261,7 @@ def cache_duration
272261
def idp_name_id_format(name_id_priority = nil)
273262
nodes = @idpsso_descriptor.xpath(
274263
"md:NameIDFormat",
275-
SamlMetadata::NAMESPACE
264+
NAMESPACES
276265
)
277266
first_ranked_text(nodes, name_id_priority)
278267
end
@@ -283,7 +272,7 @@ def idp_name_id_format(name_id_priority = nil)
283272
def single_signon_service_binding(binding_priority = nil)
284273
nodes = @idpsso_descriptor.xpath(
285274
"md:SingleSignOnService/@Binding",
286-
SamlMetadata::NAMESPACE
275+
NAMESPACES
287276
)
288277
first_ranked_value(nodes, binding_priority)
289278
end
@@ -294,7 +283,7 @@ def single_signon_service_binding(binding_priority = nil)
294283
def single_logout_service_binding(binding_priority = nil)
295284
nodes = @idpsso_descriptor.xpath(
296285
"md:SingleLogoutService/@Binding",
297-
SamlMetadata::NAMESPACE
286+
NAMESPACES
298287
)
299288
first_ranked_value(nodes, binding_priority)
300289
end
@@ -308,7 +297,7 @@ def single_signon_service_url(binding_priority = nil)
308297

309298
@idpsso_descriptor.at_xpath(
310299
"md:SingleSignOnService[@Binding=\"#{binding}\"]/@Location",
311-
SamlMetadata::NAMESPACE
300+
NAMESPACES
312301
)&.value
313302
end
314303

@@ -321,7 +310,7 @@ def single_logout_service_url(binding_priority = nil)
321310

322311
@idpsso_descriptor.at_xpath(
323312
"md:SingleLogoutService[@Binding=\"#{binding}\"]/@Location",
324-
SamlMetadata::NAMESPACE
313+
NAMESPACES
325314
)&.value
326315
end
327316

@@ -334,7 +323,7 @@ def single_logout_response_service_url(binding_priority = nil)
334323

335324
node = @idpsso_descriptor.at_xpath(
336325
"md:SingleLogoutService[@Binding=\"#{binding}\"]/@ResponseLocation",
337-
SamlMetadata::NAMESPACE
326+
NAMESPACES
338327
)
339328
node&.value
340329
end
@@ -345,12 +334,12 @@ def certificates
345334
@certificates ||= begin
346335
signing_nodes = @idpsso_descriptor.xpath(
347336
"md:KeyDescriptor[not(contains(@use, 'encryption'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate",
348-
SamlMetadata::NAMESPACE
337+
NAMESPACES
349338
)
350339

351340
encryption_nodes = @idpsso_descriptor.xpath(
352341
"md:KeyDescriptor[not(contains(@use, 'signing'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate",
353-
SamlMetadata::NAMESPACE
342+
NAMESPACES
354343
)
355344

356345
return nil if signing_nodes.empty? && encryption_nodes.empty?
@@ -389,7 +378,7 @@ def fingerprint(certificate, fingerprint_algorithm = RubySaml::XML::SHA256)
389378
def attribute_names
390379
nodes = @idpsso_descriptor.xpath(
391380
"saml:Attribute/@Name",
392-
SamlMetadata::NAMESPACE
381+
NAMESPACES
393382
)
394383
nodes.map(&:value)
395384
end

lib/ruby_saml/logoutrequest.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ def create_params(settings, params={})
5151

5252
Logging.debug "Created SLO Logout Request: #{request}"
5353

54-
request = deflate(request) if binding_redirect
55-
base64_request = encode(request)
54+
base64_request = RubySaml::XML::Decoder.encode_message(request, compress: binding_redirect)
5655
request_params = {"SAMLRequest" => base64_request}
5756
sp_signing_key = settings.get_sp_signing_key
5857

@@ -66,7 +65,7 @@ def create_params(settings, params={})
6665
)
6766
sign_algorithm = RubySaml::XML.hash_algorithm(settings.get_sp_signature_method)
6867
signature = settings.get_sp_signing_key.sign(sign_algorithm.new, url_string)
69-
params['Signature'] = encode(signature)
68+
params['Signature'] = Base64.strict_encode64(signature)
7069
end
7170

7271
params.each_pair do |key, value|
@@ -89,8 +88,8 @@ def create_xml_document(settings)
8988
assign_uuid(settings)
9089

9190
root_attributes = {
92-
'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol',
93-
'xmlns:saml' => 'urn:oasis:names:tc:SAML:2.0:assertion',
91+
'xmlns:samlp' => RubySaml::XML::NS_PROTOCOL,
92+
'xmlns:saml' => RubySaml::XML::NS_ASSERTION,
9493
'ID' => uuid,
9594
'IssueInstant' => time,
9695
'Version' => '2.0',

lib/ruby_saml/logoutresponse.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def initialize(response, settings = nil, options = {})
4040
end
4141

4242
@options = options
43-
@response = decode_raw_saml(response, settings)
43+
@response = RubySaml::XML::Decoder.decode_message(response, @settings&.message_max_bytesize)
4444
@document = RubySaml::XML::SignedDocument.new(@response)
4545
super()
4646
end
@@ -64,7 +64,7 @@ def in_response_to
6464
node = REXML::XPath.first(
6565
document,
6666
"/p:LogoutResponse",
67-
{ "p" => PROTOCOL }
67+
{ "p" => RubySaml::XML::NS_PROTOCOL }
6868
)
6969
node.nil? ? nil : node.attributes['InResponseTo']
7070
end
@@ -77,7 +77,7 @@ def issuer
7777
node = REXML::XPath.first(
7878
document,
7979
"/p:LogoutResponse/a:Issuer",
80-
{ "p" => PROTOCOL, "a" => ASSERTION }
80+
{ "p" => RubySaml::XML::NS_PROTOCOL, "a" => RubySaml::XML::NS_ASSERTION }
8181
)
8282
Utils.element_text(node)
8383
end
@@ -87,7 +87,7 @@ def issuer
8787
#
8888
def status_code
8989
@status_code ||= begin
90-
node = REXML::XPath.first(document, "/p:LogoutResponse/p:Status/p:StatusCode", { "p" => PROTOCOL })
90+
node = REXML::XPath.first(document, "/p:LogoutResponse/p:Status/p:StatusCode", { "p" => RubySaml::XML::NS_PROTOCOL })
9191
node.nil? ? nil : node.attributes["Value"]
9292
end
9393
end
@@ -97,7 +97,7 @@ def status_message
9797
node = REXML::XPath.first(
9898
document,
9999
"/p:LogoutResponse/p:Status/p:StatusMessage",
100-
{ "p" => PROTOCOL }
100+
{ "p" => RubySaml::XML::NS_PROTOCOL }
101101
)
102102
Utils.element_text(node)
103103
end

lib/ruby_saml/metadata.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ def generate(settings, pretty_print = false, valid_until = nil, cache_duration =
3333

3434
# Add saml namespace if attribute consuming service is configured
3535
if settings.attribute_consuming_service.configured?
36-
root_attributes['xmlns:saml'] = 'urn:oasis:names:tc:SAML:2.0:assertion'
36+
root_attributes['xmlns:saml'] = RubySaml::XML::NS_ASSERTION
3737
end
3838

3939
xml['md'].EntityDescriptor(root_attributes) do
4040
sp_sso_attributes = {
41-
'protocolSupportEnumeration' => 'urn:oasis:names:tc:SAML:2.0:protocol',
41+
'protocolSupportEnumeration' => RubySaml::XML::NS_PROTOCOL,
4242
'AuthnRequestsSigned' => settings.security[:authn_requests_signed] ? 'true' : 'false',
4343
'WantAssertionsSigned' => settings.security[:want_assertions_signed] ? 'true' : 'false'
4444
}
@@ -150,7 +150,7 @@ def output_xml(meta_doc, pretty_print)
150150
private
151151

152152
def add_certificate_element(xml, cert, use)
153-
cert_text = Base64.encode64(cert.to_der).delete("\n")
153+
cert_text = Base64.strict_encode64(cert.to_der)
154154
xml['md'].KeyDescriptor('use' => use.to_s) do
155155
xml['ds'].KeyInfo do
156156
xml['ds'].X509Data do

0 commit comments

Comments
 (0)