maestrano 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +43 -0
  5. data/LICENSE +21 -0
  6. data/README.md +4 -0
  7. data/Rakefile +32 -0
  8. data/bin/maestrano-console +9 -0
  9. data/lib/maestrano.rb +114 -0
  10. data/lib/maestrano/account/bill.rb +14 -0
  11. data/lib/maestrano/api/error/authentication_error.rb +8 -0
  12. data/lib/maestrano/api/error/base_error.rb +24 -0
  13. data/lib/maestrano/api/error/connection_error.rb +8 -0
  14. data/lib/maestrano/api/error/invalid_request_error.rb +14 -0
  15. data/lib/maestrano/api/list_object.rb +37 -0
  16. data/lib/maestrano/api/object.rb +187 -0
  17. data/lib/maestrano/api/operation/base.rb +216 -0
  18. data/lib/maestrano/api/operation/create.rb +18 -0
  19. data/lib/maestrano/api/operation/delete.rb +13 -0
  20. data/lib/maestrano/api/operation/list.rb +18 -0
  21. data/lib/maestrano/api/operation/update.rb +59 -0
  22. data/lib/maestrano/api/resource.rb +39 -0
  23. data/lib/maestrano/api/util.rb +121 -0
  24. data/lib/maestrano/saml/attribute_value.rb +15 -0
  25. data/lib/maestrano/saml/metadata.rb +64 -0
  26. data/lib/maestrano/saml/request.rb +93 -0
  27. data/lib/maestrano/saml/response.rb +201 -0
  28. data/lib/maestrano/saml/schemas/saml20assertion_schema.xsd +283 -0
  29. data/lib/maestrano/saml/schemas/saml20protocol_schema.xsd +302 -0
  30. data/lib/maestrano/saml/schemas/xenc_schema.xsd +146 -0
  31. data/lib/maestrano/saml/schemas/xmldsig_schema.xsd +318 -0
  32. data/lib/maestrano/saml/settings.rb +37 -0
  33. data/lib/maestrano/saml/validation_error.rb +7 -0
  34. data/lib/maestrano/sso.rb +81 -0
  35. data/lib/maestrano/sso/base_group.rb +31 -0
  36. data/lib/maestrano/sso/base_user.rb +75 -0
  37. data/lib/maestrano/sso/group.rb +24 -0
  38. data/lib/maestrano/sso/session.rb +63 -0
  39. data/lib/maestrano/sso/user.rb +34 -0
  40. data/lib/maestrano/version.rb +3 -0
  41. data/lib/maestrano/xml_security/signed_document.rb +170 -0
  42. data/maestrano.gemspec +32 -0
  43. data/test/helpers/api_helpers.rb +82 -0
  44. data/test/helpers/saml_helpers.rb +62 -0
  45. data/test/maestrano/account/bill_test.rb +48 -0
  46. data/test/maestrano/api/list_object_test.rb +20 -0
  47. data/test/maestrano/api/object_test.rb +28 -0
  48. data/test/maestrano/api/resource_test.rb +343 -0
  49. data/test/maestrano/api/util_test.rb +31 -0
  50. data/test/maestrano/maestrano_test.rb +49 -0
  51. data/test/maestrano/saml/request_test.rb +168 -0
  52. data/test/maestrano/saml/response_test.rb +290 -0
  53. data/test/maestrano/saml/settings_test.rb +51 -0
  54. data/test/maestrano/sso/base_group_test.rb +54 -0
  55. data/test/maestrano/sso/base_user_test.rb +114 -0
  56. data/test/maestrano/sso/group_test.rb +47 -0
  57. data/test/maestrano/sso/session_test.rb +108 -0
  58. data/test/maestrano/sso/user_test.rb +65 -0
  59. data/test/maestrano/sso_test.rb +81 -0
  60. data/test/maestrano/xml_security/signed_document.rb +163 -0
  61. data/test/support/saml/certificates/certificate1 +12 -0
  62. data/test/support/saml/certificates/r1_certificate2_base64 +1 -0
  63. data/test/support/saml/responses/adfs_response_sha1.xml +46 -0
  64. data/test/support/saml/responses/adfs_response_sha256.xml +46 -0
  65. data/test/support/saml/responses/adfs_response_sha384.xml +46 -0
  66. data/test/support/saml/responses/adfs_response_sha512.xml +46 -0
  67. data/test/support/saml/responses/no_signature_ns.xml +48 -0
  68. data/test/support/saml/responses/open_saml_response.xml +56 -0
  69. data/test/support/saml/responses/r1_response6.xml.base64 +1 -0
  70. data/test/support/saml/responses/response1.xml.base64 +1 -0
  71. data/test/support/saml/responses/response2.xml.base64 +79 -0
  72. data/test/support/saml/responses/response3.xml.base64 +66 -0
  73. data/test/support/saml/responses/response4.xml.base64 +93 -0
  74. data/test/support/saml/responses/response5.xml.base64 +102 -0
  75. data/test/support/saml/responses/response_with_ampersands.xml +139 -0
  76. data/test/support/saml/responses/response_with_ampersands.xml.base64 +93 -0
  77. data/test/support/saml/responses/response_with_multiple_attribute_values.xml +57 -0
  78. data/test/support/saml/responses/simple_saml_php.xml +71 -0
  79. data/test/support/saml/responses/starfield_response.xml.base64 +1 -0
  80. data/test/support/saml/responses/wrapped_response_2.xml.base64 +150 -0
  81. data/test/test_helper.rb +46 -0
  82. metadata +305 -0
@@ -0,0 +1,37 @@
1
+ module Maestrano
2
+ module Saml
3
+ class Settings
4
+ NAMEID_EMAIL_ADDRESS = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
5
+ NAMEID_X509_SUBJECT_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName'
6
+ NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName'
7
+ NAMEID_KERBEROS = 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos'
8
+ NAMEID_ENTITY = 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
9
+ NAMEID_TRANSIENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
10
+ NAMEID_PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
11
+ PROTOCOL_BINDING_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
12
+
13
+ def initialize(overrides = {})
14
+ config = DEFAULTS.merge(overrides)
15
+ config.each do |k,v|
16
+ acc = "#{k.to_s}=".to_sym
17
+ self.send(acc, v) if self.respond_to? acc
18
+ end
19
+ end
20
+ attr_accessor :assertion_consumer_service_url, :issuer, :sp_name_qualifier
21
+ attr_accessor :idp_sso_target_url, :idp_cert_fingerprint, :idp_cert, :name_identifier_format
22
+ attr_accessor :authn_context
23
+ attr_accessor :idp_slo_target_url
24
+ attr_accessor :name_identifier_value
25
+ attr_accessor :sessionindex
26
+ attr_accessor :assertion_consumer_logout_service_url
27
+ attr_accessor :compress_request
28
+ attr_accessor :double_quote_xml_attribute_values
29
+ attr_accessor :passive
30
+ attr_accessor :protocol_binding
31
+
32
+ private
33
+
34
+ DEFAULTS = {:compress_request => true, :double_quote_xml_attribute_values => false}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ module Maestrano
2
+ module Saml
3
+ class ValidationError < StandardError
4
+ end
5
+ end
6
+ end
7
+
@@ -0,0 +1,81 @@
1
+ module Maestrano
2
+ module SSO
3
+ # Return the saml_settings based on
4
+ # Maestrano configuration
5
+ def self.saml_settings
6
+ settings = Maestrano::Saml::Settings.new
7
+ settings.assertion_consumer_service_url = self.consume_url
8
+ settings.issuer = Maestrano.param('app_host')
9
+ settings.idp_sso_target_url = self.idp_url
10
+ settings.idp_cert_fingerprint = Maestrano.param('sso_x509_fingerprint')
11
+ settings.name_identifier_format = Maestrano.param('sso_name_id_format')
12
+ settings
13
+ end
14
+
15
+ # Build a new SAML Request
16
+ def self.build_request(get_params = {})
17
+ Maestrano::Saml::Request.new(get_params)
18
+ end
19
+
20
+ # Build a new SAML response
21
+ def self.build_response(saml_post_param)
22
+ Maestrano::Saml::Response.new(saml_post_param)
23
+ end
24
+
25
+ def self.enabled?
26
+ !!Maestrano.param('sso_enabled')
27
+ end
28
+
29
+ def self.init_url
30
+ host = Maestrano.param('app_host')
31
+ path = Maestrano.param('sso_app_init_path')
32
+ return "#{host}#{path}"
33
+ end
34
+
35
+ def self.consume_url
36
+ host = Maestrano.param('app_host')
37
+ path = Maestrano.param('sso_app_consume_path')
38
+ return "#{host}#{path}"
39
+ end
40
+
41
+ def self.logout_url
42
+ host = Maestrano.param('api_host')
43
+ path = '/app_logout'
44
+ return "#{host}#{path}"
45
+ end
46
+
47
+ def self.unauthorized_url
48
+ host = Maestrano.param('api_host')
49
+ path = '/app_access_unauthorized'
50
+ return "#{host}#{path}";
51
+ end
52
+
53
+ def self.idp_url
54
+ host = Maestrano.param('api_host')
55
+ api_base = Maestrano.param('api_base')
56
+ endpoint = 'auth/saml'
57
+ return "#{host}#{api_base}#{endpoint}"
58
+ end
59
+
60
+ def self.session_check_url(user_uid,sso_session)
61
+ host = Maestrano.param('api_host')
62
+ api_base = Maestrano.param('api_base')
63
+ endpoint = 'auth/saml'
64
+ return URI.escape("#{host}#{api_base}#{endpoint}/#{user_uid}?session=#{sso_session}")
65
+ end
66
+
67
+ # Set maestrano attributes in session
68
+ # Takes the BaseUser hash representation and current session
69
+ # in arguments
70
+ def self.set_session(session, auth)
71
+ if auth && (extra = (auth[:extra] || auth['extra'])) && (sso_session = (extra[:session] || extra['session']))
72
+ session[:mno_uid] = (sso_session[:uid] || sso_session['uid'])
73
+ session[:mno_session] = (sso_session[:token] || sso_session['token'])
74
+ if recheck = (sso_session[:recheck] || sso_session['recheck'])
75
+ session[:mno_session_recheck] = recheck.utc.iso8601
76
+ end
77
+ session[:mno_group_uid] = (sso_session[:group_uid] || sso_session['group_uid'])
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,31 @@
1
+ module Maestrano
2
+ module SSO
3
+ class BaseGroup
4
+ attr_accessor :local_id
5
+ attr_reader :uid,:country, :company_name, :free_trial_end_at
6
+
7
+ # Initializer
8
+ # @param Maestrano::SAML::Response
9
+ def initialize(saml_response)
10
+ att = saml_response.attributes
11
+ @uid = att['group_uid']
12
+ @country = att['country']
13
+ @free_trial_end_at = Time.iso8601(att['group_end_free_trial'])
14
+ @company_name = att['company_name']
15
+ end
16
+
17
+ def to_hash
18
+ {
19
+ provider: 'maestrano',
20
+ uid: self.uid,
21
+ info: {
22
+ free_trial_end_at: self.free_trial_end_at,
23
+ company_name: self.company_name,
24
+ country: self.country,
25
+ },
26
+ extra: {}
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,75 @@
1
+ module Maestrano
2
+ module SSO
3
+ class BaseUser
4
+ attr_accessor :local_id
5
+ attr_reader :sso_session,:sso_session_recheck,
6
+ :group_uid,:group_role,:uid,:virtual_uid,:email,
7
+ :virtual_email,:first_name, :last_name,:country, :company_name
8
+
9
+ # Initializer
10
+ # @param Maestrano::SAML::Response
11
+ def initialize(saml_response)
12
+ att = saml_response.attributes
13
+ @sso_session = att['mno_session']
14
+ @sso_session_recheck = Time.iso8601(att['mno_session_recheck'])
15
+ @group_uid = att['group_uid']
16
+ @group_role = att['group_role']
17
+ @uid = att['uid']
18
+ @virtual_uid = att['virtual_uid']
19
+ @email = att['email']
20
+ @virtual_email = att['virtual_email']
21
+ @first_name = att['name']
22
+ @last_name = att['surname']
23
+ @country = att['country']
24
+ @company_name = att['company_name']
25
+ end
26
+
27
+ def to_uid
28
+ if Maestrano.param('user_creation_mode') == 'real'
29
+ return self.uid
30
+ else
31
+ return self.virtual_uid
32
+ end
33
+ end
34
+
35
+ def to_email
36
+ if Maestrano.param('user_creation_mode') == 'real'
37
+ return self.email
38
+ else
39
+ return self.virtual_email
40
+ end
41
+ end
42
+
43
+ # Hash representation of the resource
44
+ def to_hash
45
+ {
46
+ provider: 'maestrano',
47
+ uid: self.to_uid,
48
+ info: {
49
+ email: self.to_email,
50
+ first_name: self.first_name,
51
+ last_name: self.last_name,
52
+ country: self.country,
53
+ company_name: self.company_name,
54
+ },
55
+ extra: {
56
+ uid: self.uid,
57
+ virtual_uid: self.virtual_uid,
58
+ real_email: self.email,
59
+ virtual_email: self.virtual_email,
60
+ group: {
61
+ uid: self.group_uid,
62
+ role: self.group_role,
63
+ },
64
+ session: {
65
+ uid: self.uid,
66
+ token: self.sso_session,
67
+ recheck: self.sso_session_recheck,
68
+ group_uid: self.group_uid
69
+ },
70
+ }
71
+ }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module Maestrano
2
+ module SSO
3
+ module Group
4
+ def find_for_maestrano_auth(auth)
5
+ # E.g with Rails
6
+ # where(auth.slice(:provider, :uid)).first_or_create do |group|
7
+ # group.provider = auth[:provider]
8
+ # group.uid = auth[:uid]
9
+ # group.name = (auth[:info][:company_name] || 'Your Group')
10
+ # group.country = auth[:info][:country]
11
+ # end
12
+ raise NoMethodError, "You need to override find_for_maestrano_auth in your #{self.class.name} model"
13
+ end
14
+
15
+ def maestrano?
16
+ if self.respond_to?(:provider)
17
+ return self.provider.to_s == 'maestrano'
18
+ else
19
+ raise NoMethodError, "You need to override maestrano? in your #{self.class.name} model"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,63 @@
1
+ module Maestrano
2
+ module SSO
3
+ class Session
4
+ attr_accessor :session, :uid, :session_token, :recheck
5
+
6
+ def initialize(session)
7
+ self.session = session
8
+ self.uid = (self.session['mno_uid'] || self.session[:mno_uid])
9
+ self.session_token = (self.session['mno_session'] || self.session[:mno_session])
10
+ if recheck = (self.session['mno_session_recheck'] || self.session[:mno_session_recheck])
11
+ self.recheck = Time.iso8601(recheck)
12
+ end
13
+
14
+ if self.uid.nil? || self.session_token.nil? || self.recheck.nil?
15
+ $stderr.puts "WARNING: Maestrano session information missing. User will have to relogin"
16
+ end
17
+ end
18
+
19
+ def remote_check_required?
20
+ if self.uid && self.session_token && self.recheck
21
+ return (self.recheck <= Time.now)
22
+ end
23
+ return true
24
+ end
25
+
26
+ # Check remote maestrano session and update the
27
+ # recheck attribute if the session is still valid
28
+ # Return true if the session is still valid and
29
+ # false otherwise
30
+ def perform_remote_check
31
+ # Get remote session info
32
+ url = Maestrano::SSO.session_check_url(self.uid, self.session_token)
33
+ begin
34
+ response = RestClient.get(url)
35
+ response = JSON.parse(response)
36
+ rescue Exception => e
37
+ response = {}
38
+ end
39
+
40
+ # Process response
41
+ if response['valid'] && response['recheck']
42
+ self.recheck = Time.iso8601(response['recheck'])
43
+ return true
44
+ end
45
+
46
+ return false
47
+ end
48
+
49
+ def valid?
50
+ if self.remote_check_required?
51
+ if perform_remote_check
52
+ self.session[:mno_session_recheck] = self.recheck.utc.iso8601
53
+ return true
54
+ else
55
+ return false
56
+ end
57
+ end
58
+ return true
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,34 @@
1
+ module Maestrano
2
+ module SSO
3
+ module User
4
+ def find_for_maestrano_auth(auth)
5
+ # E.g with Rails
6
+ # where(auth.slice(:provider, :uid)).first_or_create do |user|
7
+ # user.provider = auth[:provider]
8
+ # user.uid = auth[:uid]
9
+ # user.email = auth[:info][:email]
10
+ # user.name = auth[:info][:first_name]
11
+ # user.surname = auth[:info][:last_name]
12
+ # user.country = auth[:info][:country]
13
+ # user.company = auth[:info][:company_name]
14
+ # end
15
+ raise NoMethodError, "You need to override find_for_maestrano_auth in your #{self.class.name} model"
16
+ end
17
+
18
+ # Check whether the user is a maestrano one
19
+ def maestrano?
20
+ if self.respond_to?(:provider)
21
+ return self.provider.to_s == 'maestrano'
22
+ else
23
+ raise NoMethodError, "You need to override maestrano? in your #{self.class.name} model"
24
+ end
25
+ end
26
+
27
+ # Check whether the SSO session is still valid
28
+ # or not
29
+ def maestrano_session_valid?(session)
30
+ Maestrano::SSO::Session.new(session).valid?
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module Maestrano
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,170 @@
1
+ # The contents of this file are subject to the terms
2
+ # of the Common Development and Distribution License
3
+ # (the License). You may not use this file except in
4
+ # compliance with the License.
5
+ #
6
+ # You can obtain a copy of the License at
7
+ # https://opensso.dev.java.net/public/CDDLv1.0.html or
8
+ # opensso/legal/CDDLv1.0.txt
9
+ # See the License for the specific language governing
10
+ # permission and limitations under the License.
11
+ #
12
+ # When distributing Covered Code, include this CDDL
13
+ # Header Notice in each file and include the License file
14
+ # at opensso/legal/CDDLv1.0.txt.
15
+ # If applicable, add the following below the CDDL Header,
16
+ # with the fields enclosed by brackets [] replaced by
17
+ # your own identifying information:
18
+ # "Portions Copyrighted [year] [name of copyright owner]"
19
+ #
20
+ # $Id: xml_sec.rb,v 1.6 2007/10/24 00:28:41 todddd Exp $
21
+ #
22
+ # Copyright 2007 Sun Microsystems Inc. All Rights Reserved
23
+ # Portions Copyrighted 2007 Todd W Saxton.
24
+
25
+ require 'rubygems'
26
+ require "rexml/document"
27
+ require "rexml/xpath"
28
+ require "openssl"
29
+ require 'nokogiri'
30
+ require "digest/sha1"
31
+ require "digest/sha2"
32
+ require "maestrano/saml/validation_error"
33
+
34
+ module Maestrano
35
+ module XMLSecurity
36
+ class SignedDocument < REXML::Document
37
+ C14N = "http://www.w3.org/2001/10/xml-exc-c14n#"
38
+ DSIG = "http://www.w3.org/2000/09/xmldsig#"
39
+
40
+ attr_accessor :signed_element_id
41
+
42
+ def initialize(response)
43
+ super(response)
44
+ extract_signed_element_id
45
+ end
46
+
47
+ def validate_document(idp_cert_fingerprint, soft = true)
48
+ # get cert from response
49
+ cert_element = REXML::XPath.first(self, "//ds:X509Certificate", { "ds"=>DSIG })
50
+ raise Maestrano::Saml::ValidationError.new("Certificate element missing in response (ds:X509Certificate)") unless cert_element
51
+ base64_cert = cert_element.text
52
+ cert_text = Base64.decode64(base64_cert)
53
+ cert = OpenSSL::X509::Certificate.new(cert_text)
54
+
55
+ # check cert matches registered idp cert
56
+ fingerprint = Digest::SHA1.hexdigest(cert.to_der)
57
+
58
+ if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
59
+ return soft ? false : (raise Maestrano::Saml::ValidationError.new("Fingerprint mismatch"))
60
+ end
61
+
62
+ validate_signature(base64_cert, soft)
63
+ end
64
+
65
+ def validate_signature(base64_cert, soft = true)
66
+ # validate references
67
+
68
+ # check for inclusive namespaces
69
+ inclusive_namespaces = extract_inclusive_namespaces
70
+
71
+ document = Nokogiri.parse(self.to_s)
72
+
73
+ # create a working copy so we don't modify the original
74
+ @working_copy ||= REXML::Document.new(self.to_s).root
75
+
76
+ # store and remove signature node
77
+ @sig_element ||= begin
78
+ element = REXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
79
+ element.remove
80
+ end
81
+
82
+
83
+ # verify signature
84
+ signed_info_element = REXML::XPath.first(@sig_element, "//ds:SignedInfo", {"ds"=>DSIG})
85
+ noko_sig_element = document.at_xpath('//ds:Signature', 'ds' => DSIG)
86
+ noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG)
87
+ canon_algorithm = canon_algorithm REXML::XPath.first(@sig_element, '//ds:CanonicalizationMethod', 'ds' => DSIG)
88
+ canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
89
+ noko_sig_element.remove
90
+
91
+ # check digests
92
+ REXML::XPath.each(@sig_element, "//ds:Reference", {"ds"=>DSIG}) do |ref|
93
+ uri = ref.attributes.get_attribute("URI").value
94
+
95
+ hashed_element = document.at_xpath("//*[@ID='#{uri[1..-1]}']")
96
+ canon_algorithm = canon_algorithm REXML::XPath.first(ref, '//ds:CanonicalizationMethod', 'ds' => DSIG)
97
+ canon_hashed_element = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces)
98
+
99
+ digest_algorithm = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod"))
100
+
101
+ hash = digest_algorithm.digest(canon_hashed_element)
102
+ digest_value = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)
103
+
104
+ unless digests_match?(hash, digest_value)
105
+ return soft ? false : (raise Maestrano::Saml::ValidationError.new("Digest mismatch"))
106
+ end
107
+ end
108
+
109
+ base64_signature = REXML::XPath.first(@sig_element, "//ds:SignatureValue", {"ds"=>DSIG}).text
110
+ signature = Base64.decode64(base64_signature)
111
+
112
+ # get certificate object
113
+ cert_text = Base64.decode64(base64_cert)
114
+ cert = OpenSSL::X509::Certificate.new(cert_text)
115
+
116
+ # signature method
117
+ signature_algorithm = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))
118
+
119
+ unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
120
+ return soft ? false : (raise Maestrano::Saml::ValidationError.new("Key validation error"))
121
+ end
122
+
123
+ return true
124
+ end
125
+
126
+ private
127
+
128
+ def digests_match?(hash, digest_value)
129
+ hash == digest_value
130
+ end
131
+
132
+ def extract_signed_element_id
133
+ reference_element = REXML::XPath.first(self, "//ds:Signature/ds:SignedInfo/ds:Reference", {"ds"=>DSIG})
134
+ self.signed_element_id = reference_element.attribute("URI").value[1..-1] unless reference_element.nil?
135
+ end
136
+
137
+ def canon_algorithm(element)
138
+ algorithm = element.attribute('Algorithm').value if element
139
+ case algorithm
140
+ when "http://www.w3.org/2001/10/xml-exc-c14n#" then Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
141
+ when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then Nokogiri::XML::XML_C14N_1_0
142
+ when "http://www.w3.org/2006/12/xml-c14n11" then Nokogiri::XML::XML_C14N_1_1
143
+ else Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
144
+ end
145
+ end
146
+
147
+ def algorithm(element)
148
+ algorithm = element.attribute("Algorithm").value if element
149
+ algorithm = algorithm && algorithm =~ /sha(.*?)$/i && $1.to_i
150
+ case algorithm
151
+ when 256 then OpenSSL::Digest::SHA256
152
+ when 384 then OpenSSL::Digest::SHA384
153
+ when 512 then OpenSSL::Digest::SHA512
154
+ else
155
+ OpenSSL::Digest::SHA1
156
+ end
157
+ end
158
+
159
+ def extract_inclusive_namespaces
160
+ if element = REXML::XPath.first(self, "//ec:InclusiveNamespaces", { "ec" => C14N })
161
+ prefix_list = element.attributes.get_attribute("PrefixList").value
162
+ prefix_list.split(" ")
163
+ else
164
+ []
165
+ end
166
+ end
167
+
168
+ end
169
+ end
170
+ end