saml-kit 1.0.9 → 1.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/Gemfile +2 -0
- data/Rakefile +2 -0
- data/bin/cibuild +2 -3
- data/bin/console +1 -0
- data/bin/lint +2 -4
- data/bin/setup +0 -2
- data/bin/test +2 -4
- data/exe/saml-kit-create-self-signed-certificate +2 -0
- data/exe/saml-kit-decode-http-post +2 -0
- data/exe/saml-kit-decode-http-redirect +2 -0
- data/lib/saml-kit.rb +2 -0
- data/lib/saml/kit.rb +2 -0
- data/lib/saml/kit/assertion.rb +21 -41
- data/lib/saml/kit/authentication_request.rb +9 -3
- data/lib/saml/kit/bindings.rb +2 -0
- data/lib/saml/kit/bindings/binding.rb +2 -0
- data/lib/saml/kit/bindings/http_post.rb +2 -0
- data/lib/saml/kit/bindings/http_redirect.rb +2 -0
- data/lib/saml/kit/bindings/url_builder.rb +2 -0
- data/lib/saml/kit/buildable.rb +2 -0
- data/lib/saml/kit/builders.rb +2 -0
- data/lib/saml/kit/builders/assertion.rb +2 -0
- data/lib/saml/kit/builders/authentication_request.rb +2 -0
- data/lib/saml/kit/builders/encrypted_assertion.rb +2 -0
- data/lib/saml/kit/builders/identity_provider_metadata.rb +2 -0
- data/lib/saml/kit/builders/logout_request.rb +2 -0
- data/lib/saml/kit/builders/logout_response.rb +2 -0
- data/lib/saml/kit/builders/metadata.rb +2 -0
- data/lib/saml/kit/builders/response.rb +2 -0
- data/lib/saml/kit/builders/service_provider_metadata.rb +2 -0
- data/lib/saml/kit/builders/templates/assertion.builder +2 -0
- data/lib/saml/kit/builders/templates/authentication_request.builder +2 -0
- data/lib/saml/kit/builders/templates/encrypted_assertion.builder +2 -0
- data/lib/saml/kit/builders/templates/identity_provider_metadata.builder +2 -0
- data/lib/saml/kit/builders/templates/logout_request.builder +2 -0
- data/lib/saml/kit/builders/templates/logout_response.builder +2 -0
- data/lib/saml/kit/builders/templates/metadata.builder +2 -0
- data/lib/saml/kit/builders/templates/response.builder +2 -0
- data/lib/saml/kit/builders/templates/service_provider_metadata.builder +2 -0
- data/lib/saml/kit/composite_metadata.rb +3 -1
- data/lib/saml/kit/configuration.rb +2 -0
- data/lib/saml/kit/default_registry.rb +2 -0
- data/lib/saml/kit/document.rb +9 -14
- data/lib/saml/kit/identity_provider_metadata.rb +4 -2
- data/lib/saml/kit/invalid_document.rb +2 -0
- data/lib/saml/kit/logout_request.rb +7 -1
- data/lib/saml/kit/logout_response.rb +2 -0
- data/lib/saml/kit/metadata.rb +35 -32
- data/lib/saml/kit/namespaces.rb +2 -0
- data/lib/saml/kit/null_assertion.rb +2 -0
- data/lib/saml/kit/requestable.rb +2 -0
- data/lib/saml/kit/respondable.rb +4 -2
- data/lib/saml/kit/response.rb +2 -0
- data/lib/saml/kit/rspec.rb +2 -0
- data/lib/saml/kit/rspec/have_query_param.rb +2 -0
- data/lib/saml/kit/rspec/have_xpath.rb +3 -8
- data/lib/saml/kit/serializable.rb +2 -0
- data/lib/saml/kit/service_provider_metadata.rb +3 -1
- data/lib/saml/kit/signature.rb +2 -0
- data/lib/saml/kit/translatable.rb +2 -0
- data/lib/saml/kit/trustable.rb +2 -0
- data/lib/saml/kit/version.rb +3 -1
- data/lib/saml/kit/xml_templatable.rb +2 -0
- data/lib/saml/kit/xsd_validatable.rb +3 -2
- data/saml-kit.gemspec +2 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48040329dac3aa9d3171bf1098ec49937b7667067dbd7c8f8a0fa7adc0837edb
|
4
|
+
data.tar.gz: fc968fad4d56cb939ce34cd7da486e19844f55e11f976cd8454228571cfbc2a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93afbfeeabbfc19f6f8d772adc63b96206ce27ad6cc3b1620d4cd934e14230123400d1b94e03f2c8b10b5a52ca341d116106dd7f3d82b272ffda1f8bc510d746
|
7
|
+
data.tar.gz: 7148ddf6fb5511bfe17f4659c1b79b2122bf7646e9b06a4f7445335fd7925b1e9117bb9c43a0efb1aca80e3f310b492e81c39522d0a3e66afed3ceb4538ba280
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/bin/cibuild
CHANGED
@@ -7,8 +7,7 @@ set -e
|
|
7
7
|
|
8
8
|
cd "$(dirname "$0")/.."
|
9
9
|
|
10
|
-
echo "Started at…"
|
11
|
-
date "+%H:%M:%S"
|
10
|
+
echo [$(date "+%H:%M:%S")] "==> Started at…"
|
12
11
|
|
13
12
|
# GC customizations
|
14
13
|
export RUBY_GC_MALLOC_LIMIT=79000000
|
@@ -19,4 +18,4 @@ export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
|
|
19
18
|
|
20
19
|
ruby -v
|
21
20
|
gem install bundler --no-ri --no-rdoc --conservative
|
22
|
-
|
21
|
+
bin/test
|
data/bin/console
CHANGED
data/bin/lint
CHANGED
@@ -4,10 +4,8 @@ set -e
|
|
4
4
|
|
5
5
|
[ -z "$DEBUG" ] || set -x
|
6
6
|
|
7
|
-
echo "==> Running setup…"
|
8
|
-
date "+%H:%M:%S"
|
7
|
+
echo [$(date "+%H:%M:%S")] "==> Running setup…"
|
9
8
|
bin/setup
|
10
9
|
|
11
|
-
echo "==> Running linters…"
|
12
|
-
date "+%H:%M:%S"
|
10
|
+
echo [$(date "+%H:%M:%S")] "==> Running linters…"
|
13
11
|
bundle exec rake rubocop
|
data/bin/setup
CHANGED
data/bin/test
CHANGED
@@ -10,10 +10,8 @@ cd "$(dirname "$0")/.."
|
|
10
10
|
|
11
11
|
[ -z "$DEBUG" ] || set -x
|
12
12
|
|
13
|
-
echo "==> Running setup…"
|
14
|
-
date "+%H:%M:%S"
|
13
|
+
echo [$(date "+%H:%M:%S")] "==> Running setup…"
|
15
14
|
bin/setup
|
16
15
|
|
17
|
-
echo "==> Running tests…"
|
18
|
-
date "+%H:%M:%S"
|
16
|
+
echo [$(date "+%H:%M:%S")] "==> Running tests…"
|
19
17
|
bundle exec rake spec
|
data/lib/saml-kit.rb
CHANGED
data/lib/saml/kit.rb
CHANGED
data/lib/saml/kit/assertion.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
class Assertion
|
@@ -18,22 +20,18 @@ module Saml
|
|
18
20
|
def initialize(node, configuration: Saml::Kit.configuration, private_keys: [])
|
19
21
|
@name = 'Assertion'
|
20
22
|
@node = node
|
21
|
-
@xml_hash = hash_from(node)['Response'] || {}
|
22
23
|
@configuration = configuration
|
23
24
|
@occurred_at = Time.current
|
24
|
-
|
25
|
-
|
26
|
-
configuration.private_keys(use: :encryption) + private_keys
|
27
|
-
).uniq
|
28
|
-
))
|
25
|
+
private_keys = (configuration.private_keys(use: :encryption) + private_keys).uniq
|
26
|
+
decrypt!(::Xml::Kit::Decryption.new(private_keys: private_keys))
|
29
27
|
end
|
30
28
|
|
31
29
|
def issuer
|
32
|
-
|
30
|
+
at_xpath('./saml:Issuer').try(:text)
|
33
31
|
end
|
34
32
|
|
35
33
|
def name_id
|
36
|
-
|
34
|
+
at_xpath('./saml:Subject/saml:NameID').try(:text)
|
37
35
|
end
|
38
36
|
|
39
37
|
def signed?
|
@@ -54,35 +52,26 @@ module Saml
|
|
54
52
|
end
|
55
53
|
|
56
54
|
def attributes
|
57
|
-
@attributes ||=
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
[[attrs['Name'], attrs['AttributeValue']]]
|
62
|
-
else
|
63
|
-
attrs.map { |item| [item['Name'], item['AttributeValue']] }
|
64
|
-
end
|
65
|
-
Hash[items].with_indifferent_access
|
66
|
-
end
|
55
|
+
@attributes ||= search('./saml:AttributeStatement/saml:Attribute').inject({}) do |memo, item|
|
56
|
+
memo[item.attribute('Name').value] = item.at_xpath('./saml:AttributeValue', Saml::Kit::Document::NAMESPACES).try(:text)
|
57
|
+
memo
|
58
|
+
end.with_indifferent_access
|
67
59
|
end
|
68
60
|
|
69
61
|
def started_at
|
70
|
-
parse_date(
|
62
|
+
parse_date(at_xpath('./saml:Conditions/@NotBefore').try(:value))
|
71
63
|
end
|
72
64
|
|
73
65
|
def expired_at
|
74
|
-
parse_date(
|
66
|
+
parse_date(at_xpath('./saml:Conditions/@NotOnOrAfter').try(:value))
|
75
67
|
end
|
76
68
|
|
77
69
|
def audiences
|
78
|
-
|
79
|
-
rescue StandardError => error
|
80
|
-
Saml::Kit.logger.error(error)
|
81
|
-
[]
|
70
|
+
search('./saml:Conditions/saml:AudienceRestriction/saml:Audience').map(&:text)
|
82
71
|
end
|
83
72
|
|
84
73
|
def encrypted?
|
85
|
-
@
|
74
|
+
@encrypted
|
86
75
|
end
|
87
76
|
|
88
77
|
def decryptable?
|
@@ -91,7 +80,7 @@ module Saml
|
|
91
80
|
end
|
92
81
|
|
93
82
|
def present?
|
94
|
-
|
83
|
+
@node.present?
|
95
84
|
end
|
96
85
|
|
97
86
|
def to_xml(pretty: false)
|
@@ -102,19 +91,10 @@ module Saml
|
|
102
91
|
|
103
92
|
attr_reader :configuration
|
104
93
|
|
105
|
-
def assertion
|
106
|
-
@assertion ||=
|
107
|
-
begin
|
108
|
-
result = (hash_from(@node)['Response'] || {})['Assertion']
|
109
|
-
return result if result.is_a?(Hash)
|
110
|
-
{}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
94
|
def decrypt!(decryptor)
|
115
|
-
|
116
|
-
|
117
|
-
|
95
|
+
encrypted_assertion = at_xpath('./xmlenc:EncryptedData')
|
96
|
+
@encrypted = encrypted_assertion.present?
|
97
|
+
return unless @encrypted
|
118
98
|
@node = decryptor.decrypt_node(encrypted_assertion)
|
119
99
|
rescue Xml::Kit::DecryptionError => error
|
120
100
|
@cannot_decrypt = true
|
@@ -151,12 +131,12 @@ module Saml
|
|
151
131
|
end
|
152
132
|
|
153
133
|
def at_xpath(xpath)
|
134
|
+
return unless @node
|
154
135
|
@node.at_xpath(xpath, Saml::Kit::Document::NAMESPACES)
|
155
136
|
end
|
156
137
|
|
157
|
-
def
|
158
|
-
|
159
|
-
Hash.from_xml(node.document.root.to_s) || {}
|
138
|
+
def search(xpath)
|
139
|
+
@node.search(xpath, Saml::Kit::Document::NAMESPACES)
|
160
140
|
end
|
161
141
|
end
|
162
142
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
# This class can be used to parse a SAML AuthnRequest or generate one.
|
@@ -31,15 +33,19 @@ module Saml
|
|
31
33
|
# Extract the AssertionConsumerServiceURL from the AuthnRequest
|
32
34
|
# <samlp:AuthnRequest AssertionConsumerServiceURL="https://carroll.com/acs"></samlp:AuthnRequest>
|
33
35
|
def assertion_consumer_service_url
|
34
|
-
|
36
|
+
at_xpath('./*/@AssertionConsumerServiceURL').try(:value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def name_id_format
|
40
|
+
name_id_policy
|
35
41
|
end
|
36
42
|
|
37
43
|
# Extract the NameIDPolicy from the AuthnRequest
|
38
44
|
# <samlp:AuthnRequest>
|
39
45
|
# <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
|
40
46
|
# </samlp:AuthnRequest>
|
41
|
-
def
|
42
|
-
|
47
|
+
def name_id_policy
|
48
|
+
at_xpath('./*/samlp:NameIDPolicy/@Format').try(:value)
|
43
49
|
end
|
44
50
|
|
45
51
|
# Generate a Response for a specific user.
|
data/lib/saml/kit/bindings.rb
CHANGED
data/lib/saml/kit/buildable.rb
CHANGED
data/lib/saml/kit/builders.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
class CompositeMetadata < Metadata # :nodoc:
|
@@ -14,7 +16,7 @@ module Saml
|
|
14
16
|
|
15
17
|
def services(type)
|
16
18
|
xpath = map { |x| "//md:EntityDescriptor/md:#{x.name}/md:#{type}" }.join('|')
|
17
|
-
|
19
|
+
search(xpath).map do |item|
|
18
20
|
binding = item.attribute('Binding').value
|
19
21
|
location = item.attribute('Location').value
|
20
22
|
Saml::Kit::Bindings.create_for(binding, location)
|
data/lib/saml/kit/document.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
class Document
|
@@ -29,27 +31,27 @@ module Saml
|
|
29
31
|
|
30
32
|
# Returns the ID for the SAML document.
|
31
33
|
def id
|
32
|
-
|
34
|
+
at_xpath('./*/@ID').try(:value)
|
33
35
|
end
|
34
36
|
|
35
37
|
# Returns the Issuer for the SAML document.
|
36
38
|
def issuer
|
37
|
-
|
39
|
+
at_xpath('./*/saml:Issuer').try(:text)
|
38
40
|
end
|
39
41
|
|
40
42
|
# Returns the Version of the SAML document.
|
41
43
|
def version
|
42
|
-
|
44
|
+
at_xpath('./*/@Version').try(:value)
|
43
45
|
end
|
44
46
|
|
45
47
|
# Returns the Destination of the SAML document.
|
46
48
|
def destination
|
47
|
-
|
49
|
+
at_xpath('./*/@Destination').try(:value)
|
48
50
|
end
|
49
51
|
|
50
52
|
# Returns the Destination of the SAML document.
|
51
53
|
def issue_instant
|
52
|
-
Time.parse(
|
54
|
+
Time.parse(at_xpath('./*/@IssueInstant').try(:value))
|
53
55
|
end
|
54
56
|
|
55
57
|
# Returns the SAML document returned as a Hash.
|
@@ -102,15 +104,12 @@ module Saml
|
|
102
104
|
# @param xml [String] the raw xml string.
|
103
105
|
# @param configuration [Saml::Kit::Configuration] the configuration to use for unpacking the document.
|
104
106
|
def to_saml_document(xml, configuration: Saml::Kit.configuration)
|
105
|
-
xml_document = ::Xml::Kit::Document.new(xml, namespaces: {
|
106
|
-
"samlp": ::Saml::Kit::Namespaces::PROTOCOL
|
107
|
-
})
|
108
107
|
constructor = {
|
109
108
|
'AuthnRequest' => Saml::Kit::AuthenticationRequest,
|
110
109
|
'LogoutRequest' => Saml::Kit::LogoutRequest,
|
111
110
|
'LogoutResponse' => Saml::Kit::LogoutResponse,
|
112
111
|
'Response' => Saml::Kit::Response,
|
113
|
-
}[
|
112
|
+
}[Nokogiri::XML(xml).at_xpath(XPATH, "samlp": ::Saml::Kit::Namespaces::PROTOCOL).name] || InvalidDocument
|
114
113
|
constructor.new(xml, configuration: configuration)
|
115
114
|
rescue StandardError => error
|
116
115
|
Saml::Kit.logger.error(error)
|
@@ -138,10 +137,6 @@ module Saml
|
|
138
137
|
|
139
138
|
attr_reader :content, :name, :configuration
|
140
139
|
|
141
|
-
def root
|
142
|
-
to_h.fetch(name, {})
|
143
|
-
end
|
144
|
-
|
145
140
|
def must_match_xsd
|
146
141
|
matches_xsd?(PROTOCOL_XSD)
|
147
142
|
end
|
@@ -151,7 +146,7 @@ module Saml
|
|
151
146
|
end
|
152
147
|
|
153
148
|
def expected_type?
|
154
|
-
|
149
|
+
at_xpath("./samlp:#{name}").present?
|
155
150
|
end
|
156
151
|
|
157
152
|
def must_be_valid_version
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
# This class is used to parse the IDPSSODescriptor from a SAML metadata document.
|
@@ -38,7 +40,7 @@ module Saml
|
|
38
40
|
# Returns the IDPSSODescriptor/@WantAuthnRequestsSigned attribute.
|
39
41
|
def want_authn_requests_signed
|
40
42
|
xpath = "/md:EntityDescriptor/md:#{name}"
|
41
|
-
attribute =
|
43
|
+
attribute = at_xpath(xpath).attribute('WantAuthnRequestsSigned')
|
42
44
|
return true if attribute.nil?
|
43
45
|
attribute.text.casecmp('true').zero?
|
44
46
|
end
|
@@ -57,7 +59,7 @@ module Saml
|
|
57
59
|
|
58
60
|
# Returns each of the Attributes in the metadata.
|
59
61
|
def attributes
|
60
|
-
|
62
|
+
search("/md:EntityDescriptor/md:#{name}/saml:Attribute").map do |item|
|
61
63
|
{
|
62
64
|
format: item.attribute('NameFormat').try(:value),
|
63
65
|
name: item.attribute('Name').value,
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
# This class can be used to parse a LogoutRequest SAML document.
|
@@ -36,7 +38,11 @@ module Saml
|
|
36
38
|
|
37
39
|
# Returns the NameID value.
|
38
40
|
def name_id
|
39
|
-
|
41
|
+
at_xpath('./*/saml:NameID').try(:text)
|
42
|
+
end
|
43
|
+
|
44
|
+
def name_id_format
|
45
|
+
at_xpath('./*/saml:NameID/@Format').try(:value)
|
40
46
|
end
|
41
47
|
|
42
48
|
# Generates a Serialized LogoutResponse using the encoding rules for the specified binding.
|
data/lib/saml/kit/metadata.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
# The Metadata object can be used to parse an XML string of metadata.
|
@@ -29,11 +31,11 @@ module Saml
|
|
29
31
|
include Buildable
|
30
32
|
METADATA_XSD = File.expand_path('./xsd/saml-schema-metadata-2.0.xsd', File.dirname(__FILE__)).freeze
|
31
33
|
NAMESPACES = {
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
NameFormat: Namespaces::ATTR_SPLAT,
|
35
|
+
ds: ::Xml::Kit::Namespaces::XMLDSIG,
|
36
|
+
md: Namespaces::METADATA,
|
37
|
+
saml: Namespaces::ASSERTION,
|
38
|
+
samlp: Namespaces::PROTOCOL,
|
37
39
|
}.freeze
|
38
40
|
|
39
41
|
validates_presence_of :metadata
|
@@ -50,36 +52,34 @@ module Saml
|
|
50
52
|
|
51
53
|
# Returns the /EntityDescriptor/@entityID
|
52
54
|
def entity_id
|
53
|
-
|
55
|
+
at_xpath('/md:EntityDescriptor/@entityID').try(:value)
|
54
56
|
end
|
55
57
|
|
56
58
|
# Returns the supported NameIDFormats.
|
57
59
|
def name_id_formats
|
58
|
-
|
60
|
+
search("/md:EntityDescriptor/md:#{name}/md:NameIDFormat").map(&:text)
|
59
61
|
end
|
60
62
|
|
61
63
|
# Returns the Organization Name
|
62
64
|
def organization_name
|
63
|
-
|
65
|
+
at_xpath('/md:EntityDescriptor/md:Organization/md:OrganizationName').try(:text)
|
64
66
|
end
|
65
67
|
|
66
68
|
# Returns the Organization URL
|
67
69
|
def organization_url
|
68
|
-
|
70
|
+
at_xpath('/md:EntityDescriptor/md:Organization/md:OrganizationURL').try(:text)
|
69
71
|
end
|
70
72
|
|
71
73
|
# Returns the Company
|
72
74
|
def contact_person_company
|
73
|
-
|
75
|
+
at_xpath('/md:EntityDescriptor/md:ContactPerson/md:Company').try(:text)
|
74
76
|
end
|
75
77
|
|
76
78
|
# Returns each of the X509 certificates.
|
77
79
|
def certificates
|
78
|
-
@certificates ||=
|
79
|
-
cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate',
|
80
|
-
|
81
|
-
use = attribute.nil? ? nil : item.attribute('use').value
|
82
|
-
::Xml::Kit::Certificate.new(cert, use: use)
|
80
|
+
@certificates ||= search("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
|
81
|
+
cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', 'ds' => ::Xml::Kit::Namespaces::XMLDSIG).try(:text)
|
82
|
+
::Xml::Kit::Certificate.new(cert, use: item.attribute('use').try(:value))
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -97,7 +97,7 @@ module Saml
|
|
97
97
|
#
|
98
98
|
# @param type [String] the type of service. .E.g. `AssertionConsumerServiceURL`
|
99
99
|
def services(type)
|
100
|
-
|
100
|
+
search("/md:EntityDescriptor/md:#{name}/md:#{type}").map do |item|
|
101
101
|
binding = item.attribute('Binding').value
|
102
102
|
location = item.attribute('Location').value
|
103
103
|
Saml::Kit::Bindings.create_for(binding, location)
|
@@ -132,9 +132,7 @@ module Saml
|
|
132
132
|
# @param relay_state [String] the relay state to have echo'd back.
|
133
133
|
# @return [Array] Returns an array with a url and Hash of parameters to send to the other party.
|
134
134
|
def logout_request_for(user, binding: :http_post, relay_state: nil)
|
135
|
-
builder = Saml::Kit::LogoutRequest.builder(user)
|
136
|
-
yield x if block_given?
|
137
|
-
end
|
135
|
+
builder = Saml::Kit::LogoutRequest.builder(user) { |x| yield x if block_given? }
|
138
136
|
request_binding = single_logout_service_for(binding: binding)
|
139
137
|
request_binding.serialize(builder, relay_state: relay_state)
|
140
138
|
end
|
@@ -145,9 +143,7 @@ module Saml
|
|
145
143
|
# @param use [Symbol] the type of certificates to look at. Can be `:signing` or `:encryption`.
|
146
144
|
# @return [Xml::Kit::Certificate] returns the matching `{Xml::Kit::Certificate}`
|
147
145
|
def matches?(fingerprint, use: :signing)
|
148
|
-
certificates.find
|
149
|
-
certificate.for?(use) && certificate.fingerprint == fingerprint
|
150
|
-
end
|
146
|
+
certificates.find { |x| x.for?(use) && x.fingerprint == fingerprint }
|
151
147
|
end
|
152
148
|
|
153
149
|
# Returns the XML document converted to a Hash.
|
@@ -159,7 +155,7 @@ module Saml
|
|
159
155
|
#
|
160
156
|
# @param pretty [Symbol] true to return a human friendly version of the XML.
|
161
157
|
def to_xml(pretty: false)
|
162
|
-
|
158
|
+
pretty ? to_nokogiri.to_xml(indent: 2) : @xml
|
163
159
|
end
|
164
160
|
|
165
161
|
# Returns the XML document as a [String].
|
@@ -189,13 +185,15 @@ module Saml
|
|
189
185
|
# @param content [String] the raw metadata XML.
|
190
186
|
# @return [Saml::Kit::Metadata] the metadata document or subclass.
|
191
187
|
def from(content)
|
192
|
-
|
193
|
-
|
194
|
-
|
188
|
+
document = Nokogiri::XML(content)
|
189
|
+
return unless document.at_xpath('/md:EntityDescriptor', NAMESPACES)
|
190
|
+
sp = document.at_xpath('/md:EntityDescriptor/md:SPSSODescriptor', NAMESPACES)
|
191
|
+
idp = document.at_xpath('/md:EntityDescriptor/md:IDPSSODescriptor', NAMESPACES)
|
192
|
+
if sp && idp
|
195
193
|
Saml::Kit::CompositeMetadata.new(content)
|
196
|
-
elsif
|
194
|
+
elsif sp
|
197
195
|
Saml::Kit::ServiceProviderMetadata.new(content)
|
198
|
-
elsif
|
196
|
+
elsif idp
|
199
197
|
Saml::Kit::IdentityProviderMetadata.new(content)
|
200
198
|
end
|
201
199
|
end
|
@@ -210,16 +208,21 @@ module Saml
|
|
210
208
|
|
211
209
|
attr_reader :xml
|
212
210
|
|
213
|
-
|
214
|
-
|
211
|
+
# @!visibility private
|
212
|
+
def to_nokogiri
|
213
|
+
@nokogiri ||= Nokogiri::XML(xml)
|
215
214
|
end
|
216
215
|
|
217
216
|
def at_xpath(xpath)
|
218
|
-
|
217
|
+
to_nokogiri.at_xpath(xpath, NAMESPACES)
|
218
|
+
end
|
219
|
+
|
220
|
+
def search(xpath)
|
221
|
+
to_nokogiri.search(xpath, NAMESPACES)
|
219
222
|
end
|
220
223
|
|
221
224
|
def metadata
|
222
|
-
|
225
|
+
at_xpath("/md:EntityDescriptor/md:#{name}").present?
|
223
226
|
end
|
224
227
|
|
225
228
|
def must_contain_descriptor
|
data/lib/saml/kit/namespaces.rb
CHANGED
data/lib/saml/kit/requestable.rb
CHANGED
data/lib/saml/kit/respondable.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
module Respondable
|
@@ -16,12 +18,12 @@ module Saml
|
|
16
18
|
|
17
19
|
# Returns the /Status/StatusCode@Value
|
18
20
|
def status_code
|
19
|
-
|
21
|
+
at_xpath('./*/samlp:Status/samlp:StatusCode/@Value').try(:value)
|
20
22
|
end
|
21
23
|
|
22
24
|
# Returns the /InResponseTo attribute.
|
23
25
|
def in_response_to
|
24
|
-
|
26
|
+
at_xpath('./*/@InResponseTo').try(:value)
|
25
27
|
end
|
26
28
|
|
27
29
|
# Returns true if the Status code is #{Saml::Kit::Namespaces::SUCCESS}
|
data/lib/saml/kit/response.rb
CHANGED
data/lib/saml/kit/rspec.rb
CHANGED
@@ -1,13 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define :have_xpath do |xpath|
|
2
4
|
match do |actual|
|
3
|
-
|
4
|
-
"NameFormat": Saml::Kit::Namespaces::ATTR_SPLAT,
|
5
|
-
"ds": ::Xml::Kit::Namespaces::XMLDSIG,
|
6
|
-
"md": Saml::Kit::Namespaces::METADATA,
|
7
|
-
"saml": Saml::Kit::Namespaces::ASSERTION,
|
8
|
-
"samlp": Saml::Kit::Namespaces::PROTOCOL,
|
9
|
-
}
|
10
|
-
xml_document(actual).xpath(xpath, namespaces).any?
|
5
|
+
xml_document(actual).xpath(xpath, Saml::Kit::Document::NAMESPACES).any?
|
11
6
|
end
|
12
7
|
|
13
8
|
failure_message do |actual|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
# {include:file:spec/examples/service_provider_metadata_spec.rb}
|
@@ -20,7 +22,7 @@ module Saml
|
|
20
22
|
|
21
23
|
# Returns true when the metadata demands that Assertions must be signed.
|
22
24
|
def want_assertions_signed
|
23
|
-
attribute =
|
25
|
+
attribute = at_xpath("/md:EntityDescriptor/md:#{name}").attribute('WantAssertionsSigned')
|
24
26
|
return true if attribute.nil?
|
25
27
|
attribute.text.casecmp('true').zero?
|
26
28
|
end
|
data/lib/saml/kit/signature.rb
CHANGED
data/lib/saml/kit/trustable.rb
CHANGED
data/lib/saml/kit/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Saml
|
2
4
|
module Kit
|
3
5
|
module XsdValidatable
|
@@ -5,8 +7,7 @@ module Saml
|
|
5
7
|
def matches_xsd?(xsd)
|
6
8
|
Dir.chdir(File.dirname(xsd)) do
|
7
9
|
xsd = Nokogiri::XML::Schema(IO.read(xsd))
|
8
|
-
|
9
|
-
xsd.validate(document).each do |error|
|
10
|
+
xsd.validate(to_nokogiri).each do |error|
|
10
11
|
errors[:base] << error.message
|
11
12
|
end
|
12
13
|
end
|
data/saml-kit.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saml-kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mo khan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -294,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
294
294
|
version: '0'
|
295
295
|
requirements: []
|
296
296
|
rubyforge_project:
|
297
|
-
rubygems_version: 2.7.
|
297
|
+
rubygems_version: 2.7.6
|
298
298
|
signing_key:
|
299
299
|
specification_version: 4
|
300
300
|
summary: A simple toolkit for working with SAML.
|