ruby-samlnechotech 0.7.34 → 0.7.35

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.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 83acf516a41f0c28c18108b8f5b5ffbcc4698e1a
4
- data.tar.gz: f83184add5a75fcf488b2ff879a5816e0298a2e6
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ M2Y3NTY1OWQyMmI4ZmY4YWRjNmI1ZTllNTQ0MzQ0MGYwNDZiZTEzZQ==
5
+ data.tar.gz: !binary |-
6
+ ODExYjkyMTg0YWM4NDcyOTRkYjQzZjZiNmNhNTg4YTdhZWExM2MzZQ==
5
7
  SHA512:
6
- metadata.gz: 6348a6a9abeb1d41a1851351c473aaa0c9643ace578a811ddd3c3090f960da79b37eba635f5a30bf0ea2b8924e65d6f79d2415a96e164569886922522d73e60f
7
- data.tar.gz: 45eb2a6a53c8c03977e26038e995a64c544cff803e9a6c47664057889ce383211515ee334af85db7d0ab3bf5bbbb07abfcdeb850daba145af68bb3159dfeb289
8
+ metadata.gz: !binary |-
9
+ OWEwMTY0OGY5YmI4ZGM5N2ZlZjRkZDRhZmNkZGY5MWIzZjY2ZTZmNzE2YjJj
10
+ MTE2OTJiOWU2OGFkZmNlYjg5MzJiZmJmNTg4NDgyM2Q1MjhlZWJmMTY3MjJj
11
+ N2NiZjQ1NWM2NjY3MWQ0MDJhNTJlNzZjZDBmMzA2NzVkYTFhNmU=
12
+ data.tar.gz: !binary |-
13
+ ZGI0OWZmMTU3NWUwNWRlMzI1NmExNTMzOTlhYmI4OWFkNGY0NzdlOGNhNmI4
14
+ ZTRlYjQ3ZTA3MzY2ZjU2N2VmNGZkOTc5NThjMmI3NThhYmY5NjRlY2NjYzE5
15
+ M2EyNTVjMmIzMjNjMzI3MzgzMWY5M2U1ZTEzOWRmMmI0MWYxNGI=
@@ -0,0 +1,75 @@
1
+ require 'cgi'
2
+ require 'zlib'
3
+ require 'base64'
4
+
5
+ module Onelogin
6
+ module Saml
7
+ class SamlMessage
8
+
9
+ ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
10
+ PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
11
+
12
+ def valid_saml?(document, soft = true)
13
+ Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
14
+ @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
15
+ @xml = Nokogiri::XML(document.to_s)
16
+ end
17
+ if soft
18
+ @schema.validate(@xml).map{ return false }
19
+ else
20
+ @schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
21
+ end
22
+ end
23
+
24
+ def validation_error(message)
25
+ raise ValidationError.new(message)
26
+ end
27
+
28
+ private
29
+
30
+ def decode_raw_saml(saml)
31
+ if saml =~ /^</
32
+ return saml
33
+ elsif (decoded = decode(saml)) =~ /^</
34
+ return decoded
35
+ elsif (inflated = inflate(decoded)) =~ /^</
36
+ return inflated
37
+ end
38
+
39
+ return nil
40
+ end
41
+
42
+ def encode_raw_saml(saml, settings)
43
+ saml = Zlib::Deflate.deflate(saml, 9)[2..-5] if settings.compress_request
44
+ base64_saml = Base64.encode64(saml)
45
+ return CGI.escape(base64_saml)
46
+ end
47
+
48
+ def decode(encoded)
49
+ Base64.decode64(encoded)
50
+ end
51
+
52
+ def encode(encoded)
53
+ Base64.encode64(encoded).gsub(/\n/, "")
54
+ end
55
+
56
+ def escape(unescaped)
57
+ CGI.escape(unescaped)
58
+ end
59
+
60
+ def unescape(escaped)
61
+ CGI.unescape(escaped)
62
+ end
63
+
64
+ def inflate(deflated)
65
+ zlib = Zlib::Inflate.new(-Zlib::MAX_WBITS)
66
+ zlib.inflate(deflated)
67
+ end
68
+
69
+ def deflate(inflated)
70
+ Zlib::Deflate.deflate(inflated, 9)[2..-5]
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,66 @@
1
+ require 'zlib'
2
+ require 'time'
3
+ require 'nokogiri'
4
+
5
+ # Only supports SAML 2.0
6
+ module Onelogin
7
+ module Saml
8
+ class SloLogoutrequest < SamlMessage
9
+ attr_reader :options
10
+ attr_reader :request
11
+ attr_reader :document
12
+
13
+ def initialize(request, options = {})
14
+ raise ArgumentError.new("Request cannot be nil") if request.nil?
15
+ @options = options
16
+ @request = decode_raw_saml(request)
17
+ @document = REXML::Document.new(@request)
18
+ end
19
+
20
+ def is_valid?
21
+ validate
22
+ end
23
+
24
+ def validate!
25
+ validate(false)
26
+ end
27
+
28
+ # The value of the user identifier as designated by the initialization request response
29
+ def name_id
30
+ @name_id ||= begin
31
+ node = REXML::XPath.first(document, "/p:LogoutRequest/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
32
+ node.nil? ? nil : node.text
33
+ end
34
+ end
35
+
36
+ def id
37
+ return @id if @id
38
+ element = REXML::XPath.first(document, "/p:LogoutRequest", {
39
+ "p" => PROTOCOL} )
40
+ return nil if element.nil?
41
+ return element.attributes["ID"]
42
+ end
43
+
44
+ def issuer
45
+ @issuer ||= begin
46
+ node = REXML::XPath.first(document, "/p:LogoutRequest/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
47
+ node.nil? ? nil : node.text
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def validate(soft = true)
54
+ valid_saml?(document, soft) && validate_request_state(soft)
55
+ end
56
+
57
+ def validate_request_state(soft = true)
58
+ if request.empty?
59
+ return soft ? false : validation_error("Blank request")
60
+ end
61
+ true
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,62 @@
1
+ module Onelogin
2
+ module Saml
3
+ class SloLogoutresponse < SamlMessage
4
+
5
+ def create(settings, request, logout_message = nil, params = {})
6
+ params = {} if params.nil?
7
+
8
+ response_doc = create_logout_response_xml_doc(settings, request, logout_message)
9
+ response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
10
+
11
+ response = ''
12
+ response_doc.write(response)
13
+
14
+ Logging.debug "Created SLO Logout Response: #{response}"
15
+
16
+ encoded_response = encode_raw_saml(response, settings)
17
+ params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
18
+ response_params = "#{params_prefix}SAMLResponse=#{encoded_response}"
19
+
20
+ params.each_pair do |key, value|
21
+ response_params << "&#{key.to_s}=#{escape(value.to_s)}"
22
+ end
23
+
24
+ settings.idp_slo_target_url + response_params
25
+ end
26
+
27
+ def create_logout_response_xml_doc(settings, request, logout_message = nil)
28
+ uuid = '_' + UUID.new.generate
29
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
30
+
31
+ response_doc = REXML::Document.new
32
+
33
+ root = response_doc.add_element 'samlp:LogoutResponse', { 'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol' }
34
+ root.attributes['ID'] = uuid
35
+ root.attributes['IssueInstant'] = time
36
+ root.attributes['Version'] = '2.0'
37
+ root.attributes['InResponseTo'] = request.id unless request.id.nil?
38
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil?
39
+
40
+ # add success message
41
+ status = root.add_element 'samlp:Status'
42
+
43
+ # success status code
44
+ status_code = status.add_element 'samlp:StatusCode'
45
+ status_code.attributes['Value'] = 'urn:oasis:names:tc:SAML:2.0:status:Success'
46
+
47
+ # success status message
48
+ logout_message ||= 'Successfully Signed Out'
49
+ status_message = status.add_element 'samlp:StatusMessage'
50
+ status_message.text = logout_message
51
+
52
+ if settings.issuer != nil
53
+ issuer = root.add_element "saml:Issuer", { "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
54
+ issuer.text = settings.issuer
55
+ end
56
+
57
+ response_doc
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -1,5 +1,5 @@
1
1
  module Onelogin
2
2
  module Saml
3
- VERSION = '0.7.34'
3
+ VERSION = '0.7.35'
4
4
  end
5
5
  end
@@ -7,3 +7,6 @@ require 'onelogin/ruby-samlnechotech/settings'
7
7
  require 'onelogin/ruby-samlnechotech/validation_error'
8
8
  require 'onelogin/ruby-samlnechotech/metadata'
9
9
  require 'onelogin/ruby-samlnechotech/version'
10
+ require 'onelogin/ruby-samlnechotech/saml_message'
11
+ require 'onelogin/ruby-samlnechotech/slo_logoutrequest'
12
+ require 'onelogin/ruby-samlnechotech/slo_logoutresponse'
@@ -0,0 +1,82 @@
1
+ #encoding: utf-8
2
+
3
+ def default_request_opts
4
+ {
5
+ :uuid => "_28024690-000e-0130-b6d2-38f6b112be8b",
6
+ :issue_instant => Time.now.strftime('%Y-%m-%dT%H:%M:%SZ'),
7
+ :settings => settings
8
+ }
9
+ end
10
+
11
+ def valid_request(opts = {})
12
+ opts = default_request_opts.merge!(opts)
13
+
14
+ "<samlp:LogoutRequest
15
+ xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
16
+ ID=\"#{random_id}\" Version=\"2.0\"
17
+ IssueInstant=\"#{opts[:issue_instant]}\"
18
+ Destination=\"#{opts[:settings].assertion_consumer_logout_service_url}\">
19
+ <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].issuer}</saml:Issuer>
20
+ </samlp:LogoutRequest>"
21
+ "<samlp:LogoutRequest ID=\"f8a62847-92f2-4f0c-936a-df9efe0cc42f\"
22
+ Version=\"2.0\"
23
+ IssueInstant=\"2013-08-29T20:53:50Z\"
24
+ Destination=\"https://server/adfs/ls/\"
25
+ Consent=\"urn:oasis:names:tc:SAML:2.0:consent:unspecified\"
26
+ xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
27
+ >
28
+ <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">https://sp.com/</saml:Issuer>
29
+ <Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">
30
+ <SignedInfo>
31
+ <CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\" />
32
+ <SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\" />
33
+ <Reference URI=\"#f8a62847-92f2-4f0c-936a-df9efe0cc42f\">
34
+ <Transforms>
35
+ <Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\" />
36
+ <Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\" />
37
+ </Transforms>
38
+ <DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\" />
39
+ <DigestValue>W7F1E2U1OAHRXn/ItbnsYZyXw/8=</DigestValue>
40
+ </Reference>
41
+ </SignedInfo>
42
+ <SignatureValue></SignatureValue>
43
+ <KeyInfo>
44
+ <X509Data>
45
+ <X509Certificate></X509Certificate>
46
+ </X509Data>
47
+ </KeyInfo>
48
+ </Signature>
49
+ <saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"
50
+ Format=\"http://schemas.xmlsoap.org/claims/UPN\"
51
+ >user</saml:NameID>
52
+ <samlp:SessionIndex>_2537f94b-a150-415e-9a45-3c6fa2b6dd60</samlp:SessionIndex>
53
+ </samlp:LogoutRequest>"
54
+ end
55
+
56
+ def invalid_xml_request
57
+ "<samlp:SomethingAwful
58
+ xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
59
+ ID=\"#{random_id}\" Version=\"2.0\">
60
+ </samlp:SomethingAwful>"
61
+ end
62
+
63
+ def settings
64
+ @settings ||= Onelogin::Saml::Settings.new(
65
+ {
66
+ :assertion_consumer_service_url => "http://app.muda.no/sso/consume",
67
+ :assertion_consumer_logout_service_url => "http://app.muda.no/sso/consume_logout",
68
+ :issuer => "http://app.muda.no",
69
+ :sp_name_qualifier => "http://sso.muda.no",
70
+ :idp_sso_target_url => "http://sso.muda.no/sso",
71
+ :idp_slo_target_url => "http://sso.muda.no/slo",
72
+ :idp_cert_fingerprint => "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
73
+ :name_identifier_format => "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
74
+ }
75
+ )
76
+ end
77
+
78
+ # logoutresponse fixtures
79
+ def random_id
80
+ "_#{UUID.new.generate}"
81
+ end
82
+
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
+ require 'rexml/document'
3
+ require 'requests/logoutrequest_fixtures'
4
+ class RubySamlTest < Test::Unit::TestCase
5
+
6
+ context "SloLogoutrequest" do
7
+ context "#new" do
8
+ should "raise an exception when request is initialized with nil" do
9
+ assert_raises(ArgumentError) { Onelogin::Saml::SloLogoutrequest.new(nil) }
10
+ end
11
+ should "accept constructor-injected options" do
12
+ logoutrequest= Onelogin::Saml::SloLogoutrequest.new(valid_request, { :foo => :bar} )
13
+ assert !logoutrequest.options.empty?
14
+ end
15
+ should "support base64 encoded responses" do
16
+ expected_request = valid_request
17
+ logoutrequest= Onelogin::Saml::SloLogoutrequest.new(Base64.encode64(expected_request))
18
+
19
+ assert_equal expected_request, logoutrequest.request
20
+ end
21
+ end
22
+
23
+ context "#validate!" do
24
+ should "validates good requests" do
25
+ logoutrequest = Onelogin::Saml::SloLogoutrequest.new(valid_request)
26
+ logoutrequest.validate!
27
+ end
28
+
29
+ should "raise error for invalid xml" do
30
+ logoutrequest = Onelogin::Saml::SloLogoutrequest.new(invalid_xml_request)
31
+ assert_raises(Onelogin::Saml::ValidationError) { logoutrequest.validate! }
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ # logoutresponse fixtures
38
+ def random_id
39
+ "_#{UUID.new.generate}"
40
+ end
41
+
42
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
+ require 'requests/logoutrequest_fixtures'
3
+
4
+ class SloResponseTest < Test::Unit::TestCase
5
+
6
+ context "SloLogoutresponse" do
7
+ settings = Onelogin::Saml::Settings.new
8
+ settings.idp_slo_target_url = "http://unauth.com/logout"
9
+ settings.name_identifier_value = "f00f00"
10
+ logoutrequest = Onelogin::Saml::SloLogoutrequest.new(valid_request)
11
+
12
+ should "create the deflated SAMLRequest URL parameter" do
13
+
14
+ unauth_url = Onelogin::Saml::SloLogoutresponse.new.create(settings, logoutrequest)
15
+ assert unauth_url =~ /^http:\/\/unauth\.com\/logout\?SAMLResponse=/
16
+
17
+ inflated = decode_saml_response_payload(unauth_url)
18
+
19
+ assert_match /^<samlp:LogoutResponse/, inflated
20
+ end
21
+
22
+ should "set InResponseTo" do
23
+
24
+ unauth_url = Onelogin::Saml::SloLogoutresponse.new.create(settings, logoutrequest)
25
+ inflated = decode_saml_response_payload(unauth_url)
26
+
27
+ assert_match %r(InResponseTo='#{logoutrequest.id}'), inflated
28
+
29
+ end
30
+
31
+ end
32
+
33
+ def decode_saml_response_payload(unauth_url)
34
+ payload = CGI.unescape(unauth_url.split("SAMLResponse=").last)
35
+ decoded = Base64.decode64(payload)
36
+
37
+ zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
38
+ inflated = zstream.inflate(decoded)
39
+ zstream.finish
40
+ zstream.close
41
+ inflated
42
+ end
43
+
44
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-samlnechotech
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.34
4
+ version: 0.7.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - OneLogin LLC, beekermememe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-24 00:00:00.000000000 Z
11
+ date: 2014-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: canonix
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: nokogiri
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ! '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: 1.5.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ! '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.5.0
55
55
  description: SAML toolkit for Ruby on Rails forked and modified by beekermememe
@@ -73,7 +73,10 @@ files:
73
73
  - lib/onelogin/ruby-samlnechotech/logoutresponse.rb
74
74
  - lib/onelogin/ruby-samlnechotech/metadata.rb
75
75
  - lib/onelogin/ruby-samlnechotech/response.rb
76
+ - lib/onelogin/ruby-samlnechotech/saml_message.rb
76
77
  - lib/onelogin/ruby-samlnechotech/settings.rb
78
+ - lib/onelogin/ruby-samlnechotech/slo_logoutrequest.rb
79
+ - lib/onelogin/ruby-samlnechotech/slo_logoutresponse.rb
77
80
  - lib/onelogin/ruby-samlnechotech/validation_error.rb
78
81
  - lib/onelogin/ruby-samlnechotech/version.rb
79
82
  - lib/ruby-samlnechotech.rb
@@ -88,6 +91,7 @@ files:
88
91
  - test/logoutrequest_test.rb
89
92
  - test/logoutresponse_test.rb
90
93
  - test/request_test.rb
94
+ - test/requests/logoutrequest_fixtures.rb
91
95
  - test/response_test.rb
92
96
  - test/responses/adfs_response_sha1.xml
93
97
  - test/responses/adfs_response_sha256.xml
@@ -108,6 +112,8 @@ files:
108
112
  - test/responses/starfield_response.xml.base64
109
113
  - test/responses/wrapped_response_2.xml.base64
110
114
  - test/settings_test.rb
115
+ - test/slologoutrequest_test.rb
116
+ - test/slologoutresponse_test.rb
111
117
  - test/test_helper.rb
112
118
  - test/xml_security_test.rb
113
119
  homepage: https://github.com/beekermememe/ruby-saml
@@ -120,17 +126,17 @@ require_paths:
120
126
  - lib
121
127
  required_ruby_version: !ruby/object:Gem::Requirement
122
128
  requirements:
123
- - - '>='
129
+ - - ! '>='
124
130
  - !ruby/object:Gem::Version
125
131
  version: '0'
126
132
  required_rubygems_version: !ruby/object:Gem::Requirement
127
133
  requirements:
128
- - - '>='
134
+ - - ! '>='
129
135
  - !ruby/object:Gem::Version
130
136
  version: '0'
131
137
  requirements: []
132
138
  rubyforge_project: http://www.rubygems.org/gems/ruby-samlnechotech
133
- rubygems_version: 2.0.3
139
+ rubygems_version: 2.1.11
134
140
  signing_key:
135
141
  specification_version: 4
136
142
  summary: SAML Ruby Tookit
@@ -140,6 +146,7 @@ test_files:
140
146
  - test/logoutrequest_test.rb
141
147
  - test/logoutresponse_test.rb
142
148
  - test/request_test.rb
149
+ - test/requests/logoutrequest_fixtures.rb
143
150
  - test/response_test.rb
144
151
  - test/responses/adfs_response_sha1.xml
145
152
  - test/responses/adfs_response_sha256.xml
@@ -160,5 +167,7 @@ test_files:
160
167
  - test/responses/starfield_response.xml.base64
161
168
  - test/responses/wrapped_response_2.xml.base64
162
169
  - test/settings_test.rb
170
+ - test/slologoutrequest_test.rb
171
+ - test/slologoutresponse_test.rb
163
172
  - test/test_helper.rb
164
173
  - test/xml_security_test.rb