Skip to content

Commit f1b6c98

Browse files
authored
Merge pull request #610 from johnnyshields/new-idp-binding-params
New IDP sso/slo binding params which deprecate :embed_sign
2 parents c6489cc + 5b58bae commit f1b6c98

15 files changed

+372
-129
lines changed

README.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
[![Build Status](https://github.com/onelogin/ruby-saml/actions/workflows/test.yml/badge.svg?query=branch%3Amaster)](https://github.com/onelogin/ruby-saml/actions/workflows/test.yml?query=branch%3Amaster)
33
[![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master)](https://coveralls.io/r/onelogin/ruby-saml?branch=master)
44

5-
## Breaking Changes
6-
75
Ruby SAML minor and tiny versions may introduce breaking changes. Please read
86
[UPGRADING.md](UPGRADING.md) for guidance on upgrading to new Ruby SAML versions.
97

@@ -208,8 +206,10 @@ def saml_settings
208206
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
209207
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
210208
settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
211-
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
212-
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
209+
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
210+
settings.idp_sso_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
211+
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
212+
settings.idp_slo_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
213213
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
214214
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
215215
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -222,9 +222,9 @@ def saml_settings
222222
"urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
223223
]
224224
225-
# Optional bindings (defaults to Redirect for logout POST for acs)
226-
settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
227-
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
225+
# Optional bindings (defaults to Redirect for logout POST for ACS)
226+
settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
227+
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
228228
229229
settings
230230
end
@@ -546,14 +546,12 @@ The settings related to sign are stored in the `security` attribute of the setti
546546
settings.security[:digest_method] = XMLSecurity::Document::SHA1
547547
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
548548
549-
# Embeded signature or HTTP GET parameter signature
550-
# Note that metadata signature is always embedded regardless of this value.
551-
settings.security[:embed_sign] = false
552549
settings.security[:check_idp_cert_expiration] = false # Enable or not IdP x509 cert expiration check
553550
settings.security[:check_sp_cert_expiration] = false # Enable or not SP x509 cert expiration check
554551
```
555552
556-
Notice that the RelayState parameter is used when creating the Signature on the HTTP-Redirect Binding.
553+
Signatures will be handled for both `HTTP-Redirect` and `HTTP-Redirect` Bindings.
554+
Note that the RelayState parameter is used when creating the Signature on the `HTTP-Redirect` Binding.
557555
Remember to provide it to the Signature builder if you are sending a `GET RelayState` parameter or the
558556
signature validation process will fail at the Identity Provider.
559557
@@ -604,7 +602,7 @@ def sp_logout_request
604602
delete_session
605603
else
606604
607-
logout_request = OneLogin::RubySaml::Logoutrequest.new()
605+
logout_request = OneLogin::RubySaml::Logoutrequest.new
608606
logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
609607
610608
if settings.name_identifier_value.nil?
@@ -620,7 +618,7 @@ def sp_logout_request
620618
session[:transaction_id] = logout_request.uuid
621619
session[:logged_out_user] = logged_user
622620
623-
relayState = url_for controller: 'saml', action: 'index'
621+
relayState = url_for(controller: 'saml', action: 'index')
624622
redirect_to(logout_request.create(settings, :RelayState => relayState))
625623
end
626624
end

lib/onelogin/ruby-saml/authrequest.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def create_params(settings, params={})
7373
base64_request = encode(request)
7474
request_params = {"SAMLRequest" => base64_request}
7575

76-
if settings.security[:authn_requests_signed] && !settings.security[:embed_sign] && settings.private_key
76+
if settings.idp_sso_service_binding == Utils::BINDINGS[:redirect] && settings.security[:authn_requests_signed] && settings.private_key
7777
params['SigAlg'] = settings.security[:signature_method]
7878
url_string = OneLogin::RubySaml::Utils.build_query(
7979
:type => 'SAMLRequest',
@@ -179,8 +179,7 @@ def create_xml_document(settings)
179179
end
180180

181181
def sign_document(document, settings)
182-
# embed signature
183-
if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
182+
if settings.idp_sso_service_binding == Utils::BINDINGS[:post] && settings.security[:authn_requests_signed] && settings.private_key && settings.certificate
184183
private_key = settings.get_sp_key
185184
cert = settings.get_sp_cert
186185
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])

lib/onelogin/ruby-saml/idp_metadata_parser.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ def to_hash(options = {})
225225
:idp_entity_id => @entity_id,
226226
:name_identifier_format => idp_name_id_format,
227227
:idp_sso_service_url => single_signon_service_url(options),
228+
:idp_sso_service_binding => single_signon_service_binding(options[:sso_binding]),
228229
:idp_slo_service_url => single_logout_service_url(options),
230+
:idp_slo_service_binding => single_logout_service_binding(options[:slo_binding]),
229231
:idp_slo_response_service_url => single_logout_response_service_url(options),
230232
:idp_attribute_names => attribute_names,
231233
:idp_cert => nil,
@@ -275,8 +277,8 @@ def single_signon_service_binding(binding_priority = nil)
275277
if binding_priority
276278
values = nodes.map(&:value)
277279
binding_priority.detect{ |binding| values.include? binding }
278-
else
279-
nodes.first.value if nodes.any?
280+
elsif nodes.any?
281+
nodes.first.value
280282
end
281283
end
282284

@@ -307,8 +309,8 @@ def single_logout_service_binding(binding_priority = nil)
307309
if binding_priority
308310
values = nodes.map(&:value)
309311
binding_priority.detect{ |binding| values.include? binding }
310-
else
311-
nodes.first.value if nodes.any?
312+
elsif nodes.any?
313+
nodes.first.value
312314
end
313315
end
314316

lib/onelogin/ruby-saml/logoutrequest.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ def create_params(settings, params={})
7070
base64_request = encode(request)
7171
request_params = {"SAMLRequest" => base64_request}
7272

73-
if settings.security[:logout_requests_signed] && !settings.security[:embed_sign] && settings.private_key
74-
params['SigAlg'] = settings.security[:signature_method]
73+
if settings.idp_slo_service_binding == Utils::BINDINGS[:redirect] && settings.security[:logout_requests_signed] && settings.private_key
74+
params['SigAlg'] = settings.security[:signature_method]
7575
url_string = OneLogin::RubySaml::Utils.build_query(
7676
:type => 'SAMLRequest',
7777
:data => base64_request,
@@ -138,7 +138,7 @@ def create_xml_document(settings)
138138

139139
def sign_document(document, settings)
140140
# embed signature
141-
if settings.security[:logout_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
141+
if settings.idp_slo_service_binding == Utils::BINDINGS[:post] && settings.security[:logout_requests_signed] && settings.private_key && settings.certificate
142142
private_key = settings.get_sp_key
143143
cert = settings.get_sp_cert
144144
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])

lib/onelogin/ruby-saml/saml_message.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ module RubySaml
1616
class SamlMessage
1717
include REXML
1818

19-
ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
20-
PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
19+
ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion".freeze
20+
PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol".freeze
2121

2222
BASE64_FORMAT = %r(\A([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z)
2323
@@mutex = Mutex.new

lib/onelogin/ruby-saml/settings.rb

Lines changed: 74 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ def initialize(overrides = {}, keep_security_attributes = false)
3131

3232
# IdP Data
3333
attr_accessor :idp_entity_id
34-
35-
attr_accessor :idp_sso_service_url
36-
attr_accessor :idp_slo_service_url
34+
attr_writer :idp_sso_service_url
35+
attr_writer :idp_slo_service_url
3736
attr_accessor :idp_slo_response_service_url
3837
attr_accessor :idp_cert
3938
attr_accessor :idp_cert_fingerprint
@@ -43,8 +42,10 @@ def initialize(overrides = {}, keep_security_attributes = false)
4342
attr_accessor :idp_name_qualifier
4443
attr_accessor :valid_until
4544
# SP Data
45+
attr_writer :sp_entity_id
4646
attr_accessor :assertion_consumer_service_url
47-
attr_accessor :assertion_consumer_service_binding
47+
attr_reader :assertion_consumer_service_binding
48+
attr_writer :single_logout_service_url
4849
attr_accessor :sp_name_qualifier
4950
attr_accessor :name_identifier_format
5051
attr_accessor :name_identifier_value
@@ -54,7 +55,7 @@ def initialize(overrides = {}, keep_security_attributes = false)
5455
attr_accessor :compress_response
5556
attr_accessor :double_quote_xml_attribute_values
5657
attr_accessor :passive
57-
attr_accessor :protocol_binding
58+
attr_reader :protocol_binding
5859
attr_accessor :attributes_index
5960
attr_accessor :force_authn
6061
attr_accessor :certificate
@@ -67,104 +68,99 @@ def initialize(overrides = {}, keep_security_attributes = false)
6768
# Work-flow
6869
attr_accessor :security
6970
attr_accessor :soft
70-
# Compability
71+
# Deprecated
7172
attr_accessor :assertion_consumer_logout_service_url
72-
attr_accessor :assertion_consumer_logout_service_binding
73+
attr_reader :assertion_consumer_logout_service_binding
7374
attr_accessor :issuer
7475
attr_accessor :idp_sso_target_url
7576
attr_accessor :idp_slo_target_url
7677

7778
# @return [String] IdP Single Sign On Service URL
7879
#
7980
def idp_sso_service_url
80-
val = nil
81-
if @idp_sso_service_url.nil?
82-
if @idp_sso_target_url
83-
val = @idp_sso_target_url
84-
end
85-
else
86-
val = @idp_sso_service_url
87-
end
88-
val
81+
@idp_sso_service_url || @idp_sso_target_url
8982
end
9083

9184
# @return [String] IdP Single Logout Service URL
9285
#
9386
def idp_slo_service_url
94-
val = nil
95-
if @idp_slo_service_url.nil?
96-
if @idp_slo_target_url
97-
val = @idp_slo_target_url
98-
end
99-
else
100-
val = @idp_slo_service_url
101-
end
102-
val
87+
@idp_slo_service_url || @idp_slo_target_url
88+
end
89+
90+
# @return [String] IdP Single Sign On Service Binding
91+
#
92+
def idp_sso_service_binding
93+
@idp_sso_service_binding || idp_binding_from_embed_sign
94+
end
95+
96+
# Setter for IdP Single Sign On Service Binding
97+
# @param value [String, Symbol].
98+
#
99+
def idp_sso_service_binding=(value)
100+
@idp_sso_service_binding = get_binding(value)
101+
end
102+
103+
# @return [String] IdP Single Logout Service Binding
104+
#
105+
def idp_slo_service_binding
106+
@idp_slo_service_binding || idp_binding_from_embed_sign
107+
end
108+
109+
# Setter for IdP Single Logout Service Binding
110+
# @param value [String, Symbol].
111+
#
112+
def idp_slo_service_binding=(value)
113+
@idp_slo_service_binding = get_binding(value)
103114
end
104115

105116
# @return [String] SP Entity ID
106117
#
107118
def sp_entity_id
108-
val = nil
109-
if @sp_entity_id.nil?
110-
if @issuer
111-
val = @issuer
112-
end
113-
else
114-
val = @sp_entity_id
115-
end
116-
val
119+
@sp_entity_id || @issuer
117120
end
118121

119-
# Setter for SP Entity ID.
120-
# @param val [String].
122+
# Setter for SP Protocol Binding
123+
# @param value [String, Symbol].
121124
#
122-
def sp_entity_id=(val)
123-
@sp_entity_id = val
125+
def protocol_binding=(value)
126+
@protocol_binding = get_binding(value)
124127
end
125128

126-
# @return [String] Single Logout Service URL.
129+
# Setter for SP Assertion Consumer Service Binding
130+
# @param value [String, Symbol].
127131
#
128-
def single_logout_service_url
129-
val = nil
130-
if @single_logout_service_url.nil?
131-
if @assertion_consumer_logout_service_url
132-
val = @assertion_consumer_logout_service_url
133-
end
134-
else
135-
val = @single_logout_service_url
136-
end
137-
val
132+
def assertion_consumer_service_binding=(value)
133+
@assertion_consumer_service_binding = get_binding(value)
138134
end
139135

140-
# Setter for the Single Logout Service URL.
141-
# @param url [String].
136+
# @return [String] Single Logout Service URL.
142137
#
143-
def single_logout_service_url=(url)
144-
@single_logout_service_url = url
138+
def single_logout_service_url
139+
@single_logout_service_url || @assertion_consumer_logout_service_url
145140
end
146141

147142
# @return [String] Single Logout Service Binding.
148143
#
149144
def single_logout_service_binding
150-
val = nil
151-
if @single_logout_service_binding.nil?
152-
if @assertion_consumer_logout_service_binding
153-
val = @assertion_consumer_logout_service_binding
154-
end
155-
else
156-
val = @single_logout_service_binding
157-
end
158-
val
145+
@single_logout_service_binding || @assertion_consumer_logout_service_binding
159146
end
160147

161148
# Setter for Single Logout Service Binding.
162149
#
163150
# (Currently we only support "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")
164-
# @param url [String]
151+
# @param value [String, Symbol]
165152
#
166-
def single_logout_service_binding=(url)
167-
@single_logout_service_binding = url
153+
def single_logout_service_binding=(value)
154+
@single_logout_service_binding = get_binding(value)
155+
end
156+
157+
# @deprecated Setter for legacy Single Logout Service Binding parameter.
158+
#
159+
# (Currently we only support "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")
160+
# @param value [String, Symbol]
161+
#
162+
def assertion_consumer_logout_service_binding=(value)
163+
@assertion_consumer_logout_service_binding = get_binding(value)
168164
end
169165

170166
# Calculates the fingerprint of the IdP x509 certificate.
@@ -252,9 +248,19 @@ def get_sp_key
252248

253249
private
254250

251+
def idp_binding_from_embed_sign
252+
security[:embed_sign] ? Utils::BINDINGS[:post] : Utils::BINDINGS[:redirect]
253+
end
254+
255+
def get_binding(value)
256+
return unless value
257+
258+
Utils::BINDINGS[value.to_sym] || value
259+
end
260+
255261
DEFAULTS = {
256-
:assertion_consumer_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST".freeze,
257-
:single_logout_service_binding => "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect".freeze,
262+
:assertion_consumer_service_binding => Utils::BINDINGS[:post],
263+
:single_logout_service_binding => Utils::BINDINGS[:redirect],
258264
:idp_cert_fingerprint_algorithm => XMLSecurity::Document::SHA1,
259265
:compress_request => true,
260266
:compress_response => true,
@@ -268,7 +274,7 @@ def get_sp_key
268274
:want_assertions_encrypted => false,
269275
:want_name_id => false,
270276
:metadata_signed => false,
271-
:embed_sign => false,
277+
:embed_sign => false, # Deprecated
272278
:digest_method => XMLSecurity::Document::SHA1,
273279
:signature_method => XMLSecurity::Document::RSA_SHA1,
274280
:check_idp_cert_expiration => false,

lib/onelogin/ruby-saml/slo_logoutresponse.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def create_params(settings, request_id = nil, logout_message = nil, params = {},
7979
base64_response = encode(response)
8080
response_params = {"SAMLResponse" => base64_response}
8181

82-
if settings.security[:logout_responses_signed] && !settings.security[:embed_sign] && settings.private_key
82+
if settings.idp_slo_service_binding == Utils::BINDINGS[:redirect] && settings.security[:logout_responses_signed] && settings.private_key
8383
params['SigAlg'] = settings.security[:signature_method]
8484
url_string = OneLogin::RubySaml::Utils.build_query(
8585
:type => 'SAMLResponse',
@@ -150,7 +150,7 @@ def create_xml_document(settings, request_id = nil, logout_message = nil, status
150150

151151
def sign_document(document, settings)
152152
# embed signature
153-
if settings.security[:logout_responses_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
153+
if settings.idp_slo_service_binding == Utils::BINDINGS[:post] && settings.private_key && settings.certificate
154154
private_key = settings.get_sp_key
155155
cert = settings.get_sp_cert
156156
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])

0 commit comments

Comments
 (0)