saml_idp 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +197 -0
- data/app/controllers/saml_idp/idp_controller.rb +42 -0
- data/app/views/saml_idp/idp/new.html.erb +21 -0
- data/app/views/saml_idp/idp/saml_post.html.erb +13 -0
- data/lib/saml_idp.rb +92 -0
- data/lib/saml_idp/algorithmable.rb +19 -0
- data/lib/saml_idp/assertion_builder.rb +144 -0
- data/lib/saml_idp/attribute_decorator.rb +27 -0
- data/lib/saml_idp/attributeable.rb +24 -0
- data/lib/saml_idp/configurator.rb +45 -0
- data/lib/saml_idp/controller.rb +71 -0
- data/lib/saml_idp/default.rb +28 -0
- data/lib/saml_idp/engine.rb +5 -0
- data/lib/saml_idp/hashable.rb +26 -0
- data/lib/saml_idp/incoming_metadata.rb +144 -0
- data/lib/saml_idp/metadata_builder.rb +158 -0
- data/lib/saml_idp/name_id_formatter.rb +68 -0
- data/lib/saml_idp/persisted_metadata.rb +10 -0
- data/lib/saml_idp/request.rb +79 -0
- data/lib/saml_idp/response_builder.rb +60 -0
- data/lib/saml_idp/saml_response.rb +63 -0
- data/lib/saml_idp/service_provider.rb +68 -0
- data/lib/saml_idp/signable.rb +131 -0
- data/lib/saml_idp/signature_builder.rb +42 -0
- data/lib/saml_idp/signed_info_builder.rb +51 -0
- data/lib/saml_idp/version.rb +4 -0
- data/lib/saml_idp/xml_security.rb +168 -0
- data/saml_idp.gemspec +38 -0
- data/spec/acceptance/acceptance_helper.rb +9 -0
- data/spec/acceptance/idp_controller_spec.rb +16 -0
- data/spec/lib/saml_idp/algorithmable_spec.rb +48 -0
- data/spec/lib/saml_idp/assertion_builder_spec.rb +27 -0
- data/spec/lib/saml_idp/attribute_decorator_spec.rb +31 -0
- data/spec/lib/saml_idp/configurator_spec.rb +30 -0
- data/spec/lib/saml_idp/controller_spec.rb +51 -0
- data/spec/lib/saml_idp/metadata_builder_spec.rb +9 -0
- data/spec/lib/saml_idp/name_id_formatter_spec.rb +39 -0
- data/spec/lib/saml_idp/request_spec.rb +14 -0
- data/spec/lib/saml_idp/response_builder_spec.rb +32 -0
- data/spec/lib/saml_idp/saml_response_spec.rb +27 -0
- data/spec/lib/saml_idp/service_provider_spec.rb +21 -0
- data/spec/lib/saml_idp/signable_spec.rb +74 -0
- data/spec/lib/saml_idp/signature_builder_spec.rb +19 -0
- data/spec/lib/saml_idp/signed_info_builder_spec.rb +25 -0
- data/spec/rails_app/.gitignore +15 -0
- data/spec/rails_app/README.rdoc +261 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +15 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/controllers/saml_controller.rb +8 -0
- data/spec/rails_app/app/controllers/saml_idp_controller.rb +11 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.gitkeep +0 -0
- data/spec/rails_app/app/models/.gitkeep +0 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +60 -0
- data/spec/rails_app/config/boot.rb +6 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +37 -0
- data/spec/rails_app/config/environments/production.rb +67 -0
- data/spec/rails_app/config/environments/test.rb +37 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +15 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +6 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/doc/README_FOR_APP +2 -0
- data/spec/rails_app/lib/assets/.gitkeep +0 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/log/.gitkeep +0 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +25 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/index.html +241 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/rails_app/test/fixtures/.gitkeep +0 -0
- data/spec/rails_app/test/functional/.gitkeep +0 -0
- data/spec/rails_app/test/integration/.gitkeep +0 -0
- data/spec/rails_app/test/performance/browsing_test.rb +12 -0
- data/spec/rails_app/test/test_helper.rb +13 -0
- data/spec/rails_app/test/unit/.gitkeep +0 -0
- data/spec/rails_app/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/support/certificates/certificate1 +12 -0
- data/spec/support/certificates/r1_certificate2_base64 +1 -0
- data/spec/support/responses/adfs_response_sha1.xml +46 -0
- data/spec/support/responses/adfs_response_sha256.xml +46 -0
- data/spec/support/responses/adfs_response_sha384.xml +46 -0
- data/spec/support/responses/adfs_response_sha512.xml +46 -0
- data/spec/support/responses/logoutresponse_fixtures.rb +67 -0
- data/spec/support/responses/no_signature_ns.xml +48 -0
- data/spec/support/responses/open_saml_response.xml +56 -0
- data/spec/support/responses/r1_response6.xml.base64 +1 -0
- data/spec/support/responses/response1.xml.base64 +1 -0
- data/spec/support/responses/response2.xml.base64 +79 -0
- data/spec/support/responses/response3.xml.base64 +66 -0
- data/spec/support/responses/response4.xml.base64 +93 -0
- data/spec/support/responses/response5.xml.base64 +102 -0
- data/spec/support/responses/response_with_ampersands.xml +139 -0
- data/spec/support/responses/response_with_ampersands.xml.base64 +93 -0
- data/spec/support/responses/simple_saml_php.xml +71 -0
- data/spec/support/responses/starfield_response.xml.base64 +1 -0
- data/spec/support/responses/wrapped_response_2.xml.base64 +150 -0
- data/spec/support/saml_request_macros.rb +19 -0
- data/spec/support/security_helpers.rb +61 -0
- data/spec/xml_security_spec.rb +136 -0
- metadata +407 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
module SamlIdp
|
2
|
+
class NameIdFormatter
|
3
|
+
attr_accessor :list
|
4
|
+
def initialize(list)
|
5
|
+
self.list = (list || {})
|
6
|
+
end
|
7
|
+
|
8
|
+
def all
|
9
|
+
if split?
|
10
|
+
one_one.map { |key_val| build("1.1", key_val)[:name] } +
|
11
|
+
two_zero.map { |key_val| build("2.0", key_val)[:name] }
|
12
|
+
else
|
13
|
+
list.map { |key_val| build("2.0", key_val)[:name] }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def chosen
|
18
|
+
if split?
|
19
|
+
version, choose = "1.1", one_one.first
|
20
|
+
version, choose = "2.0", two_zero.first unless choose
|
21
|
+
version, choose = "2.0", "persistent" unless choose
|
22
|
+
build(version, choose)
|
23
|
+
else
|
24
|
+
choose = list.first || "persistent"
|
25
|
+
build("2.0", choose)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def build(version, key_val)
|
30
|
+
key_val = Array(key_val)
|
31
|
+
name = key_val.first.to_s.underscore
|
32
|
+
getter = build_getter key_val.last || name
|
33
|
+
{
|
34
|
+
name: "urn:oasis:names:tc:SAML:#{version}:nameid-format:#{name.camelize(:lower)}",
|
35
|
+
getter: getter
|
36
|
+
}
|
37
|
+
end
|
38
|
+
private :build
|
39
|
+
|
40
|
+
def build_getter(getter_val)
|
41
|
+
if getter_val.respond_to?(:call)
|
42
|
+
getter_val
|
43
|
+
else
|
44
|
+
->(p) { p.public_send getter_val.to_s }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
private :build_getter
|
48
|
+
|
49
|
+
def split?
|
50
|
+
list.is_a?(Hash) && (list.key?("2.0") || list.key?("1.1"))
|
51
|
+
end
|
52
|
+
private :split?
|
53
|
+
|
54
|
+
def one_one
|
55
|
+
list["1.1"] || {}
|
56
|
+
rescue TypeError
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
private :one_one
|
60
|
+
|
61
|
+
def two_zero
|
62
|
+
list["2.0"] || {}
|
63
|
+
rescue TypeError
|
64
|
+
{}
|
65
|
+
end
|
66
|
+
private :two_zero
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'saml_idp/xml_security'
|
2
|
+
require 'saml_idp/service_provider'
|
3
|
+
module SamlIdp
|
4
|
+
class Request
|
5
|
+
def self.from_deflated_request(raw)
|
6
|
+
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
7
|
+
inflated = zstream.inflate(Base64.decode64(raw)).tap do
|
8
|
+
zstream.finish
|
9
|
+
zstream.close
|
10
|
+
end
|
11
|
+
new(inflated)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :raw_xml
|
15
|
+
|
16
|
+
delegate :config, to: :SamlIdp
|
17
|
+
private :config
|
18
|
+
delegate :xpath, to: :document
|
19
|
+
private :xpath
|
20
|
+
|
21
|
+
def initialize(raw_xml = "")
|
22
|
+
self.raw_xml = raw_xml
|
23
|
+
end
|
24
|
+
|
25
|
+
def request_id
|
26
|
+
authn_request["ID"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def acs_url
|
30
|
+
authn_request["AssertionConsumerServiceURL"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def valid_signature?
|
34
|
+
service_provider.valid_signature? document
|
35
|
+
end
|
36
|
+
|
37
|
+
def service_provider?
|
38
|
+
service_provider.valid?
|
39
|
+
end
|
40
|
+
|
41
|
+
def service_provider
|
42
|
+
@service_provider ||= ServiceProvider.new((service_provider_finder[issuer] || {}).merge(identifier: issuer))
|
43
|
+
end
|
44
|
+
|
45
|
+
def issuer
|
46
|
+
xpath("//saml:Issuer", saml: assertion).first.try :content
|
47
|
+
end
|
48
|
+
|
49
|
+
def document
|
50
|
+
@document ||= Saml::XML::Document.parse(raw_xml)
|
51
|
+
end
|
52
|
+
private :document
|
53
|
+
|
54
|
+
def authn_request
|
55
|
+
xpath("//samlp:AuthnRequest", samlp: samlp).first
|
56
|
+
end
|
57
|
+
private :authn_request
|
58
|
+
|
59
|
+
def samlp
|
60
|
+
Saml::XML::Namespaces::PROTOCOL
|
61
|
+
end
|
62
|
+
private :samlp
|
63
|
+
|
64
|
+
def assertion
|
65
|
+
Saml::XML::Namespaces::ASSERTION
|
66
|
+
end
|
67
|
+
private :assertion
|
68
|
+
|
69
|
+
def signature_namespace
|
70
|
+
Saml::XML::Namespaces::SIGNATURE
|
71
|
+
end
|
72
|
+
private :signature_namespace
|
73
|
+
|
74
|
+
def service_provider_finder
|
75
|
+
config.service_provider.finder
|
76
|
+
end
|
77
|
+
private :service_provider_finder
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'builder'
|
2
|
+
module SamlIdp
|
3
|
+
class ResponseBuilder
|
4
|
+
attr_accessor :response_id
|
5
|
+
attr_accessor :issuer_uri
|
6
|
+
attr_accessor :saml_acs_url
|
7
|
+
attr_accessor :saml_request_id
|
8
|
+
attr_accessor :assertion_and_signature
|
9
|
+
|
10
|
+
def initialize(response_id, issuer_uri, saml_acs_url, saml_request_id, assertion_and_signature)
|
11
|
+
self.response_id = response_id
|
12
|
+
self.issuer_uri = issuer_uri
|
13
|
+
self.saml_acs_url = saml_acs_url
|
14
|
+
self.saml_request_id = saml_request_id
|
15
|
+
self.assertion_and_signature = assertion_and_signature
|
16
|
+
end
|
17
|
+
|
18
|
+
def encoded
|
19
|
+
@encoded ||= encode
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw
|
23
|
+
build
|
24
|
+
end
|
25
|
+
|
26
|
+
def encode
|
27
|
+
Base64.encode64(raw)
|
28
|
+
end
|
29
|
+
private :encode
|
30
|
+
|
31
|
+
def build
|
32
|
+
builder = Builder::XmlMarkup.new
|
33
|
+
builder.tag! "samlp:Response",
|
34
|
+
ID: response_id_string,
|
35
|
+
Version: "2.0",
|
36
|
+
IssueInstant: now_iso,
|
37
|
+
Destination: saml_acs_url,
|
38
|
+
Consent: Saml::XML::Namespaces::Consents::UNSPECIFIED,
|
39
|
+
InResponseTo: saml_request_id,
|
40
|
+
"xmlns:samlp" => Saml::XML::Namespaces::PROTOCOL do |response|
|
41
|
+
response.Issuer issuer_uri, xmlns: Saml::XML::Namespaces::ASSERTION
|
42
|
+
response.tag! "samlp:Status" do |status|
|
43
|
+
status.tag! "samlp:StatusCode", Value: Saml::XML::Namespaces::Statuses::SUCCESS
|
44
|
+
end
|
45
|
+
response << assertion_and_signature
|
46
|
+
end
|
47
|
+
end
|
48
|
+
private :build
|
49
|
+
|
50
|
+
def response_id_string
|
51
|
+
"_#{response_id}"
|
52
|
+
end
|
53
|
+
private :response_id_string
|
54
|
+
|
55
|
+
def now_iso
|
56
|
+
Time.now.utc.iso8601
|
57
|
+
end
|
58
|
+
private :now_iso
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'saml_idp/assertion_builder'
|
2
|
+
require 'saml_idp/response_builder'
|
3
|
+
module SamlIdp
|
4
|
+
class SamlResponse
|
5
|
+
attr_accessor :assertion_with_signature
|
6
|
+
attr_accessor :reference_id
|
7
|
+
attr_accessor :response_id
|
8
|
+
attr_accessor :issuer_uri
|
9
|
+
attr_accessor :principal
|
10
|
+
attr_accessor :audience_uri
|
11
|
+
attr_accessor :saml_request_id
|
12
|
+
attr_accessor :saml_acs_url
|
13
|
+
attr_accessor :algorithm
|
14
|
+
attr_accessor :secret_key
|
15
|
+
attr_accessor :x509_certificate
|
16
|
+
|
17
|
+
def initialize(reference_id,
|
18
|
+
response_id,
|
19
|
+
issuer_uri,
|
20
|
+
principal,
|
21
|
+
audience_uri,
|
22
|
+
saml_request_id,
|
23
|
+
saml_acs_url,
|
24
|
+
algorithm
|
25
|
+
)
|
26
|
+
self.reference_id = reference_id
|
27
|
+
self.response_id = response_id
|
28
|
+
self.issuer_uri = issuer_uri
|
29
|
+
self.principal = principal
|
30
|
+
self.audience_uri = audience_uri
|
31
|
+
self.saml_request_id = saml_request_id
|
32
|
+
self.saml_acs_url = saml_acs_url
|
33
|
+
self.algorithm = algorithm
|
34
|
+
self.secret_key = secret_key
|
35
|
+
self.x509_certificate = x509_certificate
|
36
|
+
end
|
37
|
+
|
38
|
+
def build
|
39
|
+
@built ||= response_builder.encoded
|
40
|
+
end
|
41
|
+
|
42
|
+
def signed_assertion
|
43
|
+
assertion_builder.signed
|
44
|
+
end
|
45
|
+
private
|
46
|
+
|
47
|
+
def response_builder
|
48
|
+
ResponseBuilder.new(response_id, issuer_uri, saml_acs_url, saml_request_id, signed_assertion)
|
49
|
+
end
|
50
|
+
private :response_builder
|
51
|
+
|
52
|
+
def assertion_builder
|
53
|
+
@assertion_builder ||= AssertionBuilder.new reference_id,
|
54
|
+
issuer_uri,
|
55
|
+
principal,
|
56
|
+
audience_uri,
|
57
|
+
saml_request_id,
|
58
|
+
saml_acs_url,
|
59
|
+
algorithm
|
60
|
+
end
|
61
|
+
private :assertion_builder
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'saml_idp/attributeable'
|
3
|
+
require 'saml_idp/incoming_metadata'
|
4
|
+
require 'saml_idp/persisted_metadata'
|
5
|
+
module SamlIdp
|
6
|
+
class ServiceProvider
|
7
|
+
include Attributeable
|
8
|
+
attribute :identifier
|
9
|
+
attribute :fingerprint
|
10
|
+
attribute :metadata_url
|
11
|
+
|
12
|
+
delegate :config, to: :SamlIdp
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
attributes.present?
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_signature?(doc)
|
19
|
+
!should_validate_signature? ||
|
20
|
+
doc.valid_signature?(fingerprint)
|
21
|
+
end
|
22
|
+
|
23
|
+
def should_validate_signature?
|
24
|
+
current_metadata.respond_to?(:sign_assertions?) && current_metadata.sign_assertions?
|
25
|
+
end
|
26
|
+
|
27
|
+
def refresh_metadata
|
28
|
+
fresh = fresh_incoming_metadata
|
29
|
+
if valid_signature?(fresh.document)
|
30
|
+
metadata_persister[identifier, fresh]
|
31
|
+
@current_metadata = nil
|
32
|
+
fresh
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def current_metadata
|
37
|
+
@current_metadata ||= get_current_or_build
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_current_or_build
|
41
|
+
persisted = metadata_getter[identifier, self]
|
42
|
+
if persisted.is_a? Hash
|
43
|
+
PersistedMetadata.new(persisted)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
private :get_current_or_build
|
47
|
+
|
48
|
+
def metadata_getter
|
49
|
+
config.service_provider.persisted_metadata_getter
|
50
|
+
end
|
51
|
+
private :metadata_getter
|
52
|
+
|
53
|
+
def metadata_persister
|
54
|
+
config.service_provider.metadata_persister
|
55
|
+
end
|
56
|
+
private :metadata_persister
|
57
|
+
|
58
|
+
def fresh_incoming_metadata
|
59
|
+
IncomingMetadata.new request_metadata
|
60
|
+
end
|
61
|
+
private :fresh_incoming_metadata
|
62
|
+
|
63
|
+
def request_metadata
|
64
|
+
metadata_url.present? ? HTTParty.get(metadata_url).body : ""
|
65
|
+
end
|
66
|
+
private :request_metadata
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# Requires methods:
|
2
|
+
# * reference_id
|
3
|
+
# * raw
|
4
|
+
# * digest
|
5
|
+
# * algorithm
|
6
|
+
require 'saml_idp/signed_info_builder'
|
7
|
+
require 'saml_idp/signature_builder'
|
8
|
+
module SamlIdp
|
9
|
+
module Signable
|
10
|
+
def self.included(base)
|
11
|
+
base.extend ClassMethods
|
12
|
+
base.send :attr_accessor, :reference_id
|
13
|
+
end
|
14
|
+
|
15
|
+
def signed
|
16
|
+
generated_reference_id do
|
17
|
+
with_signature do
|
18
|
+
send(self.class.raw_method)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def sign(el)
|
24
|
+
el << signature if sign?
|
25
|
+
end
|
26
|
+
|
27
|
+
def generated_reference_id
|
28
|
+
if reference_id
|
29
|
+
fin = yield reference_id if block_given?
|
30
|
+
else
|
31
|
+
self.reference_id = ref = reference_id_generator.call
|
32
|
+
fin = yield reference_id if block_given?
|
33
|
+
self.reference_id = nil
|
34
|
+
end
|
35
|
+
block_given? ? fin : ref
|
36
|
+
end
|
37
|
+
private :generated_reference_id
|
38
|
+
|
39
|
+
def reference_id_generator
|
40
|
+
SamlIdp.config.reference_id_generator
|
41
|
+
end
|
42
|
+
private :reference_id_generator
|
43
|
+
|
44
|
+
def with_signature
|
45
|
+
original = @sign
|
46
|
+
@sign = true
|
47
|
+
yield.tap do
|
48
|
+
@sign = original
|
49
|
+
end
|
50
|
+
end
|
51
|
+
private :with_signature
|
52
|
+
|
53
|
+
def without_signature
|
54
|
+
original = @sign
|
55
|
+
@sign = false
|
56
|
+
yield.tap do
|
57
|
+
@sign = original
|
58
|
+
end
|
59
|
+
end
|
60
|
+
private :without_signature
|
61
|
+
|
62
|
+
def sign?
|
63
|
+
!!@sign
|
64
|
+
end
|
65
|
+
private :sign?
|
66
|
+
|
67
|
+
def signature
|
68
|
+
SignatureBuilder.new(signed_info_builder).raw
|
69
|
+
end
|
70
|
+
private :signature
|
71
|
+
|
72
|
+
def signed_info_builder
|
73
|
+
SignedInfoBuilder.new(get_reference_id, get_digest, get_algorithm)
|
74
|
+
end
|
75
|
+
private :signed_info_builder
|
76
|
+
|
77
|
+
def get_reference_id
|
78
|
+
send(self.class.reference_id_method)
|
79
|
+
end
|
80
|
+
private :get_reference_id
|
81
|
+
|
82
|
+
def get_digest
|
83
|
+
without_signature do
|
84
|
+
send(self.class.digest_method)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
private :get_digest
|
88
|
+
|
89
|
+
def get_algorithm
|
90
|
+
send(self.class.algorithm_method)
|
91
|
+
end
|
92
|
+
private :get_algorithm
|
93
|
+
|
94
|
+
def get_raw
|
95
|
+
send(self.class.raw_method)
|
96
|
+
end
|
97
|
+
private :get_raw
|
98
|
+
|
99
|
+
def noko_raw
|
100
|
+
Nokogiri::XML::Document.parse(get_raw)
|
101
|
+
end
|
102
|
+
private :noko_raw
|
103
|
+
|
104
|
+
def digest
|
105
|
+
# Make it check for inclusive at some point (https://github.com/onelogin/ruby-saml/blob/master/lib/xml_security.rb#L159)
|
106
|
+
inclusive_namespaces = []
|
107
|
+
# Also make customizable
|
108
|
+
canon_algorithm = Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
|
109
|
+
canon_hashed_element = noko_raw.canonicalize(canon_algorithm, inclusive_namespaces)
|
110
|
+
digest_algorithm = get_algorithm
|
111
|
+
|
112
|
+
hash = digest_algorithm.digest(canon_hashed_element)
|
113
|
+
Base64.encode64(hash).gsub(/\n/, '')
|
114
|
+
end
|
115
|
+
private :digest
|
116
|
+
|
117
|
+
module ClassMethods
|
118
|
+
def self.module_method(name, default = nil)
|
119
|
+
default ||= name
|
120
|
+
define_method "#{name}_method" do |new_method_name = nil|
|
121
|
+
instance_variable_set("@#{name}", new_method_name) if new_method_name
|
122
|
+
instance_variable_get("@#{name}") || default
|
123
|
+
end
|
124
|
+
end
|
125
|
+
module_method :raw
|
126
|
+
module_method :digest
|
127
|
+
module_method :algorithm
|
128
|
+
module_method :reference_id
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|