saml-kit 1.0.9 → 1.0.10
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 +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.
|