omniauth-islykill 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 56fced1e74fbd3dfc280e4bcf348fe2d9d618108
4
+ data.tar.gz: 5b4c83f5ba4f4d904254024305263cf5643f6368
5
+ SHA512:
6
+ metadata.gz: 0aba1334e79e01ee4446173e95029afc09f0cfe55ae40b1fec260edf069d2c75ccf4dd305c8ada165bec73681aa1d1ae0eeea9d4ff84fc8940a2a64864f801aa
7
+ data.tar.gz: fdfc5a2a975b9d89e0ed82c9fc1dc74c35ef1ad3d211d67dfd716319625afac14ca5fbba8530b2be0a0beb47903577d75ff962b0681d90d46b894e8aaed20f9e
@@ -0,0 +1,2 @@
1
+ Changelog for omniauth-islykill
2
+ =================
@@ -0,0 +1,103 @@
1
+ # OmniAuth Islykill
2
+
3
+ This is a specific SAML strategy that handles authentication to Icelands Íslykill for OmniAuth
4
+
5
+ https://github.com/Algrim/omniauth-islykill
6
+
7
+ ## Requirements
8
+
9
+ * [OmniAuth](http://www.omniauth.org/) 1.2+
10
+ * [ruby-saml](https://github.com/onelogin/ruby-saml)
11
+ * Ruby 1.9.x or Ruby 2.1.x
12
+
13
+ ## Usage
14
+
15
+ Use the Islykill strategy in your Rails application:
16
+
17
+ in `Gemfile`:
18
+
19
+ ```ruby
20
+ gem 'omniauth-islykill'
21
+ ```
22
+
23
+ and in `config/initializers/omniauth.rb`:
24
+
25
+ ```ruby
26
+ Rails.application.config.middleware.use OmniAuth::Builder do
27
+ provider :islykill,
28
+ :assertion_consumer_service_url => "consumer_service_url",
29
+ :issuer => "Islyklar",
30
+ :idp_sso_target_url => "https://innskraning.island.is/?id=consumer_service_url",
31
+ :idp_cert => "-----BEGIN CERTIFICATE-----\n...-----END CERTIFICATE-----",
32
+ :idp_cert_fingerprint => "E7:91:B2:E1:...",
33
+ :name_identifier_format => "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
34
+ end
35
+ ```
36
+
37
+ For IdP-initiated SSO, users should directly access the IdP SSO target URL. Set the `href` of your application's login link to the value of `idp_sso_target_url`. For SP-initiated SSO, link to `/auth/saml`.
38
+
39
+ ## Metadata
40
+
41
+ The service provider metadata used to ease configuration of the SAML SP in the IdP can be retrieved from `http://example.com/auth/saml/metadata`. Send this URL to the administrator of the IdP.
42
+
43
+ ## Options
44
+
45
+ * `:assertion_consumer_service_url` - The URL at which the SAML assertion should be
46
+ received. If not provided, defaults to the OmniAuth callback URL (typically
47
+ `http://example.com/auth/saml/callback`). Optional.
48
+
49
+ * `:issuer` - The name of your application. Some identity providers might need this
50
+ to establish the identity of the service provider requesting the login. **Required**.
51
+
52
+ * `:idp_sso_target_url` - The URL to which the authentication request should be sent.
53
+ This would be on the identity provider. **Required**.
54
+
55
+ * `:idp_sso_target_url_runtime_params` - A dynamic mapping of request params that exist
56
+ during the request phase of OmniAuth that should to be sent to the IdP after a specific
57
+ mapping. So for example, a param `original_request_param` with value `original_param_value`,
58
+ could be sent to the IdP on the login request as `mapped_idp_param` with value
59
+ `original_param_value`. Optional.
60
+
61
+ * `:idp_cert` - The identity provider's certificate in PEM format. Takes precedence
62
+ over the fingerprint option below. This option or `:idp_cert_fingerprint` must
63
+ be present.
64
+
65
+ * `:idp_cert_fingerprint` - The SHA1 fingerprint of the certificate, e.g.
66
+ "90:CC:16:F0:8D:...". This is provided from the identity provider when setting up
67
+ the relationship. This option or `:idp_cert` must be present.
68
+
69
+ * `:name_identifier_format` - Used during SP-initiated SSO. Describes the format of
70
+ the username required by this application. If you need the email address, use
71
+ "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress". See
72
+ http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf section 8.3 for
73
+ other options. Note that the identity provider might not support all options.
74
+ If not specified, the IdP is free to choose the name identifier format used
75
+ in the response. Optional.
76
+
77
+ * See the `Onelogin::Saml::Settings` class in the [Ruby SAML gem](https://github.com/onelogin/ruby-saml) for additional supported options.
78
+
79
+ ## Authors
80
+
81
+ Authored by Björgvin Bæhrenz Þórðarson.
82
+
83
+ Maintained by [Björgvin Bæhrenz Þórðarson](https://github.com/Bjorgvin).
84
+
85
+ ## License
86
+
87
+ Permission is hereby granted, free of charge, to any person obtaining a copy
88
+ of this software and associated documentation files (the "Software"), to deal
89
+ in the Software without restriction, including without limitation the rights
90
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91
+ copies of the Software, and to permit persons to whom the Software is
92
+ furnished to do so, subject to the following conditions:
93
+
94
+ The above copyright notice and this permission notice shall be included in
95
+ all copies or substantial portions of the Software.
96
+
97
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
98
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
99
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
100
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
101
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
102
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
103
+ THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ require 'omniauth/strategies/islykill'
2
+ require 'omniauth/strategies/islykill/validation_error'
3
+ require 'signed_xml'
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module ISLYKILL
3
+ VERSION = '0.9.8'
4
+ end
5
+ end
@@ -0,0 +1,103 @@
1
+ require 'omniauth'
2
+ require 'ruby-saml'
3
+
4
+ module OmniAuth
5
+ module Strategies
6
+ class Islykill
7
+ include OmniAuth::Strategy
8
+
9
+ option :name_identifier_format, nil
10
+ option :idp_sso_target_url_runtime_params, {}
11
+
12
+ def request_phase
13
+ options[:assertion_consumer_service_url] ||= callback_url
14
+ runtime_request_parameters = options.delete(:idp_sso_target_url_runtime_params)
15
+
16
+ additional_params = {}
17
+ runtime_request_parameters.each_pair do |request_param_key, mapped_param_key|
18
+ additional_params[mapped_param_key] = request.params[request_param_key.to_s] if request.params.has_key?(request_param_key.to_s)
19
+ end if runtime_request_parameters
20
+
21
+ authn_request = Onelogin::Saml::Authrequest.new
22
+ settings = Onelogin::Saml::Settings.new(options)
23
+
24
+ redirect(authn_request.create(settings, additional_params))
25
+ end
26
+
27
+ def callback_phase
28
+ puts " ___ _ _ _ _ "
29
+ puts " / __ __ _| | | |__ __ _ ___| | __"
30
+ puts " / / / _` | | | '_ / _` |/ __| |/ /"
31
+ puts "/ /__| (_| | | | |_) | (_| | (__| < "
32
+ puts " ____/ __,_|_|_|_.__/ __,_| ___|_| _ "
33
+ puts " "
34
+
35
+ unless request.params['token']
36
+ raise OmniAuth::Strategies::Islykill::ValidationError.new("Islykill response missing")
37
+ end
38
+
39
+ token_base64 = request.params['token']
40
+ islykill_xml_saml_response = Base64.decode64(token_base64)
41
+ signedDocument = SignedXml::Document(islykill_xml_saml_response)
42
+ if !signedDocument.is_verified?
43
+ raise OmniAuth::Strategies::Islykill::ValidationError.new("Islykill response not valid")
44
+ end
45
+
46
+ # response is valid so we extract the information using xpath
47
+ xml_doc = REXML::Document.new(islykill_xml_saml_response)
48
+ prefix='Response/Assertion/AttributeStatement/Attribute[@Name="'
49
+ postfix='"]/AttributeValue'
50
+
51
+ @attributes={
52
+ name: REXML::XPath.first(xml_doc,"#{prefix}Name#{postfix}").text,
53
+ kennitala: REXML::XPath.first(xml_doc,"#{prefix}UserSSN#{postfix}").text,
54
+ provider: REXML::XPath.first(xml_doc,"#{prefix}Authentication#{postfix}").text
55
+ }
56
+
57
+ @name_id = REXML::XPath.first(xml_doc,"Response/Assertion/Subject/NameID/@NameQualifier").value()
58
+
59
+ if @name_id.nil? || @name_id.empty?
60
+ raise OmniAuth::Strategies::Islykill::ValidationError.new("SAML response missing 'name_id'")
61
+ end
62
+
63
+ super
64
+ rescue
65
+ fail!(:invalid_ticket, $!)
66
+ rescue Onelogin::Saml::ValidationError
67
+ fail!(:invalid_ticket, $!)
68
+ end
69
+
70
+ # def other_phase
71
+ # if on_path?("#{request_path}/metadata")
72
+ # # omniauth does not set the strategy on the other_phase
73
+ # @env['omniauth.strategy'] ||= self
74
+ # setup_phase
75
+
76
+ # response = Onelogin::Saml::Metadata.new
77
+ # settings = Onelogin::Saml::Settings.new(options)
78
+ # Rack::Response.new(response.generate(settings), 200, { "Content-Type" => "application/xml" }).finish
79
+ # else
80
+ # call_app!
81
+ # end
82
+ # end
83
+
84
+ uid {
85
+ #@name_id
86
+ @attributes[:kennitala]
87
+ }
88
+
89
+ info do
90
+ {
91
+ :name => @attributes[:name],
92
+ :kennitala => @attributes[:kennitala]
93
+ }
94
+ end
95
+
96
+ extra { { :raw_info => @attributes } }
97
+ end
98
+ end
99
+ end
100
+
101
+
102
+
103
+
@@ -0,0 +1,8 @@
1
+ module OmniAuth
2
+ module Strategies
3
+ class Islykill
4
+ class ValidationError < Exception
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,40 @@
1
+ require 'logger'
2
+ require 'nokogiri'
3
+
4
+ module SignedXml
5
+ XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
6
+
7
+ def self.Document(thing)
8
+ Document.new(thing)
9
+ end
10
+
11
+ # Logger that does nothing
12
+ BITBUCKET_LOGGER = Logger.new(nil)
13
+ class << BITBUCKET_LOGGER
14
+ def add(*args)
15
+ end
16
+ end
17
+
18
+ # The logger signed_xml should use
19
+ def self.logger
20
+ @@logger ||= BITBUCKET_LOGGER
21
+ end
22
+
23
+ # Set the logger for signed_xml
24
+ def self.logger=(a_logger)
25
+ @@logger = a_logger
26
+ end
27
+
28
+ autoload :Transformable, 'signed_xml/transformable'
29
+ autoload :Document, 'signed_xml/document'
30
+ autoload :Signature, 'signed_xml/signature'
31
+ autoload :SignedInfo, 'signed_xml/signed_info'
32
+ autoload :Reference, 'signed_xml/reference'
33
+ autoload :DigestMethodResolution, 'signed_xml/digest_method_resolution'
34
+ autoload :DigestTransform, 'signed_xml/digest_transform'
35
+ autoload :Base64Transform, 'signed_xml/base64_transform'
36
+ autoload :C14NTransform, 'signed_xml/c14n_transform'
37
+ autoload :EnvelopedSignatureTransform, 'signed_xml/enveloped_signature_transform'
38
+ autoload :Fingerprinting, 'signed_xml/fingerprinting'
39
+ autoload :Logging, 'signed_xml/logging'
40
+ end
@@ -0,0 +1,9 @@
1
+ require 'base64'
2
+
3
+ module SignedXml
4
+ class Base64Transform
5
+ def apply(input)
6
+ Base64.encode64(input).chomp
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ module SignedXml
2
+ class C14NTransform
3
+ include Nokogiri::XML
4
+
5
+ attr_reader :method
6
+ attr_reader :with_comments
7
+
8
+ def initialize(method = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
9
+ method, with_comments = method.split('#')
10
+ @method = case method
11
+ when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then XML_C14N_1_0
12
+ when "http://www.w3.org/2001/10/xml-exc-c14n" then XML_C14N_EXCLUSIVE_1_0
13
+ when "http://www.w3.org/2006/12/xml-c14n11" then XML_C14N_1_1
14
+ else raise ArgumentError, "unknown canonicalization method #{method}"
15
+ end
16
+
17
+ @with_comments = !!with_comments
18
+ end
19
+
20
+ def apply(input)
21
+ raise ArgumentError, "input #{input.inspect}:#{input.class} is not canonicalizable" unless input.respond_to?(:canonicalize)
22
+
23
+ input.canonicalize(method, nil, with_comments)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ require 'openssl'
2
+
3
+ module SignedXml
4
+ module DigestMethodResolution
5
+ include OpenSSL
6
+
7
+ def new_digester_for_id(id)
8
+ id = id && id =~ /sha(.*?)$/i && $1.to_i
9
+ case id
10
+ when 256 then OpenSSL::Digest::SHA256.new
11
+ when 384 then OpenSSL::Digest::SHA384.new
12
+ when 512 then OpenSSL::Digest::SHA512.new
13
+ when 1 then OpenSSL::Digest::SHA1.new
14
+ else
15
+ raise ArgumentError, "unknown digest method #{id}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ require "openssl"
2
+
3
+ module SignedXml
4
+ class DigestTransform
5
+ include DigestMethodResolution
6
+
7
+ attr_reader :digest
8
+
9
+ def initialize(method_id)
10
+ @digest = new_digester_for_id(method_id)
11
+ end
12
+
13
+ def apply(input)
14
+ digest.digest(input)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,70 @@
1
+ require "openssl"
2
+ require "options"
3
+
4
+ module SignedXml
5
+ class Document
6
+ include Logging
7
+
8
+ attr_reader :doc
9
+
10
+ def initialize(thing)
11
+ if thing.is_a? Nokogiri::XML::Document
12
+ @doc = thing
13
+ else
14
+ @doc = Nokogiri::XML(thing)
15
+ end
16
+ end
17
+
18
+ def is_verifiable?
19
+ signatures.any?
20
+ end
21
+
22
+ def is_verified?(arg = nil)
23
+ unless is_verifiable?
24
+ logger.warn "document cannot be verified because it contains no <Signature> elements"
25
+ return false
26
+ end
27
+
28
+ if arg.respond_to? :public_key
29
+ set_public_key_for_signatures(arg)
30
+ elsif arg.respond_to? :has_key?
31
+ set_certificate_store_for_signatures(arg)
32
+ elsif !arg.nil?
33
+ raise ArgumentError, "#{arg.inspect}:#{arg.class} must have a public key or be a hash of public keys"
34
+ end
35
+
36
+ signatures.all?(&:is_verified?)
37
+ end
38
+
39
+ def sign(private_key, certificate = nil)
40
+ signatures.each { |sig| sig.sign(private_key, certificate) }
41
+ self
42
+ end
43
+
44
+ def to_xml
45
+ doc.to_xml
46
+ end
47
+
48
+ private
49
+
50
+ def signatures
51
+ @signatures ||= init_signatures
52
+ end
53
+
54
+ def init_signatures
55
+ signatures = []
56
+ doc.xpath("//ds:Signature", ds: XMLDSIG_NS).each do |signature_node|
57
+ signatures << Signature.new(signature_node)
58
+ end
59
+ signatures
60
+ end
61
+
62
+ def set_public_key_for_signatures(certificate)
63
+ signatures.each { |sig| sig.public_key = certificate.public_key }
64
+ end
65
+
66
+ def set_certificate_store_for_signatures(cert_store)
67
+ signatures.each { |sig| sig.certificate_store = cert_store }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,10 @@
1
+ module SignedXml
2
+ class EnvelopedSignatureTransform
3
+ def apply(input)
4
+ envelope = Nokogiri::XML::Document.new
5
+ envelope.root = input
6
+ envelope.at_xpath('//ds:Signature', ds: XMLDSIG_NS).remove
7
+ envelope
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require 'digest'
2
+
3
+ module SignedXml
4
+ module Fingerprinting
5
+ def fingerprint(data)
6
+ Digest::SHA1.hexdigest(data)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module SignedXml
2
+ # Logging stuff borrowed from https://github.com/pezra/saml-sp
3
+
4
+ module Logging
5
+ def logger
6
+ SignedXml.logger
7
+ end
8
+
9
+ def self.included(base)
10
+ base.extend(self)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,73 @@
1
+ module SignedXml
2
+ class Reference
3
+ include Transformable
4
+ include Logging
5
+
6
+ attr_reader :here, :start
7
+
8
+ def initialize(here)
9
+ @here = here
10
+
11
+ uri = here['URI']
12
+ case uri
13
+ when nil, ""
14
+ @start = here.document.root
15
+ when /^#/
16
+ id = uri.split('#').last
17
+ raise ArgumentError, "XPointer expressions like #{id} are not yet supported" if id =~ /^xpointer/
18
+ # TODO: handle ID attrs with names other than 'ID'
19
+ @start = here.document.at_xpath("//*[@ID='#{id}']")
20
+ raise ArgumentError, "no match found for ID #{id}" if @start.nil?
21
+ else
22
+ raise ArgumentError, "unsupported Reference URI #{uri}"
23
+ end
24
+
25
+ @transforms = init_transforms
26
+ end
27
+
28
+ def is_verified?
29
+ result = apply_transforms == digest_value
30
+ logger.info "verification failed for digest value [#{digest_value}]" unless result
31
+ result
32
+ end
33
+
34
+ def compute_and_set_digest_value
35
+ digest_value_node.content = apply_transforms
36
+ logger.debug "set digest value to [#{digest_value}]"
37
+ end
38
+
39
+ private
40
+
41
+ def init_transforms
42
+ transforms = []
43
+
44
+ here.xpath('.//ds:Transform', ds: XMLDSIG_NS).each do |transform_node|
45
+ method = transform_node['Algorithm']
46
+ case method
47
+ when "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
48
+ transforms << EnvelopedSignatureTransform.new
49
+ when %r{^http://.*c14n}
50
+ transforms << C14NTransform.new(method)
51
+ else
52
+ raise ArgumentError, "unknown transform method #{method}"
53
+ end
54
+ end
55
+
56
+ # If no explicit c14n transform is specified, make sure we do one before digesting.
57
+ transforms << C14NTransform.new unless transforms.last.is_a? C14NTransform
58
+
59
+ digest_method = here.at_xpath('//ds:DigestMethod/@Algorithm', ds: XMLDSIG_NS).value.strip
60
+ transforms << DigestTransform.new(digest_method)
61
+
62
+ transforms << Base64Transform.new
63
+ end
64
+
65
+ def digest_value
66
+ @digest_value ||= digest_value_node.text.strip
67
+ end
68
+
69
+ def digest_value_node
70
+ @digest_value_node ||= here.at_xpath('ds:DigestValue', ds: XMLDSIG_NS)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,137 @@
1
+ require 'base64'
2
+
3
+ module SignedXml
4
+ class Signature
5
+ include DigestMethodResolution
6
+ include Fingerprinting
7
+ include Logging
8
+
9
+ attr_accessor :here
10
+ attr_accessor :public_key
11
+ attr_accessor :certificate_store
12
+
13
+ def initialize(here)
14
+ @here = here
15
+ end
16
+
17
+ def is_verified?
18
+ is_signed_info_verified? && are_reference_digests_verified?
19
+ end
20
+
21
+ def sign(private_key, certificate = nil)
22
+ compute_digests_for_references
23
+ sign_signed_info(private_key)
24
+ set_certificate_data(certificate)
25
+ end
26
+
27
+ private
28
+
29
+ def is_signed_info_verified?
30
+ return false if public_key.nil?
31
+
32
+ result = public_key.verify(new_digester_for_id(signed_info.signature_method), decoded_value, signed_info.apply_transforms)
33
+ logger.info "verification of signature value [#{value}] failed" unless result
34
+ result
35
+ end
36
+
37
+ def are_reference_digests_verified?
38
+ references.all?(&:is_verified?)
39
+ end
40
+
41
+ def sign_signed_info(private_key)
42
+ data = signed_info.apply_transforms
43
+ logger.debug "data to sign: [#{data}]"
44
+ digester = new_digester_for_id(signed_info.signature_method)
45
+ logger.debug "digester: #{digester.inspect}"
46
+ sig_value = private_key.sign(digester, data)
47
+ logger.debug "signature value (before Base64 encoding): [#{sig_value}]"
48
+ value_node.content = Base64Transform.new.apply(sig_value)
49
+ logger.debug "SignatureValue set to [#{value}]"
50
+ end
51
+
52
+ def compute_digests_for_references
53
+ references.each(&:compute_and_set_digest_value)
54
+ end
55
+
56
+ def set_certificate_data(certificate)
57
+ x509_cert_data_node.content = certificate.to_pem.split("\n")[1..-2].join("\n") if certificate
58
+ logger.debug "set certificate data to [#{x509_cert_data}]"
59
+ end
60
+
61
+ def references
62
+ @references ||= init_references
63
+ end
64
+
65
+ def init_references
66
+ references = []
67
+
68
+ here.xpath('//ds:Reference', ds: XMLDSIG_NS).each do |reference_node|
69
+ references << Reference.new(reference_node)
70
+ end
71
+
72
+ references
73
+ end
74
+
75
+ def decoded_value
76
+ @decoded_value ||= Base64.decode64 value
77
+ end
78
+
79
+ def value
80
+ @value ||= value_node.text.strip
81
+ end
82
+
83
+ def value_node
84
+ @value_node ||= here.at_xpath('//ds:SignatureValue', ds: XMLDSIG_NS)
85
+ end
86
+
87
+ def signed_info
88
+ @signed_info ||= SignedInfo.new(here.at_xpath("//ds:SignedInfo", ds: XMLDSIG_NS))
89
+ end
90
+
91
+ def certificate_store
92
+ @certificate_store ||= {}
93
+ end
94
+
95
+ def public_key
96
+ # If the user provided a certificate store, we MUST only use a
97
+ # key which matches the one in the signature's KeyInfo. Otherwise,
98
+ # use the key in the signature.
99
+ @public_key ||= if certificate_store.any?
100
+ logger.debug "using cert store #{certificate_store}"
101
+ if certificate_store.has_key? x509_cert_fingerprint
102
+ certificate_store[x509_cert_fingerprint].public_key
103
+ else
104
+ logger.warn "Store has no certificate with fingerprint #{x509_cert_fingerprint}. Signature validation will fail."
105
+ nil
106
+ end
107
+ else
108
+ x509_certificate.public_key
109
+ end
110
+ end
111
+
112
+ def x509_certificate
113
+ OpenSSL::X509::Certificate.new(certificate(x509_cert_data))
114
+ end
115
+
116
+ def x509_cert_fingerprint
117
+ @x509_cert_fingerprint ||= fingerprint(x509_certificate.to_der)
118
+ end
119
+
120
+ def x509_cert_data
121
+ x509_cert_data_node.text
122
+ end
123
+
124
+ def x509_cert_data_node
125
+ @x509_cert_data_node ||= here.at_xpath("//ds:X509Certificate", ds: XMLDSIG_NS)
126
+ end
127
+
128
+ def certificate(data)
129
+ "-----BEGIN CERTIFICATE-----\n#{wrap_text(data, 64)}-----END CERTIFICATE-----\n"
130
+ end
131
+
132
+ # http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
133
+ def wrap_text(txt, col = 80)
134
+ txt.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/, "\\1\\3\n")
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,17 @@
1
+ module SignedXml
2
+ class SignedInfo
3
+ include Transformable
4
+
5
+ attr_reader :start, :signature_method
6
+
7
+ def initialize(here)
8
+ @start = here
9
+
10
+ canonicalization_method = here.at_xpath('//ds:CanonicalizationMethod/@Algorithm', ds: XMLDSIG_NS).value.strip
11
+
12
+ transforms << C14NTransform.new(canonicalization_method)
13
+
14
+ @signature_method = here.at_xpath('//ds:SignatureMethod/@Algorithm', ds: XMLDSIG_NS).value.strip
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module SignedXml
2
+ module Transformable
3
+ include Logging
4
+
5
+ def transforms
6
+ @transforms ||= []
7
+ end
8
+
9
+ def apply_transforms
10
+ transforms.reduce(start) do |input, transform|
11
+ logger.debug "applying transform #{transform.inspect}"
12
+ logger.debug "input: [#{input}]"
13
+
14
+ result = transform.apply(input)
15
+ logger.debug "output: [#{result}]"
16
+ result
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module SignedXml
2
+ VERSION = "1.0.2"
3
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth-islykill
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.8
5
+ platform: ruby
6
+ authors:
7
+ - Bjorgvin Thordarson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: omniauth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby-saml
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.7.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.7.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: options
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: This is a specific SAML strategy that handles authentication to Icelands
70
+ Íslykill for OmniAuth.
71
+ email: algrim.is@outlook.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - CHANGELOG.md
78
+ - lib/signed_xml.rb
79
+ - lib/signed_xml/c14n_transform.rb
80
+ - lib/signed_xml/signed_info.rb
81
+ - lib/signed_xml/digest_transform.rb
82
+ - lib/signed_xml/document.rb
83
+ - lib/signed_xml/enveloped_signature_transform.rb
84
+ - lib/signed_xml/reference.rb
85
+ - lib/signed_xml/base64_transform.rb
86
+ - lib/signed_xml/version.rb
87
+ - lib/signed_xml/digest_method_resolution.rb
88
+ - lib/signed_xml/logging.rb
89
+ - lib/signed_xml/fingerprinting.rb
90
+ - lib/signed_xml/transformable.rb
91
+ - lib/signed_xml/signature.rb
92
+ - lib/omniauth-islykill.rb
93
+ - lib/omniauth-islykill/version.rb
94
+ - lib/omniauth/strategies/islykill/validation_error.rb
95
+ - lib/omniauth/strategies/islykill.rb
96
+ homepage: https://github.com/Algrim/omniauth-islykill
97
+ licenses:
98
+ - ''
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.1.9
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: This is a specific SAML strategy that handles authentication to Icelands
120
+ Íslykill for OmniAuth.
121
+ test_files: []