ruby-saml 1.12.4 → 1.18.1
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/.github/FUNDING.yml +3 -0
- data/.github/workflows/test.yml +29 -2
- data/{changelog.md → CHANGELOG.md} +64 -15
- data/LICENSE +2 -1
- data/README.md +425 -233
- data/UPGRADING.md +158 -0
- data/lib/onelogin/ruby-saml/authrequest.rb +9 -11
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +115 -84
- data/lib/onelogin/ruby-saml/logoutrequest.rb +9 -9
- data/lib/onelogin/ruby-saml/logoutresponse.rb +2 -2
- data/lib/onelogin/ruby-saml/metadata.rb +75 -42
- data/lib/onelogin/ruby-saml/response.rb +130 -70
- data/lib/onelogin/ruby-saml/saml_message.rb +16 -19
- data/lib/onelogin/ruby-saml/settings.rb +214 -110
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +51 -37
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +9 -9
- data/lib/onelogin/ruby-saml/utils.rb +129 -46
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/xml_security.rb +81 -48
- data/ruby-saml.gemspec +40 -14
- metadata +29 -32
- data/.travis.yml +0 -48
|
@@ -4,7 +4,6 @@ require 'base64'
|
|
|
4
4
|
require 'nokogiri'
|
|
5
5
|
require 'rexml/document'
|
|
6
6
|
require 'rexml/xpath'
|
|
7
|
-
require 'thread'
|
|
8
7
|
require "onelogin/ruby-saml/error_handling"
|
|
9
8
|
|
|
10
9
|
# Only supports SAML 2.0
|
|
@@ -16,21 +15,17 @@ module OneLogin
|
|
|
16
15
|
class SamlMessage
|
|
17
16
|
include REXML
|
|
18
17
|
|
|
19
|
-
ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
|
|
20
|
-
PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
|
|
18
|
+
ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion".freeze
|
|
19
|
+
PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol".freeze
|
|
21
20
|
|
|
22
21
|
BASE64_FORMAT = %r(\A([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z)
|
|
23
|
-
@@mutex = Mutex.new
|
|
24
|
-
|
|
25
|
-
MAX_BYTE_SIZE = 250000
|
|
26
22
|
|
|
27
23
|
# @return [Nokogiri::XML::Schema] Gets the schema object of the SAML 2.0 Protocol schema
|
|
28
24
|
#
|
|
29
25
|
def self.schema
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
end
|
|
26
|
+
path = File.expand_path("../../../schemas/saml-schema-protocol-2.0.xsd", __FILE__)
|
|
27
|
+
File.open(path) do |file|
|
|
28
|
+
::Nokogiri::XML::Schema(file)
|
|
34
29
|
end
|
|
35
30
|
end
|
|
36
31
|
|
|
@@ -70,14 +65,14 @@ module OneLogin
|
|
|
70
65
|
def valid_saml?(document, soft = true, check_malformed_doc = true)
|
|
71
66
|
begin
|
|
72
67
|
xml = XMLSecurity::BaseDocument.safe_load_xml(document, check_malformed_doc)
|
|
73
|
-
rescue
|
|
68
|
+
rescue StandardError => error
|
|
74
69
|
return false if soft
|
|
75
70
|
raise ValidationError.new("XML load failed: #{error.message}")
|
|
76
71
|
end
|
|
77
72
|
|
|
78
73
|
SamlMessage.schema.validate(xml).map do |schema_error|
|
|
79
74
|
return false if soft
|
|
80
|
-
raise ValidationError.new("#{schema_error.message}\n\n#{xml
|
|
75
|
+
raise ValidationError.new("#{schema_error.message}\n\n#{xml}")
|
|
81
76
|
end
|
|
82
77
|
end
|
|
83
78
|
|
|
@@ -85,15 +80,17 @@ module OneLogin
|
|
|
85
80
|
|
|
86
81
|
# Base64 decode and try also to inflate a SAML Message
|
|
87
82
|
# @param saml [String] The deflated and encoded SAML Message
|
|
83
|
+
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
|
88
84
|
# @return [String] The plain SAML Message
|
|
89
85
|
#
|
|
90
|
-
def decode_raw_saml(saml)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
raise ValidationError.new("Encoded SAML Message exceeds " + MAX_BYTE_SIZE.to_s + " bytes, so was rejected")
|
|
86
|
+
def decode_raw_saml(saml, settings = nil)
|
|
87
|
+
settings = OneLogin::RubySaml::Settings.new if settings.nil?
|
|
88
|
+
if saml.bytesize > settings.message_max_bytesize
|
|
89
|
+
raise ValidationError.new("Encoded SAML Message exceeds " + settings.message_max_bytesize.to_s + " bytes, so was rejected")
|
|
95
90
|
end
|
|
96
91
|
|
|
92
|
+
return saml unless base64_encoded?(saml)
|
|
93
|
+
|
|
97
94
|
decoded = decode(saml)
|
|
98
95
|
begin
|
|
99
96
|
message = inflate(decoded)
|
|
@@ -101,8 +98,8 @@ module OneLogin
|
|
|
101
98
|
message = decoded
|
|
102
99
|
end
|
|
103
100
|
|
|
104
|
-
if message.bytesize >
|
|
105
|
-
|
|
101
|
+
if message.bytesize > settings.message_max_bytesize
|
|
102
|
+
raise ValidationError.new("SAML Message exceeds " + settings.message_max_bytesize.to_s + " bytes, so was rejected")
|
|
106
103
|
end
|
|
107
104
|
|
|
108
105
|
message
|
|
@@ -20,7 +20,7 @@ module OneLogin
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
config.each do |k,v|
|
|
23
|
-
acc = "#{k
|
|
23
|
+
acc = "#{k}=".to_sym
|
|
24
24
|
if respond_to? acc
|
|
25
25
|
value = v.is_a?(Hash) ? v.dup : v
|
|
26
26
|
send(acc, value)
|
|
@@ -31,9 +31,8 @@ module OneLogin
|
|
|
31
31
|
|
|
32
32
|
# IdP Data
|
|
33
33
|
attr_accessor :idp_entity_id
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
attr_accessor :idp_slo_service_url
|
|
34
|
+
attr_writer :idp_sso_service_url
|
|
35
|
+
attr_writer :idp_slo_service_url
|
|
37
36
|
attr_accessor :idp_slo_response_service_url
|
|
38
37
|
attr_accessor :idp_cert
|
|
39
38
|
attr_accessor :idp_cert_fingerprint
|
|
@@ -43,8 +42,10 @@ module OneLogin
|
|
|
43
42
|
attr_accessor :idp_name_qualifier
|
|
44
43
|
attr_accessor :valid_until
|
|
45
44
|
# SP Data
|
|
45
|
+
attr_writer :sp_entity_id
|
|
46
46
|
attr_accessor :assertion_consumer_service_url
|
|
47
|
-
|
|
47
|
+
attr_reader :assertion_consumer_service_binding
|
|
48
|
+
attr_writer :single_logout_service_url
|
|
48
49
|
attr_accessor :sp_name_qualifier
|
|
49
50
|
attr_accessor :name_identifier_format
|
|
50
51
|
attr_accessor :name_identifier_value
|
|
@@ -53,14 +54,15 @@ module OneLogin
|
|
|
53
54
|
attr_accessor :compress_request
|
|
54
55
|
attr_accessor :compress_response
|
|
55
56
|
attr_accessor :double_quote_xml_attribute_values
|
|
57
|
+
attr_accessor :message_max_bytesize
|
|
56
58
|
attr_accessor :check_malformed_doc
|
|
57
59
|
attr_accessor :passive
|
|
58
|
-
|
|
60
|
+
attr_reader :protocol_binding
|
|
59
61
|
attr_accessor :attributes_index
|
|
60
62
|
attr_accessor :force_authn
|
|
61
63
|
attr_accessor :certificate
|
|
62
|
-
attr_accessor :certificate_new
|
|
63
64
|
attr_accessor :private_key
|
|
65
|
+
attr_accessor :sp_cert_multi
|
|
64
66
|
attr_accessor :authn_context
|
|
65
67
|
attr_accessor :authn_context_comparison
|
|
66
68
|
attr_accessor :authn_context_decl_ref
|
|
@@ -68,9 +70,10 @@ module OneLogin
|
|
|
68
70
|
# Work-flow
|
|
69
71
|
attr_accessor :security
|
|
70
72
|
attr_accessor :soft
|
|
71
|
-
#
|
|
73
|
+
# Deprecated
|
|
74
|
+
attr_accessor :certificate_new
|
|
72
75
|
attr_accessor :assertion_consumer_logout_service_url
|
|
73
|
-
|
|
76
|
+
attr_reader :assertion_consumer_logout_service_binding
|
|
74
77
|
attr_accessor :issuer
|
|
75
78
|
attr_accessor :idp_sso_target_url
|
|
76
79
|
attr_accessor :idp_slo_target_url
|
|
@@ -78,94 +81,89 @@ module OneLogin
|
|
|
78
81
|
# @return [String] IdP Single Sign On Service URL
|
|
79
82
|
#
|
|
80
83
|
def idp_sso_service_url
|
|
81
|
-
|
|
82
|
-
if @idp_sso_service_url.nil?
|
|
83
|
-
if @idp_sso_target_url
|
|
84
|
-
val = @idp_sso_target_url
|
|
85
|
-
end
|
|
86
|
-
else
|
|
87
|
-
val = @idp_sso_service_url
|
|
88
|
-
end
|
|
89
|
-
val
|
|
84
|
+
@idp_sso_service_url || @idp_sso_target_url
|
|
90
85
|
end
|
|
91
86
|
|
|
92
87
|
# @return [String] IdP Single Logout Service URL
|
|
93
88
|
#
|
|
94
89
|
def idp_slo_service_url
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
@idp_slo_service_url || @idp_slo_target_url
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [String] IdP Single Sign On Service Binding
|
|
94
|
+
#
|
|
95
|
+
def idp_sso_service_binding
|
|
96
|
+
@idp_sso_service_binding || idp_binding_from_embed_sign
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Setter for IdP Single Sign On Service Binding
|
|
100
|
+
# @param value [String, Symbol].
|
|
101
|
+
#
|
|
102
|
+
def idp_sso_service_binding=(value)
|
|
103
|
+
@idp_sso_service_binding = get_binding(value)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @return [String] IdP Single Logout Service Binding
|
|
107
|
+
#
|
|
108
|
+
def idp_slo_service_binding
|
|
109
|
+
@idp_slo_service_binding || idp_binding_from_embed_sign
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Setter for IdP Single Logout Service Binding
|
|
113
|
+
# @param value [String, Symbol].
|
|
114
|
+
#
|
|
115
|
+
def idp_slo_service_binding=(value)
|
|
116
|
+
@idp_slo_service_binding = get_binding(value)
|
|
104
117
|
end
|
|
105
118
|
|
|
106
119
|
# @return [String] SP Entity ID
|
|
107
120
|
#
|
|
108
121
|
def sp_entity_id
|
|
109
|
-
|
|
110
|
-
if @sp_entity_id.nil?
|
|
111
|
-
if @issuer
|
|
112
|
-
val = @issuer
|
|
113
|
-
end
|
|
114
|
-
else
|
|
115
|
-
val = @sp_entity_id
|
|
116
|
-
end
|
|
117
|
-
val
|
|
122
|
+
@sp_entity_id || @issuer
|
|
118
123
|
end
|
|
119
124
|
|
|
120
|
-
# Setter for SP
|
|
121
|
-
# @param
|
|
125
|
+
# Setter for SP Protocol Binding
|
|
126
|
+
# @param value [String, Symbol].
|
|
122
127
|
#
|
|
123
|
-
def
|
|
124
|
-
@
|
|
128
|
+
def protocol_binding=(value)
|
|
129
|
+
@protocol_binding = get_binding(value)
|
|
125
130
|
end
|
|
126
131
|
|
|
127
|
-
#
|
|
132
|
+
# Setter for SP Assertion Consumer Service Binding
|
|
133
|
+
# @param value [String, Symbol].
|
|
128
134
|
#
|
|
129
|
-
def
|
|
130
|
-
|
|
131
|
-
if @single_logout_service_url.nil?
|
|
132
|
-
if @assertion_consumer_logout_service_url
|
|
133
|
-
val = @assertion_consumer_logout_service_url
|
|
134
|
-
end
|
|
135
|
-
else
|
|
136
|
-
val = @single_logout_service_url
|
|
137
|
-
end
|
|
138
|
-
val
|
|
135
|
+
def assertion_consumer_service_binding=(value)
|
|
136
|
+
@assertion_consumer_service_binding = get_binding(value)
|
|
139
137
|
end
|
|
140
138
|
|
|
141
|
-
#
|
|
142
|
-
# @param url [String].
|
|
139
|
+
# @return [String] Single Logout Service URL.
|
|
143
140
|
#
|
|
144
|
-
def single_logout_service_url
|
|
145
|
-
@single_logout_service_url
|
|
141
|
+
def single_logout_service_url
|
|
142
|
+
@single_logout_service_url || @assertion_consumer_logout_service_url
|
|
146
143
|
end
|
|
147
144
|
|
|
148
145
|
# @return [String] Single Logout Service Binding.
|
|
149
146
|
#
|
|
150
147
|
def single_logout_service_binding
|
|
151
|
-
|
|
152
|
-
if @single_logout_service_binding.nil?
|
|
153
|
-
if @assertion_consumer_logout_service_binding
|
|
154
|
-
val = @assertion_consumer_logout_service_binding
|
|
155
|
-
end
|
|
156
|
-
else
|
|
157
|
-
val = @single_logout_service_binding
|
|
158
|
-
end
|
|
159
|
-
val
|
|
148
|
+
@single_logout_service_binding || @assertion_consumer_logout_service_binding
|
|
160
149
|
end
|
|
161
150
|
|
|
162
151
|
# Setter for Single Logout Service Binding.
|
|
163
152
|
#
|
|
164
153
|
# (Currently we only support "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")
|
|
165
|
-
# @param
|
|
154
|
+
# @param value [String, Symbol]
|
|
166
155
|
#
|
|
167
|
-
def single_logout_service_binding=(
|
|
168
|
-
@single_logout_service_binding =
|
|
156
|
+
def single_logout_service_binding=(value)
|
|
157
|
+
@single_logout_service_binding = get_binding(value)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# @deprecated Setter for legacy Single Logout Service Binding parameter.
|
|
161
|
+
#
|
|
162
|
+
# (Currently we only support "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")
|
|
163
|
+
# @param value [String, Symbol]
|
|
164
|
+
#
|
|
165
|
+
def assertion_consumer_logout_service_binding=(value)
|
|
166
|
+
@assertion_consumer_logout_service_binding = get_binding(value)
|
|
169
167
|
end
|
|
170
168
|
|
|
171
169
|
# Calculates the fingerprint of the IdP x509 certificate.
|
|
@@ -184,10 +182,7 @@ module OneLogin
|
|
|
184
182
|
# @return [OpenSSL::X509::Certificate|nil] Build the IdP certificate from the settings (previously format it)
|
|
185
183
|
#
|
|
186
184
|
def get_idp_cert
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
formatted_cert = OneLogin::RubySaml::Utils.format_cert(idp_cert)
|
|
190
|
-
OpenSSL::X509::Certificate.new(formatted_cert)
|
|
185
|
+
OneLogin::RubySaml::Utils.build_cert_object(idp_cert)
|
|
191
186
|
end
|
|
192
187
|
|
|
193
188
|
# @return [Hash with 2 arrays of OpenSSL::X509::Certificate] Build multiple IdP certificates from the settings.
|
|
@@ -195,73 +190,101 @@ module OneLogin
|
|
|
195
190
|
def get_idp_cert_multi
|
|
196
191
|
return nil if idp_cert_multi.nil? || idp_cert_multi.empty?
|
|
197
192
|
|
|
198
|
-
raise ArgumentError.new("Invalid value for idp_cert_multi")
|
|
193
|
+
raise ArgumentError.new("Invalid value for idp_cert_multi") unless idp_cert_multi.is_a?(Hash)
|
|
199
194
|
|
|
200
195
|
certs = {:signing => [], :encryption => [] }
|
|
201
196
|
|
|
202
|
-
|
|
203
|
-
idp_cert_multi[
|
|
204
|
-
|
|
205
|
-
certs[:signing].push(OpenSSL::X509::Certificate.new(formatted_cert))
|
|
206
|
-
end
|
|
207
|
-
end
|
|
197
|
+
[:signing, :encryption].each do |type|
|
|
198
|
+
certs_for_type = idp_cert_multi[type] || idp_cert_multi[type.to_s]
|
|
199
|
+
next if !certs_for_type || certs_for_type.empty?
|
|
208
200
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
formatted_cert = OneLogin::RubySaml::Utils.format_cert(idp_cert)
|
|
212
|
-
certs[:encryption].push(OpenSSL::X509::Certificate.new(formatted_cert))
|
|
201
|
+
certs_for_type.each do |idp_cert|
|
|
202
|
+
certs[type].push(OneLogin::RubySaml::Utils.build_cert_object(idp_cert))
|
|
213
203
|
end
|
|
214
204
|
end
|
|
215
205
|
|
|
216
206
|
certs
|
|
217
207
|
end
|
|
218
208
|
|
|
219
|
-
# @return [OpenSSL::X509::Certificate
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
|
|
209
|
+
# @return [Hash<Symbol, Array<Array<OpenSSL::X509::Certificate, OpenSSL::PKey::RSA>>>]
|
|
210
|
+
# Build the SP certificates and private keys from the settings. If
|
|
211
|
+
# check_sp_cert_expiration is true, only returns certificates and private keys
|
|
212
|
+
# that are not expired.
|
|
213
|
+
def get_sp_certs
|
|
214
|
+
certs = get_all_sp_certs
|
|
215
|
+
return certs unless security[:check_sp_cert_expiration]
|
|
223
216
|
|
|
224
|
-
|
|
225
|
-
|
|
217
|
+
active_certs = { signing: [], encryption: [] }
|
|
218
|
+
certs.each do |use, pairs|
|
|
219
|
+
next if pairs.empty?
|
|
226
220
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
221
|
+
pairs = pairs.select { |cert, _| !cert || OneLogin::RubySaml::Utils.is_cert_active(cert) }
|
|
222
|
+
raise OneLogin::RubySaml::ValidationError.new("The SP certificate expired.") if pairs.empty?
|
|
223
|
+
|
|
224
|
+
active_certs[use] = pairs.freeze
|
|
231
225
|
end
|
|
226
|
+
active_certs.freeze
|
|
227
|
+
end
|
|
232
228
|
|
|
233
|
-
|
|
229
|
+
# @return [Array<OpenSSL::X509::Certificate, OpenSSL::PKey::RSA>]
|
|
230
|
+
# The SP signing certificate and private key.
|
|
231
|
+
def get_sp_signing_pair
|
|
232
|
+
get_sp_certs[:signing].first
|
|
234
233
|
end
|
|
235
234
|
|
|
236
|
-
# @return [OpenSSL::X509::Certificate
|
|
237
|
-
#
|
|
238
|
-
def
|
|
239
|
-
|
|
235
|
+
# @return [OpenSSL::X509::Certificate] The SP signing certificate.
|
|
236
|
+
# @deprecated Use get_sp_signing_pair or get_sp_certs instead.
|
|
237
|
+
def get_sp_cert
|
|
238
|
+
node = get_sp_signing_pair
|
|
239
|
+
node[0] if node
|
|
240
|
+
end
|
|
240
241
|
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
# @return [OpenSSL::PKey::RSA] The SP signing key.
|
|
243
|
+
def get_sp_signing_key
|
|
244
|
+
node = get_sp_signing_pair
|
|
245
|
+
node[1] if node
|
|
243
246
|
end
|
|
244
247
|
|
|
245
|
-
# @
|
|
248
|
+
# @deprecated Use get_sp_signing_key or get_sp_certs instead.
|
|
249
|
+
alias_method :get_sp_key, :get_sp_signing_key
|
|
250
|
+
|
|
251
|
+
# @return [Array<OpenSSL::PKey::RSA>] The SP decryption keys.
|
|
252
|
+
def get_sp_decryption_keys
|
|
253
|
+
ary = get_sp_certs[:encryption].map { |pair| pair[1] }
|
|
254
|
+
ary.compact!
|
|
255
|
+
ary.uniq!(&:to_pem)
|
|
256
|
+
ary.freeze
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# @return [OpenSSL::X509::Certificate|nil] Build the New SP certificate from the settings.
|
|
246
260
|
#
|
|
247
|
-
|
|
248
|
-
|
|
261
|
+
# @deprecated Use get_sp_certs instead
|
|
262
|
+
def get_sp_cert_new
|
|
263
|
+
node = get_sp_certs[:signing].last
|
|
264
|
+
node[0] if node
|
|
265
|
+
end
|
|
249
266
|
|
|
250
|
-
|
|
251
|
-
|
|
267
|
+
def idp_binding_from_embed_sign
|
|
268
|
+
security[:embed_sign] ? Utils::BINDINGS[:post] : Utils::BINDINGS[:redirect]
|
|
252
269
|
end
|
|
253
270
|
|
|
254
|
-
|
|
271
|
+
def get_binding(value)
|
|
272
|
+
return unless value
|
|
273
|
+
|
|
274
|
+
Utils::BINDINGS[value.to_sym] || value
|
|
275
|
+
end
|
|
255
276
|
|
|
256
277
|
DEFAULTS = {
|
|
257
|
-
:assertion_consumer_service_binding =>
|
|
258
|
-
:single_logout_service_binding =>
|
|
278
|
+
:assertion_consumer_service_binding => Utils::BINDINGS[:post],
|
|
279
|
+
:single_logout_service_binding => Utils::BINDINGS[:redirect],
|
|
259
280
|
:idp_cert_fingerprint_algorithm => XMLSecurity::Document::SHA1,
|
|
260
281
|
:compress_request => true,
|
|
261
282
|
:compress_response => true,
|
|
283
|
+
:message_max_bytesize => 250000,
|
|
262
284
|
:soft => true,
|
|
263
|
-
:check_malformed_doc => true,
|
|
285
|
+
:check_malformed_doc => true,
|
|
264
286
|
:double_quote_xml_attribute_values => false,
|
|
287
|
+
|
|
265
288
|
:security => {
|
|
266
289
|
:authn_requests_signed => false,
|
|
267
290
|
:logout_requests_signed => false,
|
|
@@ -270,13 +293,94 @@ module OneLogin
|
|
|
270
293
|
:want_assertions_encrypted => false,
|
|
271
294
|
:want_name_id => false,
|
|
272
295
|
:metadata_signed => false,
|
|
273
|
-
:embed_sign => false,
|
|
296
|
+
:embed_sign => false, # Deprecated
|
|
274
297
|
:digest_method => XMLSecurity::Document::SHA1,
|
|
275
298
|
:signature_method => XMLSecurity::Document::RSA_SHA1,
|
|
276
299
|
:check_idp_cert_expiration => false,
|
|
277
|
-
:check_sp_cert_expiration => false
|
|
300
|
+
:check_sp_cert_expiration => false,
|
|
301
|
+
:strict_audience_validation => false,
|
|
302
|
+
:lowercase_url_encoding => false
|
|
278
303
|
}.freeze
|
|
279
304
|
}.freeze
|
|
305
|
+
|
|
306
|
+
private
|
|
307
|
+
|
|
308
|
+
# @return [Hash<Symbol, Array<Array<OpenSSL::X509::Certificate, OpenSSL::PKey::RSA>>>]
|
|
309
|
+
# Build the SP certificates and private keys from the settings. Returns all
|
|
310
|
+
# certificates and private keys, even if they are expired.
|
|
311
|
+
def get_all_sp_certs
|
|
312
|
+
validate_sp_certs_params!
|
|
313
|
+
get_sp_certs_multi || get_sp_certs_single
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Validate certificate, certificate_new, private_key, and sp_cert_multi params.
|
|
317
|
+
def validate_sp_certs_params!
|
|
318
|
+
multi = sp_cert_multi && !sp_cert_multi.empty?
|
|
319
|
+
cert = certificate && !certificate.empty?
|
|
320
|
+
cert_new = certificate_new && !certificate_new.empty?
|
|
321
|
+
pk = private_key && !private_key.empty?
|
|
322
|
+
if multi && (cert || cert_new || pk)
|
|
323
|
+
raise ArgumentError.new("Cannot specify both sp_cert_multi and certificate, certificate_new, private_key parameters")
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Get certs from certificate, certificate_new, and private_key parameters.
|
|
328
|
+
def get_sp_certs_single
|
|
329
|
+
certs = { :signing => [], :encryption => [] }
|
|
330
|
+
|
|
331
|
+
sp_key = OneLogin::RubySaml::Utils.build_private_key_object(private_key)
|
|
332
|
+
cert = OneLogin::RubySaml::Utils.build_cert_object(certificate)
|
|
333
|
+
if cert || sp_key
|
|
334
|
+
ary = [cert, sp_key].freeze
|
|
335
|
+
certs[:signing] << ary
|
|
336
|
+
certs[:encryption] << ary
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
cert_new = OneLogin::RubySaml::Utils.build_cert_object(certificate_new)
|
|
340
|
+
if cert_new
|
|
341
|
+
ary = [cert_new, sp_key].freeze
|
|
342
|
+
certs[:signing] << ary
|
|
343
|
+
certs[:encryption] << ary
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
certs
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Get certs from get_sp_cert_multi parameter.
|
|
350
|
+
def get_sp_certs_multi
|
|
351
|
+
return if sp_cert_multi.nil? || sp_cert_multi.empty?
|
|
352
|
+
|
|
353
|
+
raise ArgumentError.new("sp_cert_multi must be a Hash") unless sp_cert_multi.is_a?(Hash)
|
|
354
|
+
|
|
355
|
+
certs = { :signing => [], :encryption => [] }.freeze
|
|
356
|
+
|
|
357
|
+
[:signing, :encryption].each do |type|
|
|
358
|
+
certs_for_type = sp_cert_multi[type] || sp_cert_multi[type.to_s]
|
|
359
|
+
next if !certs_for_type || certs_for_type.empty?
|
|
360
|
+
|
|
361
|
+
unless certs_for_type.is_a?(Array) && certs_for_type.all? { |cert| cert.is_a?(Hash) }
|
|
362
|
+
raise ArgumentError.new("sp_cert_multi :#{type} node must be an Array of Hashes")
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
certs_for_type.each do |pair|
|
|
366
|
+
cert = pair[:certificate] || pair['certificate'] || pair[:cert] || pair['cert']
|
|
367
|
+
key = pair[:private_key] || pair['private_key'] || pair[:key] || pair['key']
|
|
368
|
+
|
|
369
|
+
unless cert && key
|
|
370
|
+
raise ArgumentError.new("sp_cert_multi :#{type} node Hashes must specify keys :certificate and :private_key")
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
certs[type] << [
|
|
374
|
+
OneLogin::RubySaml::Utils.build_cert_object(cert),
|
|
375
|
+
OneLogin::RubySaml::Utils.build_private_key_object(key)
|
|
376
|
+
].freeze
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
certs.each { |_, ary| ary.freeze }
|
|
381
|
+
certs
|
|
382
|
+
end
|
|
280
383
|
end
|
|
281
384
|
end
|
|
282
385
|
end
|
|
386
|
+
|