saml-kit 1.0.15 → 1.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -5
  3. data/exe/saml-kit-create-self-signed-certificate +6 -2
  4. data/exe/saml-kit-decode-http-post +2 -1
  5. data/exe/saml-kit-decode-http-redirect +2 -1
  6. data/lib/saml/kit/assertion.rb +22 -48
  7. data/lib/saml/kit/attribute_statement.rb +25 -0
  8. data/lib/saml/kit/authentication_request.rb +34 -15
  9. data/lib/saml/kit/bindings/binding.rb +4 -7
  10. data/lib/saml/kit/bindings/http_post.rb +6 -2
  11. data/lib/saml/kit/bindings/http_redirect.rb +8 -5
  12. data/lib/saml/kit/bindings/url_builder.rb +7 -7
  13. data/lib/saml/kit/bindings.rb +4 -3
  14. data/lib/saml/kit/builders/assertion.rb +6 -3
  15. data/lib/saml/kit/builders/authentication_request.rb +4 -2
  16. data/lib/saml/kit/builders/encrypted_assertion.rb +3 -1
  17. data/lib/saml/kit/builders/identity_provider_metadata.rb +14 -4
  18. data/lib/saml/kit/builders/metadata.rb +8 -4
  19. data/lib/saml/kit/builders/null.rb +0 -1
  20. data/lib/saml/kit/builders/response.rb +14 -5
  21. data/lib/saml/kit/builders/service_provider_metadata.rb +10 -3
  22. data/lib/saml/kit/builders.rb +0 -1
  23. data/lib/saml/kit/composite_metadata.rb +18 -3
  24. data/lib/saml/kit/{buildable.rb → concerns/buildable.rb} +0 -0
  25. data/lib/saml/kit/{requestable.rb → concerns/requestable.rb} +0 -0
  26. data/lib/saml/kit/{respondable.rb → concerns/respondable.rb} +0 -0
  27. data/lib/saml/kit/{serializable.rb → concerns/serializable.rb} +0 -0
  28. data/lib/saml/kit/{translatable.rb → concerns/translatable.rb} +0 -0
  29. data/lib/saml/kit/{trustable.rb → concerns/trustable.rb} +9 -7
  30. data/lib/saml/kit/concerns/xml_parseable.rb +62 -0
  31. data/lib/saml/kit/{xml_templatable.rb → concerns/xml_templatable.rb} +3 -2
  32. data/lib/saml/kit/{xsd_validatable.rb → concerns/xsd_validatable.rb} +10 -0
  33. data/lib/saml/kit/conditions.rb +37 -0
  34. data/lib/saml/kit/configuration.rb +28 -10
  35. data/lib/saml/kit/default_registry.rb +19 -4
  36. data/lib/saml/kit/document.rb +21 -67
  37. data/lib/saml/kit/identity_provider_metadata.rb +34 -15
  38. data/lib/saml/kit/invalid_document.rb +1 -1
  39. data/lib/saml/kit/logout_request.rb +11 -6
  40. data/lib/saml/kit/logout_response.rb +3 -1
  41. data/lib/saml/kit/metadata.rb +63 -109
  42. data/lib/saml/kit/namespaces.rb +2 -1
  43. data/lib/saml/kit/organization.rb +36 -0
  44. data/lib/saml/kit/parser.rb +28 -0
  45. data/lib/saml/kit/response.rb +10 -2
  46. data/lib/saml/kit/rspec/have_xpath.rb +4 -2
  47. data/lib/saml/kit/service_provider_metadata.rb +2 -1
  48. data/lib/saml/kit/signature.rb +21 -5
  49. data/lib/saml/kit/version.rb +1 -1
  50. data/lib/saml/kit.rb +14 -7
  51. data/saml-kit.gemspec +0 -1
  52. metadata +16 -25
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml/kit/xml_templatable'
4
3
  require 'saml/kit/builders/assertion'
5
4
  require 'saml/kit/builders/authentication_request'
6
5
  require 'saml/kit/builders/encrypted_assertion'
@@ -9,6 +9,7 @@ module Saml
9
9
  # and SPSSODescriptor element.
10
10
  class CompositeMetadata < Metadata # :nodoc:
11
11
  include Enumerable
12
+
12
13
  attr_reader :service_provider, :identity_provider
13
14
 
14
15
  def initialize(xml)
@@ -19,8 +20,22 @@ module Saml
19
20
  ]
20
21
  end
21
22
 
23
+ def organization
24
+ find { |x| x.organization.present? }.try(:organization)
25
+ end
26
+
27
+ def organization_name
28
+ organization.name
29
+ end
30
+
31
+ def organization_url
32
+ organization.url
33
+ end
34
+
22
35
  def services(type)
23
- xpath = map { |xxx| "//md:EntityDescriptor/md:#{xxx.name}/md:#{type}" }.join('|')
36
+ xpath = map do |x|
37
+ "//md:EntityDescriptor/md:#{x.name}/md:#{type}"
38
+ end.join('|')
24
39
  search(xpath).map do |item|
25
40
  binding = item.attribute('Binding').value
26
41
  location = item.attribute('Location').value
@@ -37,7 +52,7 @@ module Saml
37
52
  end
38
53
 
39
54
  def method_missing(name, *args)
40
- if (target = find { |xxx| xxx.respond_to?(name) })
55
+ if (target = find { |x| x.respond_to?(name) })
41
56
  target.public_send(name, *args)
42
57
  else
43
58
  super
@@ -45,7 +60,7 @@ module Saml
45
60
  end
46
61
 
47
62
  def respond_to_missing?(method, *)
48
- find { |xxx| xxx.respond_to?(method) }
63
+ find { |x| x.respond_to?(method) }
49
64
  end
50
65
  end
51
66
  end
@@ -9,14 +9,15 @@ module Saml
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- validate :must_have_valid_signature, unless: :signature_manually_verified
12
+ validate :must_have_valid_signature, unless: :signature_verified
13
13
  validate :must_be_registered
14
14
  validate :must_be_trusted
15
15
  end
16
16
 
17
- # Returns true when the document has an embedded XML Signature or has been verified externally.
17
+ # Returns true when the document has an embedded XML Signature or has
18
+ # been verified externally.
18
19
  def signed?
19
- signature_manually_verified || signature.present?
20
+ signature_verified || signature.present?
20
21
  end
21
22
 
22
23
  # @!visibility private
@@ -24,9 +25,10 @@ module Saml
24
25
  @signature ||= Signature.new(at_xpath("/samlp:#{name}/ds:Signature"))
25
26
  end
26
27
 
27
- # Returns true when documents is signed and the signing certificate belongs to a known service entity.
28
+ # Returns true when documents is signed and the signing certificate
29
+ # belongs to a known service entity.
28
30
  def trusted?
29
- return true if signature_manually_verified
31
+ return true if signature_verified
30
32
  return false unless signed?
31
33
  signature.trusted?(provider)
32
34
  end
@@ -38,12 +40,12 @@ module Saml
38
40
 
39
41
  # @!visibility private
40
42
  def signature_verified!
41
- @signature_manually_verified = true
43
+ @signature_verified = true
42
44
  end
43
45
 
44
46
  private
45
47
 
46
- attr_reader :signature_manually_verified
48
+ attr_reader :signature_verified
47
49
 
48
50
  def must_have_valid_signature
49
51
  return if to_xml.blank?
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'saml/kit/namespaces'
4
+
5
+ module Saml
6
+ module Kit
7
+ module XmlParseable
8
+ NAMESPACES = {
9
+ NameFormat: ::Saml::Kit::Namespaces::ATTR_SPLAT,
10
+ ds: ::Xml::Kit::Namespaces::XMLDSIG,
11
+ md: ::Saml::Kit::Namespaces::METADATA,
12
+ saml: ::Saml::Kit::Namespaces::ASSERTION,
13
+ samlp: ::Saml::Kit::Namespaces::PROTOCOL,
14
+ xmlenc: ::Xml::Kit::Namespaces::XMLENC,
15
+ }.freeze
16
+
17
+ # Returns the SAML document returned as a Hash.
18
+ def to_h
19
+ @to_h ||= Hash.from_xml(to_s) || {}
20
+ end
21
+
22
+ # Returns the XML document as a String.
23
+ #
24
+ # @param pretty [Boolean] true to return a human friendly version
25
+ # of the XML.
26
+ def to_xml(pretty: nil)
27
+ pretty ? to_nokogiri.to_xml(indent: 2) : to_s
28
+ end
29
+
30
+ # Returns the SAML document as an XHTML string.
31
+ # This is useful for rendering in a web page.
32
+ def to_xhtml
33
+ Nokogiri::XML(to_xml, &:noblanks).to_xhtml
34
+ end
35
+
36
+ def present?
37
+ to_s.present?
38
+ end
39
+
40
+ # @!visibility private
41
+ def to_nokogiri
42
+ @to_nokogiri ||= Nokogiri::XML(to_s)
43
+ end
44
+
45
+ # @!visibility private
46
+ def at_xpath(xpath)
47
+ return unless present?
48
+ to_nokogiri.at_xpath(xpath, NAMESPACES)
49
+ end
50
+
51
+ # @!visibility private
52
+ def search(xpath)
53
+ to_nokogiri.search(xpath, NAMESPACES)
54
+ end
55
+
56
+ # Returns the XML document as a [String].
57
+ def to_s
58
+ content
59
+ end
60
+ end
61
+ end
62
+ end
@@ -5,7 +5,7 @@ module Saml
5
5
  # This module is responsible for
6
6
  # generating converting templates to xml.
7
7
  module XmlTemplatable
8
- TEMPLATES_DIR = Pathname.new(File.join(__dir__, 'builders/templates/'))
8
+ TEMPLATES_DIR = Pathname.new(File.join(__dir__, '../builders/templates/'))
9
9
  include ::Xml::Kit::Templatable
10
10
 
11
11
  def template_path
@@ -16,7 +16,8 @@ module Saml
16
16
  "#{self.class.name.split('::').last.underscore}.builder"
17
17
  end
18
18
 
19
- # Returns true if an embedded signature is requested and at least one signing certificate is available via the configuration.
19
+ # Returns true if an embedded signature is requested and at least one
20
+ # signing certificate is available via the configuration.
20
21
  def sign?
21
22
  return configuration.sign? if embed_signature.nil?
22
23
  (embed_signature && configuration.sign?) ||
@@ -5,8 +5,18 @@ module Saml
5
5
  # This module is responsible for validating
6
6
  # xml documents against the SAML XSD's
7
7
  module XsdValidatable
8
+ PROTOCOL_XSD = File.expand_path(
9
+ '../xsd/saml-schema-protocol-2.0.xsd', File.dirname(__FILE__)
10
+ ).freeze
11
+
12
+ METADATA_XSD = File.expand_path(
13
+ '../xsd/saml-schema-metadata-2.0.xsd', File.dirname(__FILE__)
14
+ ).freeze
15
+
8
16
  # @!visibility private
9
17
  def matches_xsd?(xsd)
18
+ return unless to_nokogiri.present?
19
+
10
20
  Dir.chdir(File.dirname(xsd)) do
11
21
  xsd = Nokogiri::XML::Schema(IO.read(xsd))
12
22
  xsd.validate(to_nokogiri).each do |error|
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Saml
4
+ module Kit
5
+ class Conditions
6
+ include XmlParseable
7
+
8
+ attr_reader :content
9
+
10
+ def initialize(node)
11
+ @to_nokogiri = node
12
+ @content = node.to_s
13
+ end
14
+
15
+ def started_at
16
+ parse_iso8601(at_xpath('./@NotBefore').try(:value))
17
+ end
18
+
19
+ def expired_at
20
+ parse_iso8601(at_xpath('./@NotOnOrAfter').try(:value))
21
+ end
22
+
23
+ def audiences
24
+ search('./saml:AudienceRestriction/saml:Audience').map(&:text)
25
+ end
26
+
27
+ private
28
+
29
+ def parse_iso8601(value)
30
+ DateTime.parse(value)
31
+ rescue StandardError => error
32
+ Saml::Kit.logger.error(error)
33
+ Time.at(0).to_datetime
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,7 +2,8 @@
2
2
 
3
3
  module Saml
4
4
  module Kit
5
- # This class represents the main configuration that is use for generating SAML documents.
5
+ # This class represents the main configuration that is use for generating
6
+ # SAML documents.
6
7
  #
7
8
  # Saml::Kit::Configuration.new do |config|
8
9
  # config.entity_id = "com:saml:kit"
@@ -19,17 +20,25 @@ module Saml
19
20
  # Saml::Kit.configure do |configuration|
20
21
  # configuration.entity_id = "https://www.example.com/saml/metadata"
21
22
  # configuration.generate_key_pair_for(use: :signing)
22
- # configuration.add_key_pair(ENV["X509_CERTIFICATE"], ENV["PRIVATE_KEY"], passphrase: ENV['PRIVATE_KEY_PASSPHRASE'], use: :encryption)
23
+ # configuration.add_key_pair(
24
+ # ENV["X509_CERTIFICATE"],
25
+ # ENV["PRIVATE_KEY"],
26
+ # passphrase: ENV['PRIVATE_KEY_PASSPHRASE'],
27
+ # use: :encryption
28
+ # )
23
29
  # end
24
30
  class Configuration
25
31
  USES = %i[signing encryption].freeze
26
32
  # The issuer to use in requests or responses from this entity to use.
27
33
  attr_accessor :entity_id
28
- # The signature method to use when generating signatures (See {Saml::Kit::Builders::XmlSignature::SIGNATURE_METHODS})
34
+ # The signature method to use when generating signatures
35
+ # (See {Saml::Kit::Builders::XmlSignature::SIGNATURE_METHODS})
29
36
  attr_accessor :signature_method
30
- # The digest method to use when generating signatures (See {Saml::Kit::Builders::XmlSignature::DIGEST_METHODS})
37
+ # The digest method to use when generating signatures
38
+ # (See {Saml::Kit::Builders::XmlSignature::DIGEST_METHODS})
31
39
  attr_accessor :digest_method
32
- # The metadata registry to use for searching for metadata associated with an issuer.
40
+ # The metadata registry to use for searching for metadata associated
41
+ # with an issuer.
33
42
  attr_accessor :registry
34
43
  # The session timeout to use when generating an Assertion.
35
44
  attr_accessor :session_timeout
@@ -57,7 +66,11 @@ module Saml
57
66
  # @param use [Symbol] the type of key pair, `:signing` or `:encryption`
58
67
  def add_key_pair(certificate, private_key, passphrase: nil, use: :signing)
59
68
  ensure_proper_use(use)
60
- @key_pairs.push(::Xml::Kit::KeyPair.new(certificate, private_key, passphrase, use.to_sym))
69
+ @key_pairs.push(
70
+ ::Xml::Kit::KeyPair.new(
71
+ certificate, private_key, passphrase, use.to_sym
72
+ )
73
+ )
61
74
  end
62
75
 
63
76
  # Generates a unique key pair that can be used for signing or encryption.
@@ -66,27 +79,32 @@ module Saml
66
79
  # @param passphrase [String] the private key passphrase to use.
67
80
  def generate_key_pair_for(use:, passphrase: SecureRandom.uuid)
68
81
  ensure_proper_use(use)
69
- certificate, private_key = ::Xml::Kit::SelfSignedCertificate.new.create(passphrase: passphrase)
82
+ certificate, private_key = ::Xml::Kit::SelfSignedCertificate.new.create(
83
+ passphrase: passphrase
84
+ )
70
85
  add_key_pair(certificate, private_key, passphrase: passphrase, use: use)
71
86
  end
72
87
 
73
88
  # Return each key pair for a specific use.
74
89
  #
75
- # @param use [Symbol] the type of key pair to return `nil`, `:signing` or `:encryption`
90
+ # @param use [Symbol] the type of key pair to return
91
+ # `nil`, `:signing` or `:encryption`
76
92
  def key_pairs(use: nil)
77
93
  use.present? ? @key_pairs.find_all { |xxx| xxx.for?(use) } : @key_pairs
78
94
  end
79
95
 
80
96
  # Return each certificate for a specific use.
81
97
  #
82
- # @param use [Symbol] the type of key pair to return `nil`, `:signing` or `:encryption`
98
+ # @param use [Symbol] the type of key pair to return
99
+ # `nil`, `:signing` or `:encryption`
83
100
  def certificates(use: nil)
84
101
  key_pairs(use: use).flat_map(&:certificate)
85
102
  end
86
103
 
87
104
  # Return each private for a specific use.
88
105
  #
89
- # @param use [Symbol] the type of key pair to return `nil`, `:signing` or `:encryption`
106
+ # @param use [Symbol] the type of key pair to return
107
+ # `nil`, `:signing` or `:encryption`
90
108
  def private_keys(use: nil)
91
109
  key_pairs(use: use).flat_map(&:private_key)
92
110
  end
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Saml
4
4
  module Kit
5
- # The default metadata registry is used to fetch the metadata associated with an issuer or entity id.
6
- # The metadata associated with an issuer is used to verify trust for any SAML documents that are received.
5
+ # The default metadata registry is used to fetch the metadata associated
6
+ # with an issuer or entity id.
7
+ # The metadata associated with an issuer is used to verify trust for any
8
+ # SAML documents that are received.
7
9
  #
8
10
  # You can replace the default registry with your own at startup.
9
11
  #
@@ -41,12 +43,14 @@ module Saml
41
43
  #
42
44
  # @param metadata [Saml::Kit::Metadata] the metadata to register.
43
45
  def register(metadata)
46
+ ensure_valid_metadata(metadata)
44
47
  Saml::Kit.logger.debug(metadata.to_xml(pretty: true))
45
48
  @items[metadata.entity_id] = metadata
46
49
  end
47
50
 
48
51
  # Register metadata via a remote URL.
49
- # This will attempt to connect to the remove URL to download the metadata and register it in the registry.
52
+ # This will attempt to connect to the remove URL to download the
53
+ # metadata and register it in the registry.
50
54
  #
51
55
  # @param url [String] the url to download the metadata from.
52
56
  # @param verify_ssl [Boolean] enable/disable SSL peer verification.
@@ -57,7 +61,8 @@ module Saml
57
61
 
58
62
  # Returns the metadata document associated with an issuer or entityID.
59
63
  #
60
- # @param entity_id [String] the unique entityID/Issuer associated with metadata.
64
+ # @param entity_id [String] unique entityID/Issuer associated with
65
+ # metadata.
61
66
  def metadata_for(entity_id)
62
67
  @items[entity_id]
63
68
  end
@@ -69,6 +74,16 @@ module Saml
69
74
  end
70
75
  end
71
76
 
77
+ private
78
+
79
+ def ensure_valid_metadata(metadata)
80
+ error = ArgumentError.new('Cannot register invalid metadata')
81
+ raise error if
82
+ metadata.nil? ||
83
+ !metadata.respond_to?(:entity_id) ||
84
+ metadata.invalid?
85
+ end
86
+
72
87
  # This class is responsible for
73
88
  # making HTTP requests to fetch metadata
74
89
  # from remote locations.
@@ -5,19 +5,12 @@ module Saml
5
5
  # This class is a base class for SAML documents.
6
6
  class Document
7
7
  include ActiveModel::Validations
8
- include XsdValidatable
8
+ include Buildable
9
9
  include Translatable
10
10
  include Trustable
11
- include Buildable
12
- PROTOCOL_XSD = File.expand_path('./xsd/saml-schema-protocol-2.0.xsd', File.dirname(__FILE__)).freeze
13
- NAMESPACES = {
14
- "NameFormat": ::Saml::Kit::Namespaces::ATTR_SPLAT,
15
- "ds": ::Xml::Kit::Namespaces::XMLDSIG,
16
- "md": ::Saml::Kit::Namespaces::METADATA,
17
- "saml": ::Saml::Kit::Namespaces::ASSERTION,
18
- "samlp": ::Saml::Kit::Namespaces::PROTOCOL,
19
- 'xmlenc' => ::Xml::Kit::Namespaces::XMLENC,
20
- }.freeze
11
+ include XmlParseable
12
+ include XsdValidatable
13
+
21
14
  attr_accessor :registry
22
15
  attr_reader :name
23
16
  validates_presence_of :content
@@ -58,44 +51,13 @@ module Saml
58
51
  Time.parse(at_xpath('./*/@IssueInstant').try(:value))
59
52
  end
60
53
 
61
- # Returns the SAML document returned as a Hash.
62
- def to_h
63
- @to_h ||= Hash.from_xml(content) || {}
64
- end
65
-
66
- # Returns the SAML document as an XML string.
67
- #
68
- # @param pretty [Boolean] formats the xml or returns the raw xml.
69
- def to_xml(pretty: nil)
70
- pretty ? to_nokogiri.to_xml(indent: 2) : to_s
71
- end
72
-
73
- # Returns the SAML document as an XHTML string.
74
- # This is useful for rendering in a web page.
75
- def to_xhtml
76
- Nokogiri::XML(to_xml, &:noblanks).to_xhtml
77
- end
78
-
79
- # @!visibility private
80
- def to_nokogiri
81
- @to_nokogiri ||= Nokogiri::XML(to_s)
82
- end
83
-
84
- # @!visibility private
85
- def at_xpath(xpath)
86
- to_nokogiri.at_xpath(xpath, NAMESPACES)
87
- end
88
-
89
- # @!visibility private
90
- def search(xpath)
91
- to_nokogiri.search(xpath, NAMESPACES)
92
- end
93
-
94
- def to_s
95
- content
96
- end
97
-
98
54
  class << self
55
+ CONSTRUCTORS = {
56
+ 'AuthnRequest' => -> { Saml::Kit::AuthenticationRequest },
57
+ 'LogoutRequest' => -> { Saml::Kit::LogoutRequest },
58
+ 'LogoutResponse' => -> { Saml::Kit::LogoutResponse },
59
+ 'Response' => -> { Saml::Kit::Response },
60
+ }.freeze
99
61
  XPATH = [
100
62
  '/samlp:AuthnRequest',
101
63
  '/samlp:LogoutRequest',
@@ -106,14 +68,12 @@ module Saml
106
68
  # Returns the raw xml as a Saml::Kit SAML document.
107
69
  #
108
70
  # @param xml [String] the raw xml string.
109
- # @param configuration [Saml::Kit::Configuration] the configuration to use for unpacking the document.
71
+ # @param configuration [Saml::Kit::Configuration] configuration to use
72
+ # for unpacking the document.
110
73
  def to_saml_document(xml, configuration: Saml::Kit.configuration)
111
- constructor = {
112
- 'AuthnRequest' => Saml::Kit::AuthenticationRequest,
113
- 'LogoutRequest' => Saml::Kit::LogoutRequest,
114
- 'LogoutResponse' => Saml::Kit::LogoutResponse,
115
- 'Response' => Saml::Kit::Response,
116
- }[Nokogiri::XML(xml).at_xpath(XPATH, "samlp": ::Saml::Kit::Namespaces::PROTOCOL).name] || InvalidDocument
74
+ namespaces = { samlp: Namespaces::PROTOCOL }
75
+ element = Nokogiri::XML(xml).at_xpath(XPATH, namespaces)
76
+ constructor = CONSTRUCTORS[element.name].try(:call) || InvalidDocument
117
77
  constructor.new(xml, configuration: configuration)
118
78
  rescue StandardError => error
119
79
  Saml::Kit.logger.error(error)
@@ -122,18 +82,12 @@ module Saml
122
82
 
123
83
  # @!visibility private
124
84
  def builder_class # :nodoc:
125
- case name
126
- when Saml::Kit::Response.to_s
127
- Saml::Kit::Builders::Response
128
- when Saml::Kit::LogoutResponse.to_s
129
- Saml::Kit::Builders::LogoutResponse
130
- when Saml::Kit::AuthenticationRequest.to_s
131
- Saml::Kit::Builders::AuthenticationRequest
132
- when Saml::Kit::LogoutRequest.to_s
133
- Saml::Kit::Builders::LogoutRequest
134
- else
135
- raise ArgumentError, "Unknown SAML Document #{name}"
136
- end
85
+ {
86
+ Response.to_s => Saml::Kit::Builders::Response,
87
+ LogoutResponse.to_s => Saml::Kit::Builders::LogoutResponse,
88
+ AuthenticationRequest.to_s => Saml::Kit::Builders::AuthenticationRequest,
89
+ LogoutRequest.to_s => Saml::Kit::Builders::LogoutRequest,
90
+ }[name] || (raise ArgumentError, "Unknown SAML Document #{name}")
137
91
  end
138
92
  end
139
93
 
@@ -2,16 +2,31 @@
2
2
 
3
3
  module Saml
4
4
  module Kit
5
- # This class is used to parse the IDPSSODescriptor from a SAML metadata document.
5
+ # This class parses the IDPSSODescriptor from a SAML metadata document.
6
6
  #
7
7
  # raw_xml = <<-XML
8
8
  # <?xml version="1.0" encoding="UTF-8"?>
9
- # <EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_cfa24e2f-0ec0-4ee3-abb8-b2fcfe394c1c" entityID="">
10
- # <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
11
- # <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.example.com/logout"/>
12
- # <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
13
- # <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.example.com/login"/>
14
- # <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://www.example.com/login"/>
9
+ # <EntityDescriptor
10
+ # xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
11
+ # xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
12
+ # xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
13
+ # ID="_cfa24e2f-0ec0-4ee3-abb8-b2fcfe394c1c"
14
+ # entityID="my-entity-id">
15
+ # <IDPSSODescriptor
16
+ # WantAuthnRequestsSigned="true"
17
+ # protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
18
+ # <SingleLogoutService
19
+ # Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
20
+ # Location="https://www.example.com/logout" />
21
+ # <NameIDFormat>
22
+ # urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
23
+ # </NameIDFormat>
24
+ # <SingleSignOnService
25
+ # Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
26
+ # Location="https://www.example.com/login" />
27
+ # <SingleSignOnService
28
+ # Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
29
+ # Location="https://www.example.com/login" />
15
30
  # <saml:Attribute Name="id"/>
16
31
  # </IDPSSODescriptor>
17
32
  # </EntityDescriptor>
@@ -70,14 +85,18 @@ module Saml
70
85
  # Creates a AuthnRequest document for the specified binding.
71
86
  #
72
87
  # @param binding [Symbol] `:http_post` or `:http_redirect`.
73
- # @param relay_state [Object] The RelayState to include the returned SAML params.
74
- # @param configuration [Saml::Kit::Configuration] the configuration to use for generating the request.
75
- # @return [Array] The url and saml params encoded using the rules for the specified binding.
76
- def login_request_for(binding:, relay_state: nil, configuration: Saml::Kit.configuration)
77
- builder = Saml::Kit::AuthenticationRequest.builder(configuration: configuration) do |xxx|
78
- xxx.embed_signature = want_authn_requests_signed
79
- yield xxx if block_given?
80
- end
88
+ # @param relay_state [Object] RelayState to include the returned params.
89
+ # @param configuration [Saml::Kit::Configuration] the configuration to
90
+ # use for generating the request.
91
+ # @return [Array] Url and params encoded using rules for binding.
92
+ def login_request_for(
93
+ binding:, relay_state: nil, configuration: Saml::Kit.configuration
94
+ )
95
+ builder =
96
+ AuthenticationRequest.builder(configuration: configuration) do |x|
97
+ x.embed_signature = want_authn_requests_signed
98
+ yield x if block_given?
99
+ end
81
100
  request_binding = single_sign_on_service_for(binding: binding)
82
101
  request_binding.serialize(builder, relay_state: relay_state)
83
102
  end
@@ -10,7 +10,7 @@ module Saml
10
10
  model.errors[:base] << model.error_message(:invalid)
11
11
  end
12
12
 
13
- def initialize(xml, configuration: nil)
13
+ def initialize(xml, *)
14
14
  super(xml, name: 'InvalidDocument')
15
15
  end
16
16
 
@@ -16,7 +16,8 @@ module Saml
16
16
  #
17
17
  # See {Saml::Kit::Builders::LogoutRequest} for a list of available settings.
18
18
  #
19
- # This class can also be used to generate the correspondong LogoutResponse for a LogoutRequest.
19
+ # This class can also be used to generate the correspondong LogoutResponse
20
+ # for a LogoutRequest.
20
21
  #
21
22
  # document = Saml::Kit::LogoutRequest.new(raw_xml)
22
23
  # url, saml_params = document.response_for(binding: :http_post)
@@ -31,7 +32,7 @@ module Saml
31
32
  # A new instance of LogoutRequest
32
33
  #
33
34
  # @param xml [String] The raw xml string.
34
- # @param configuration [Saml::Kit::Configuration] the configuration to use.
35
+ # @param configuration [Saml::Kit::Configuration] configuration to use.
35
36
  def initialize(xml, configuration: Saml::Kit.configuration)
36
37
  super(xml, name: 'LogoutRequest', configuration: configuration)
37
38
  end
@@ -45,11 +46,15 @@ module Saml
45
46
  at_xpath('./*/saml:NameID/@Format').try(:value)
46
47
  end
47
48
 
48
- # Generates a Serialized LogoutResponse using the encoding rules for the specified binding.
49
+ # Generates a Serialized LogoutResponse using the encoding rules for
50
+ # the specified binding.
49
51
  #
50
- # @param binding [Symbol] The binding to use `:http_redirect` or `:http_post`.
51
- # @param relay_state [Object] The RelayState to include in the RelayState param.
52
- # @return [Array] Returns an array with a url and Hash of parameters to return to the requestor.
52
+ # @param binding [Symbol] The binding to use `:http_redirect` or
53
+ # `:http_post`.
54
+ # @param relay_state [Object] The RelayState to include in the
55
+ # RelayState param.
56
+ # @return [Array] Returns an array with a url and Hash of parameters to
57
+ # return to the requestor.
53
58
  def response_for(binding:, relay_state: nil)
54
59
  builder = Saml::Kit::LogoutResponse.builder(self) do |xxx|
55
60
  yield xxx if block_given?
@@ -10,7 +10,9 @@ module Saml
10
10
  class LogoutResponse < Document
11
11
  include Respondable
12
12
 
13
- def initialize(xml, request_id: nil, configuration: Saml::Kit.configuration)
13
+ def initialize(
14
+ xml, request_id: nil, configuration: Saml::Kit.configuration
15
+ )
14
16
  @request_id = request_id
15
17
  super(xml, name: 'LogoutResponse', configuration: configuration)
16
18
  end