saml-kit 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13c5ee20e28acd63c6ec3dde99cd1fea092be3db550dca1bd129a4b0e1fb83d3
4
- data.tar.gz: 0337c7d33845d4fbfb9dd6cc817cfde1dc620c3745cfd83b96f246e29ec30dc3
3
+ metadata.gz: b98601350af83c7090bc7fead240f7fabb4736f642a262502a96c48e533f3203
4
+ data.tar.gz: a51e398301b1115654dbe0a8a31bf61b029456c12302bb42512b7dac716d38e8
5
5
  SHA512:
6
- metadata.gz: cc09a60391991a964b3f6114e6c039da70eb917ba268787abe8940bc00a8883449f5e751aeb2365b9cae5f693d177ded5fd2d9d152ae766569a9feb5a8198ad2
7
- data.tar.gz: e6cd00b9f963348a4b9cce442d09fe7b5819c0b970334ccff01c6fcfcce54e60cfff7692878f5603a6e54061c2b75b0df61364e2eaa1717547fdc079efbe588c
6
+ metadata.gz: 1d032fb605d2c62e45e491ddde0e90274f3ae0ddab82c7e4daa72cfcc7c992483abcd5151399c67d7205bcb0de2ebe1fb1e1953fe416c9efac333e1dba86ab56
7
+ data.tar.gz: d330dc2cc0a7dfd9d7fb29e9ec9da4b9549739160f77bc6de73f1d6bd9ca15851faa595a3ccf7a75064479751b81123beaf4fb0dd6b31f5f193fbc4fd0ce182e
data/lib/saml/kit.rb CHANGED
@@ -24,6 +24,7 @@ require "saml/kit/xsd_validatable"
24
24
  require "saml/kit/respondable"
25
25
  require "saml/kit/requestable"
26
26
  require "saml/kit/trustable"
27
+ require "saml/kit/translatable"
27
28
  require "saml/kit/document"
28
29
 
29
30
  require "saml/kit/assertion"
@@ -1,7 +1,15 @@
1
1
  module Saml
2
2
  module Kit
3
3
  class Assertion
4
+ include ActiveModel::Validations
5
+ include Translatable
6
+
7
+ validate :must_match_issuer
8
+ validate :must_be_active_session
9
+ attr_reader :name
10
+
4
11
  def initialize(xml_hash, configuration:)
12
+ @name = "Assertion"
5
13
  @xml_hash = xml_hash
6
14
  @configuration = configuration
7
15
  end
@@ -11,7 +19,20 @@ module Saml
11
19
  end
12
20
 
13
21
  def signed?
14
- assertion.fetch('Signature', nil).present?
22
+ signature.present?
23
+ end
24
+
25
+ def signature
26
+ xml_hash = assertion.fetch('Signature', nil)
27
+ xml_hash ? Signature.new(xml_hash) : nil
28
+ end
29
+
30
+ def expired?
31
+ Time.current > expired_at
32
+ end
33
+
34
+ def active?
35
+ Time.current > started_at && !expired?
15
36
  end
16
37
 
17
38
  def attributes
@@ -35,10 +56,6 @@ module Saml
35
56
  parse_date(assertion.fetch('Conditions', {}).fetch('NotOnOrAfter', nil))
36
57
  end
37
58
 
38
- def certificate
39
- assertion.fetch('Signature', {}).fetch('KeyInfo', {}).fetch('X509Data', {}).fetch('X509Certificate', nil)
40
- end
41
-
42
59
  def audiences
43
60
  Array(assertion['Conditions']['AudienceRestriction']['Audience'])
44
61
  rescue => error
@@ -68,6 +85,17 @@ module Saml
68
85
  Saml::Kit.logger.error(error)
69
86
  Time.at(0).to_datetime
70
87
  end
88
+
89
+ def must_match_issuer
90
+ unless audiences.include?(@configuration.issuer)
91
+ errors[:audience] << error_message(:must_match_issuer)
92
+ end
93
+ end
94
+
95
+ def must_be_active_session
96
+ return if active?
97
+ errors[:base] << error_message(:expired)
98
+ end
71
99
  end
72
100
  end
73
101
  end
@@ -21,7 +21,7 @@ module Saml
21
21
  private
22
22
 
23
23
  def signature_for(payload)
24
- private_key = configuration.private_keys(use: :signing).sample
24
+ private_key = configuration.private_keys(use: :signing).last
25
25
  encode(private_key.sign(OpenSSL::Digest::SHA256.new, payload))
26
26
  end
27
27
 
@@ -8,6 +8,10 @@ module Saml
8
8
  builder(*args, &block).build
9
9
  end
10
10
 
11
+ def build_xml(*args, &block)
12
+ builder(*args, &block).to_xml
13
+ end
14
+
11
15
  def builder(*args)
12
16
  builder_class.new(*args).tap do |builder|
13
17
  yield builder if block_given?
@@ -24,7 +24,7 @@ module Saml
24
24
  def initialize(reference_id, configuration:)
25
25
  @configuration = configuration
26
26
  @reference_id = reference_id
27
- @x509_certificate = configuration.certificates(use: :signing).sample.stripped
27
+ @x509_certificate = configuration.certificates(use: :signing).last.stripped
28
28
  end
29
29
 
30
30
  def signature_method
@@ -19,11 +19,11 @@ module Saml
19
19
  end
20
20
 
21
21
  def encryption?
22
- :encryption == use
22
+ for?(:encryption)
23
23
  end
24
24
 
25
25
  def signing?
26
- :signing == use
26
+ for?(:signing)
27
27
  end
28
28
 
29
29
  def x509
@@ -2,8 +2,9 @@ module Saml
2
2
  module Kit
3
3
  class Document
4
4
  PROTOCOL_XSD = File.expand_path("./xsd/saml-schema-protocol-2.0.xsd", File.dirname(__FILE__)).freeze
5
- include XsdValidatable
6
5
  include ActiveModel::Validations
6
+ include XsdValidatable
7
+ include Translatable
7
8
  include Trustable
8
9
  include Buildable
9
10
  validates_presence_of :content
@@ -2,6 +2,8 @@
2
2
  en:
3
3
  saml/kit:
4
4
  errors:
5
+ Assertion:
6
+ expired: "must not be expired."
5
7
  AuthnRequest:
6
8
  invalid: "must contain AuthnRequest."
7
9
  invalid_fingerprint: "does not match."
@@ -17,7 +19,6 @@ en:
17
19
  LogoutResponse:
18
20
  unregistered: "is unregistered."
19
21
  Response:
20
- expired: "must not be expired."
21
22
  invalid: "must contain Response."
22
23
  invalid_fingerprint: "does not match."
23
24
  invalid_response_to: "must match request id."
@@ -1,10 +1,11 @@
1
1
  module Saml
2
2
  module Kit
3
3
  class Metadata
4
+ METADATA_XSD = File.expand_path("./xsd/saml-schema-metadata-2.0.xsd", File.dirname(__FILE__)).freeze
4
5
  include ActiveModel::Validations
5
6
  include XsdValidatable
7
+ include Translatable
6
8
  include Buildable
7
- METADATA_XSD = File.expand_path("./xsd/saml-schema-metadata-2.0.xsd", File.dirname(__FILE__)).freeze
8
9
 
9
10
  validates_presence_of :metadata
10
11
  validate :must_contain_descriptor
@@ -4,50 +4,25 @@ module Saml
4
4
  include Respondable
5
5
  extend Forwardable
6
6
 
7
- def_delegators :assertion, :name_id, :[], :attributes, :started_at, :expired_at, :audiences
7
+ def_delegators :assertion, :name_id, :[], :attributes
8
8
 
9
- validate :must_be_active_session
10
- validate :must_match_issuer
9
+ validate :must_be_valid_assertion
11
10
 
12
11
  def initialize(xml, request_id: nil, configuration: Saml::Kit.configuration)
13
12
  @request_id = request_id
14
13
  super(xml, name: "Response", configuration: configuration)
15
14
  end
16
15
 
17
- def expired?
18
- Time.current > expired_at
19
- end
20
-
21
- def active?
22
- Time.current > started_at && !expired?
23
- end
24
-
25
16
  def assertion
26
- @assertion = Saml::Kit::Assertion.new(to_h, configuration: @configuration)
27
- end
28
-
29
- def signed?
30
- super || assertion.signed?
31
- end
32
-
33
- def certificate
34
- super || assertion.certificate
17
+ @assertion ||= Saml::Kit::Assertion.new(to_h, configuration: @configuration)
35
18
  end
36
19
 
37
20
  private
38
21
 
39
- def must_be_active_session
40
- return unless expected_type?
41
- return unless success?
42
- errors[:base] << error_message(:expired) unless active?
43
- end
44
-
45
- def must_match_issuer
46
- return unless expected_type?
47
- return unless success?
48
-
49
- unless audiences.include?(configuration.issuer)
50
- errors[:audience] << error_message(:must_match_issuer)
22
+ def must_be_valid_assertion
23
+ assertion.valid?
24
+ assertion.errors.each do |attribute, error|
25
+ self.errors[attribute] << error
51
26
  end
52
27
  end
53
28
 
@@ -1,22 +1,23 @@
1
1
  module Saml
2
2
  module Kit
3
3
  class Signature
4
- attr_reader :signatures
5
- attr_reader :xml
4
+ def initialize(xml_hash)
5
+ @xml_hash = xml_hash
6
+ end
6
7
 
7
- def initialize(xml, signatures)
8
- @signatures = signatures
9
- @xml = xml
8
+ def certificate
9
+ value = to_h.fetch('KeyInfo', {}).fetch('X509Data', {}).fetch('X509Certificate', nil)
10
+ return if value.nil?
11
+ Saml::Kit::Certificate.new(value, use: :signing)
10
12
  end
11
13
 
12
- def template(reference_id)
13
- Template.new(signatures.build(reference_id)).to_xml(xml: xml)
14
+ def trusted?(metadata)
15
+ return false if metadata.nil?
16
+ metadata.matches?(certificate.fingerprint, use: :signing)
14
17
  end
15
18
 
16
- def self.sign(xml: ::Builder::XmlMarkup.new, configuration: Saml::Kit.configuration)
17
- signatures = Saml::Kit::Signatures.new(configuration: configuration)
18
- yield xml, new(xml, signatures)
19
- signatures.complete(xml.target!)
19
+ def to_h
20
+ @xml_hash
20
21
  end
21
22
  end
22
23
  end
@@ -14,9 +14,28 @@ module Saml
14
14
 
15
15
  def complete(raw_xml)
16
16
  return raw_xml unless configuration.sign?
17
- private_key = configuration.private_keys(use: :signing).sample
17
+ private_key = configuration.private_keys(use: :signing).last
18
18
  Xmldsig::SignedDocument.new(raw_xml).sign(private_key)
19
19
  end
20
+
21
+ def self.sign(xml: ::Builder::XmlMarkup.new, configuration: Saml::Kit.configuration)
22
+ signatures = Saml::Kit::Signatures.new(configuration: configuration)
23
+ yield xml, XmlSignatureTemplate.new(xml, signatures)
24
+ signatures.complete(xml.target!)
25
+ end
26
+
27
+ class XmlSignatureTemplate
28
+ attr_reader :signatures, :xml
29
+
30
+ def initialize(xml, signatures)
31
+ @signatures = signatures
32
+ @xml = xml
33
+ end
34
+
35
+ def template(reference_id)
36
+ Template.new(signatures.build(reference_id)).to_xml(xml: xml)
37
+ end
38
+ end
20
39
  end
21
40
  end
22
41
  end
@@ -21,7 +21,7 @@ module Saml
21
21
  end
22
22
 
23
23
  def encryption_for(xml:)
24
- if encrypt && encryption_certificate
24
+ if encrypt?
25
25
  temp = ::Builder::XmlMarkup.new
26
26
  yield temp
27
27
  xml_encryption = Saml::Kit::Builders::XmlEncryption.new(temp.target!, encryption_certificate.public_key)
@@ -31,6 +31,10 @@ module Saml
31
31
  end
32
32
  end
33
33
 
34
+ def encrypt?
35
+ encrypt && encryption_certificate
36
+ end
37
+
34
38
  def render(model, options)
35
39
  Saml::Kit::Template.new(model).to_xml(options)
36
40
  end
@@ -0,0 +1,9 @@
1
+ module Saml
2
+ module Kit
3
+ module Translatable
4
+ def error_message(attribute, type: :invalid)
5
+ I18n.translate(attribute, scope: "saml/kit.errors.#{name}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -9,24 +9,18 @@ module Saml
9
9
  validate :must_be_trusted, unless: :signature_manually_verified
10
10
  end
11
11
 
12
- def certificate
13
- return unless signed?
14
- to_h.fetch(name, {}).fetch('Signature', {}).fetch('KeyInfo', {}).fetch('X509Data', {}).fetch('X509Certificate', nil)
15
- end
16
-
17
- def fingerprint
18
- return if certificate.blank?
19
- Fingerprint.new(certificate)
12
+ def signed?
13
+ signature.present?
20
14
  end
21
15
 
22
- def signed?
23
- to_h.fetch(name, {}).fetch('Signature', nil).present?
16
+ def signature
17
+ xml_hash = to_h.fetch(name, {}).fetch('Signature', nil)
18
+ xml_hash ? Signature.new(xml_hash) : nil
24
19
  end
25
20
 
26
21
  def trusted?
27
- return false if provider.nil?
28
22
  return false unless signed?
29
- provider.matches?(fingerprint, use: :signing)
23
+ signature.trusted?(provider)
30
24
  end
31
25
 
32
26
  def provider
@@ -59,6 +53,7 @@ module Saml
59
53
 
60
54
  def must_be_trusted
61
55
  return if trusted?
56
+ return if provider.present? && !signed?
62
57
  errors[:fingerprint] << error_message(:invalid_fingerprint)
63
58
  end
64
59
  end
@@ -1,5 +1,5 @@
1
1
  module Saml
2
2
  module Kit
3
- VERSION = "0.2.4"
3
+ VERSION = "0.2.5"
4
4
  end
5
5
  end
@@ -4,7 +4,7 @@ module Saml
4
4
  attr_reader :private_key
5
5
 
6
6
  def initialize(configuration: Saml::Kit.configuration)
7
- @private_key = configuration.private_keys(use: :encryption).sample
7
+ @private_key = configuration.private_keys(use: :encryption).last
8
8
  end
9
9
 
10
10
  def decrypt(data)
@@ -10,10 +10,6 @@ module Saml
10
10
  end
11
11
  end
12
12
  end
13
-
14
- def error_message(key)
15
- I18n.translate(key, scope: "saml/kit.errors.#{name}")
16
- end
17
13
  end
18
14
  end
19
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saml-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
@@ -246,6 +246,7 @@ files:
246
246
  - lib/saml/kit/signatures.rb
247
247
  - lib/saml/kit/templatable.rb
248
248
  - lib/saml/kit/template.rb
249
+ - lib/saml/kit/translatable.rb
249
250
  - lib/saml/kit/trustable.rb
250
251
  - lib/saml/kit/version.rb
251
252
  - lib/saml/kit/xml.rb