libsaml 3.6.0 → 3.9.2

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: 9eea4c36aa9fc6f404ff5e6283c2ef39c1cb0e328652edc5e5fda2ceb7b21416
4
- data.tar.gz: d76324210f3fe2863f82f89ac7b7317bc295798ec10982b903f2e3b2700dd62f
3
+ metadata.gz: 80a144ab0df42eeb447e74d6df3f3a19a7d89e72cf5527277403b229eb87216c
4
+ data.tar.gz: cd41e41d4f0492e98c52ea9c6865e958a0896c0522f987b58175c69e2d23eaac
5
5
  SHA512:
6
- metadata.gz: 40a5e18247a43f3e215ce6045d51feeb2774a86e649b4702a64533555b4c5c98b83dad3927b3238929d141f0c49a1078903a278b2ccd76cdf6c29d6188f71839
7
- data.tar.gz: 0eda4d5265000e0da3fc7d2650b69064cda9de9914a287cecb2974e077f42d4c76d05e30e7025a56f6ba7173128c63a652b185f0253424715e6e62227f5bdb45
6
+ metadata.gz: 258f442a035b8e06cb9896ed2faf0c5e88d4d58c63ddfcbcd19b14b937fed2de1482aa89bd92bf3b8bcff20f32e5c65b0f92355eefcb1abe0944f2c14a470b45
7
+ data.tar.gz: faa732f728819578d2e75a73129148da7e74eefca3d5ef7a033b7926d2266c417f9c52666dae8c0eef5f3c6fa06032b6da2bdf7eb5118ba4fb9758d127d8f626
data/README.md CHANGED
@@ -94,10 +94,10 @@ Now you can make a SAML controller in `app/controllers/saml_controller.rb`:
94
94
  ```ruby
95
95
  class SamlController < ApplicationController
96
96
  extend Saml::Rails::ControllerHelper
97
- current_provider "entity_id"
97
+ current_provider "<sp_entity_id>"
98
98
 
99
99
  def request_authentication
100
- provider = Saml.provider("my:very:original:entityid")
100
+ provider = Saml.provider("<idp_enity_id>")
101
101
  destination = provider.single_sign_on_service_url(Saml::ProtocolBinding::HTTP_POST)
102
102
 
103
103
  authn_request = Saml::AuthnRequest.new(destination: destination)
@@ -153,7 +153,7 @@ Below is an example of a very primitive IDP Saml Controller
153
153
  ```ruby
154
154
  class SamlController < ActionController::Base
155
155
  extend Saml::Rails::ControllerHelper
156
- current_provider "entity_id"
156
+ current_provider "<idp_entity_id>"
157
157
 
158
158
  def receive_authn_request
159
159
  authn_request = if request.get?
@@ -227,6 +227,10 @@ class SamlController < ActionController::Base
227
227
  end
228
228
  ```
229
229
 
230
+ ## Caveats
231
+
232
+ - SAMLResponse and Assertions have to be signed as per the SAML security guidelines (Some IDP's don't do this by default and require special configuration)
233
+
230
234
  ## Contributing
231
235
 
232
236
  - Fork the project
data/lib/saml.rb CHANGED
@@ -34,6 +34,8 @@ module Saml
34
34
  end
35
35
  class UnparseableMessage < SamlError
36
36
  end
37
+ class InvalidParams < SamlError
38
+ end
37
39
  class MetadataDownloadFailed < SamlError
38
40
  end
39
41
  class InvalidStore < SamlError
@@ -46,7 +46,8 @@ module Saml
46
46
  @authn_statement = Saml::Elements::AuthnStatement.new(authn_instant: authn_instant,
47
47
  address: options.delete(:address),
48
48
  authn_context_class_ref: options.delete(:authn_context_class_ref),
49
- session_index: options.delete(:session_index))
49
+ session_index: options.delete(:session_index),
50
+ session_not_on_or_after: options.delete(:session_not_on_or_after))
50
51
  super(*(args << options))
51
52
  @_id ||= Saml.generate_id
52
53
  @issue_instant ||= Time.now
@@ -20,7 +20,12 @@ module Saml
20
20
  end
21
21
 
22
22
  def receive_message(request, type)
23
- message = Saml::Encoding.decode_64(request.params["SAMLRequest"] || request.params["SAMLResponse"])
23
+ receive_xml = request.params["SAMLRequest"] || request.params["SAMLResponse"]
24
+ if receive_xml.nil?
25
+ raise Saml::Errors::InvalidParams, 'require params `SAMLRequest` or `SAMLResponse`'
26
+ end
27
+
28
+ message = Saml::Encoding.decode_64(receive_xml)
24
29
  notify('receive_message', message)
25
30
  request_or_response = Saml.parse_message(message, type)
26
31
 
@@ -5,7 +5,7 @@ module Saml
5
5
 
6
6
  class << self
7
7
  def create_url(request_or_response, options = {})
8
- options[:signature_algorithm] ||= 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
8
+ options[:signature_algorithm] ||= 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' unless options[:exclude_signature]
9
9
  new(request_or_response, options).create_url
10
10
  end
11
11
 
@@ -42,13 +42,14 @@ module Saml
42
42
  end
43
43
  end
44
44
 
45
- attr_accessor :request_or_response, :signature_algorithm, :relay_state, :signature
45
+ attr_accessor :request_or_response, :signature_algorithm, :relay_state, :signature, :exclude_signature
46
46
 
47
47
  def initialize(request_or_response, options = {})
48
48
  @request_or_response = request_or_response
49
49
  @signature_algorithm = options[:signature_algorithm]
50
50
  @relay_state = options[:relay_state]
51
51
  @signature = options[:signature]
52
+ @exclude_signature = options[:exclude_signature]
52
53
  end
53
54
 
54
55
  def verify_signature(query)
@@ -61,7 +62,7 @@ module Saml
61
62
  url = request_or_response.destination
62
63
  delimiter = url.include?('?') ? '&' : '?'
63
64
 
64
- [url, signed_params].join(delimiter)
65
+ [url, exclude_signature ? unsigned_params : signed_params].join(delimiter)
65
66
  end
66
67
 
67
68
  private
@@ -108,6 +109,10 @@ module Saml
108
109
 
109
110
  "#{encoded_params}&Signature=#{encoded_signature}"
110
111
  end
112
+
113
+ def unsigned_params
114
+ encoded_params.to_s
115
+ end
111
116
  end
112
117
  end
113
118
  end
@@ -8,6 +8,7 @@ module Saml
8
8
 
9
9
  attribute :authn_instant, Time, tag: "AuthnInstant", on_save: lambda { |val| val.utc.xmlschema }
10
10
  attribute :session_index, String, tag: "SessionIndex"
11
+ attribute :session_not_on_or_after, Time, tag: "SessionNotOnOrAfter", on_save: lambda { |val| val.utc.xmlschema if val.present?}
11
12
 
12
13
  has_one :subject_locality, Saml::Elements::SubjectLocality, tag: "SubjectLocality"
13
14
  has_one :authn_context, Saml::Elements::AuthnContext, tag: "AuthnContext"
@@ -15,27 +15,9 @@ module Saml
15
15
  validates :encrypted_data, presence: true
16
16
 
17
17
  def encrypt(attribute, encrypted_key_data, encrypted_data_options = {})
18
- self.encrypted_data = Xmlenc::Builder::EncryptedData.new(encrypted_data_options)
19
- self.encrypted_data.set_encryption_method algorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'
20
- self.encrypted_data.set_key_name key_name
21
-
22
- encrypted_key_data.each do |key_descriptor, key_options|
23
- encrypted_key = self.encrypted_data.encrypt Nokogiri::XML(attribute.to_xml).root.to_xml, key_options
24
- encrypted_key.set_encryption_method algorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', digest_method_algorithm: 'http://www.w3.org/2000/09/xmldsig#sha1'
25
- encrypted_key.set_key_name key_descriptor.key_info.key_name
26
- encrypted_key.carried_key_name = key_name
27
- encrypted_key.encrypt key_descriptor.certificate.public_key
28
-
29
- self.encrypted_keys ||= []
30
- self.encrypted_keys << encrypted_key
31
- end
18
+ Saml::Util.encrypt_element(self, attribute, encrypted_key_data, encrypted_data_options)
32
19
  end
33
20
 
34
- private
35
-
36
- def key_name
37
- @key_name ||= Saml.generate_id
38
- end
39
21
  end
40
22
  end
41
23
  end
@@ -28,16 +28,16 @@ module Saml
28
28
 
29
29
  if key_descriptors.any?
30
30
  if key_descriptors.one?
31
- encrypt_for_one_recipient(key_descriptors.first, key_options)
31
+ encrypt_for_one_key_descriptor(key_descriptors.first, key_options)
32
32
  else
33
- encrypt_for_multiple_recipients(key_descriptors, key_options)
33
+ encrypt_for_multiple_key_descriptors(key_descriptors, key_options)
34
34
  end
35
35
  end
36
36
  end
37
37
 
38
38
  private
39
39
 
40
- def encrypt_for_one_recipient(key_descriptor, key_options = {})
40
+ def encrypt_for_one_key_descriptor(key_descriptor, key_options = {})
41
41
  self.encrypted_data = Xmlenc::Builder::EncryptedData.new
42
42
 
43
43
  self.encrypted_data.set_key_retrieval_method Xmlenc::Builder::RetrievalMethod.new(
@@ -47,7 +47,7 @@ module Saml
47
47
  algorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'
48
48
  )
49
49
 
50
- encrypted_key = self.encrypted_data.encrypt(name_id_xml, key_options)
50
+ encrypted_key = self.encrypted_data.encrypt(Nokogiri::XML(name_id.to_xml).root.to_xml, key_options)
51
51
  encrypted_key.set_encryption_method(
52
52
  algorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p',
53
53
  digest_method_algorithm: 'http://www.w3.org/2000/09/xmldsig#sha1'
@@ -60,39 +60,18 @@ module Saml
60
60
  self.name_id = nil
61
61
  end
62
62
 
63
- def encrypt_for_multiple_recipients(key_descriptors, key_options = {})
64
- key_name = key_options[:key_name]
65
- encrypted_keys = []
66
-
67
- self.encrypted_data = Xmlenc::Builder::EncryptedData.new
68
- self.encrypted_data.set_key_name key_name
69
- self.encrypted_data.set_encryption_method(
70
- algorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'
71
- )
72
-
73
- key_descriptors.each do |key_descriptor|
74
- encrypted_key = self.encrypted_data.encrypt(
75
- name_id_xml,
76
- key_options.merge(id: "_#{SecureRandom.uuid}", carried_key_name: key_name)
77
- )
78
- encrypted_key.set_encryption_method(
79
- algorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p',
80
- digest_method_algorithm: 'http://www.w3.org/2000/09/xmldsig#sha1'
81
- )
82
-
83
- encrypted_key.set_key_name(key_descriptor.key_info.key_name)
84
- encrypted_key.encrypt(key_descriptor.certificate.public_key)
85
-
86
- encrypted_keys << encrypted_key
63
+ def encrypt_for_multiple_key_descriptors(encrypted_key_data, encrypted_data_options = {})
64
+ if encrypted_data_options[:recipient].present? && encrypted_key_data.first.is_a?(Saml::Elements::KeyDescriptor)
65
+ encrypted_key_data.map! do |key_descriptor|
66
+ [ key_descriptor, { recipient: encrypted_data_options[:recipient] } ]
67
+ end
87
68
  end
88
69
 
89
- self.encrypted_keys = encrypted_keys
70
+ Saml::Util.encrypt_element(self, name_id, encrypted_key_data, encrypted_data_options)
71
+
90
72
  self.name_id = nil
91
73
  end
92
74
 
93
- def name_id_xml
94
- Nokogiri::XML(name_id.to_xml).root.to_xml
95
- end
96
75
  end
97
76
  end
98
77
  end
data/lib/saml/response.rb CHANGED
@@ -28,10 +28,14 @@ module Saml
28
28
  !success? && status.status_code.unknown_principal?
29
29
  end
30
30
 
31
- def encrypt_assertions(certificate, include_certificate: false)
31
+ def encrypt_assertions(key_descriptor_or_certificate, include_certificate: false, include_key_retrieval_method: false)
32
32
  @encrypted_assertions = []
33
33
  assertions.each do |assertion|
34
- @encrypted_assertions << Saml::Util.encrypt_assertion(assertion, certificate, include_certificate: include_certificate)
34
+ @encrypted_assertions << Saml::Util.encrypt_assertion(
35
+ assertion, key_descriptor_or_certificate,
36
+ include_certificate: include_certificate,
37
+ include_key_retrieval_method: include_key_retrieval_method
38
+ )
35
39
  end
36
40
  assertions.clear
37
41
  end
data/lib/saml/util.rb CHANGED
@@ -60,7 +60,7 @@ module Saml
60
60
  end
61
61
  end
62
62
 
63
- def encrypt_assertion(assertion, key_descriptor_or_certificate, include_certificate: false)
63
+ def encrypt_assertion(assertion, key_descriptor_or_certificate, include_certificate: false, include_key_retrieval_method: false)
64
64
  case key_descriptor_or_certificate
65
65
  when OpenSSL::X509::Certificate
66
66
  certificate = key_descriptor_or_certificate
@@ -87,6 +87,11 @@ module Saml
87
87
  end
88
88
  encrypted_key.encrypt(certificate.public_key)
89
89
 
90
+ if include_key_retrieval_method
91
+ encrypted_key.id = '_' + SecureRandom.uuid
92
+ encrypted_data.set_key_retrieval_method (Xmlenc::Builder::RetrievalMethod.new(uri: "##{encrypted_key.id}"))
93
+ end
94
+
90
95
  Saml::Elements::EncryptedAssertion.new(encrypted_data: encrypted_data, encrypted_keys: encrypted_key)
91
96
  end
92
97
 
@@ -98,6 +103,32 @@ module Saml
98
103
  Saml::Assertion.parse(encrypted_document.decrypt(private_key), single: true)
99
104
  end
100
105
 
106
+ def encrypt_element(element, target_element, encrypted_key_data, encrypted_data_options)
107
+ key_name = encrypted_data_options.fetch(:key_name, Saml.generate_id)
108
+
109
+ element.encrypted_data = Xmlenc::Builder::EncryptedData.new(encrypted_data_options)
110
+ element.encrypted_data.set_encryption_method(algorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc')
111
+ element.encrypted_data.set_key_name key_name
112
+
113
+ original_encrypted_key = element.encrypted_data.encrypt(Nokogiri::XML(target_element.to_xml).root.to_xml, encrypted_data_options)
114
+
115
+ encrypted_key_data.each do |key_descriptor, key_options = {}|
116
+ encrypted_key_options = key_options.merge(id: Saml.generate_id, data: original_encrypted_key.data)
117
+
118
+ encrypted_key = Xmlenc::Builder::EncryptedKey.new(encrypted_key_options)
119
+ encrypted_key.add_data_reference(element.encrypted_data.id)
120
+ encrypted_key.set_key_name(key_descriptor.key_info.key_name)
121
+ encrypted_key.carried_key_name = key_name
122
+ encrypted_key.set_encryption_method(algorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', digest_method_algorithm: 'http://www.w3.org/2000/09/xmldsig#sha1')
123
+ encrypted_key.encrypt(key_descriptor.certificate.public_key)
124
+
125
+ element.encrypted_keys ||= []
126
+ element.encrypted_keys << encrypted_key
127
+ end
128
+
129
+ element
130
+ end
131
+
101
132
  def encrypt_name_id(name_id, key_descriptor, key_options = {})
102
133
  encrypted_id = Saml::Elements::EncryptedID.new(name_id: name_id)
103
134
  encrypt_encrypted_id(encrypted_id, key_descriptor, key_options)
data/lib/saml/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Saml
2
- VERSION = '3.6.0'
2
+ VERSION = '3.9.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libsaml
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benoist Claassen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-10 00:00:00.000000000 Z
11
+ date: 2021-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -240,7 +240,7 @@ homepage: https://www.digidentity.eu
240
240
  licenses:
241
241
  - MIT
242
242
  metadata: {}
243
- post_install_message:
243
+ post_install_message:
244
244
  rdoc_options: []
245
245
  require_paths:
246
246
  - lib
@@ -256,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
256
256
  version: '0'
257
257
  requirements: []
258
258
  rubygems_version: 3.0.3
259
- signing_key:
259
+ signing_key:
260
260
  specification_version: 4
261
261
  summary: A gem to easily create SAML 2.0 messages.
262
262
  test_files: []