omniauth-islykill 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []