saml-kit 1.0.15 → 1.0.16

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.
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