Skip to content

Commit 17925cf

Browse files
committed
Adds settings.idp_sso_service_binding and settings.idp_slo_service_binding, and
+deprecates `settings.security[:embed_sign]`. If specified, new binding parameters will be used in place of `:embed_sign` to determine how to handle SAML message signing (`HTTP-POST` embeds signature and `HTTP-Redirect` does not.) In addition, the `IDPMetadataParser` `parse`, `parse_to_hash` and `parse_to_array` methods now retrieve `idp_sso_service_binding` and `idp_slo_service_binding`. Lastly, for convenience you may now use the Symbol aliases `:post` and `:redirect` for any `settings.*_binding` parameter.
1 parent b55733f commit 17925cf

11 files changed

Lines changed: 258 additions & 113 deletions

README.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.svg)](http://travis-ci.org/onelogin/ruby-saml) [![Coverage Status](https://coveralls.io/repos/onelogin/ruby-saml/badge.svg?branch=master)](https://coveralls.io/r/onelogin/ruby-saml?branch=master)
22

3+
## Updating from 1.12.x to 1.13.0
4+
Version `1.13.0` adds `settings.idp_sso_service_binding` and `settings.idp_slo_service_binding`, and
5+
deprecates `settings.security[:embed_sign]`. If specified, new binding parameters will be used in place of `:embed_sign`
6+
to determine how to handle SAML message signing (`HTTP-POST` embeds signature and `HTTP-Redirect` does not.)
7+
8+
In addition, the `IDPMetadataParser` `parse`, `parse_to_hash` and `parse_to_array` methods now retrieve
9+
`idp_sso_service_binding` and `idp_slo_service_binding`.
10+
11+
Lastly, for convenience you may now use the Symbol aliases `:post` and `:redirect` for any `settings.*_binding` parameter.
12+
313
## Updating from 1.11.x to 1.12.0
414
Version `1.12.0` adds support for gcm algorithm and
515
change/adds specific error messages for signature validations
@@ -277,8 +287,10 @@ def saml_settings
277287
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
278288
settings.sp_entity_id = "http://#{request.host}/saml/metadata"
279289
settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
280-
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
281-
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
290+
settings.idp_sso_service_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
291+
settings.idp_sso_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
292+
settings.idp_slo_service_url = "https://app.onelogin.com/trust/saml2/http-redirect/slo/#{OneLoginAppId}"
293+
settings.idp_slo_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
282294
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
283295
settings.idp_cert_fingerprint_algorithm = "http://www.w3.org/2000/09/xmldsig#sha1"
284296
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -291,9 +303,9 @@ def saml_settings
291303
"urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
292304
]
293305
294-
# Optional bindings (defaults to Redirect for logout POST for acs)
295-
settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
296-
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
306+
# Optional bindings (defaults to Redirect for logout POST for ACS)
307+
settings.single_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" # or :post, :redirect
308+
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" # or :post, :redirect
297309
298310
settings
299311
end
@@ -602,14 +614,12 @@ The settings related to sign are stored in the `security` attribute of the setti
602614
settings.security[:digest_method] = XMLSecurity::Document::SHA1
603615
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
604616
605-
# Embeded signature or HTTP GET parameter signature
606-
# Note that metadata signature is always embedded regardless of this value.
607-
settings.security[:embed_sign] = false
608617
settings.security[:check_idp_cert_expiration] = false # Enable or not IdP x509 cert expiration check
609618
settings.security[:check_sp_cert_expiration] = false # Enable or not SP x509 cert expiration check
610619
```
611620
612-
Notice that the RelayState parameter is used when creating the Signature on the HTTP-Redirect Binding.
621+
Signatures will be handled for both `HTTP-Redirect` and `HTTP-Redirect` Bindings.
622+
Note that the RelayState parameter is used when creating the Signature on the `HTTP-Redirect` Binding.
613623
Remember to provide it to the Signature builder if you are sending a `GET RelayState` parameter or the
614624
signature validation process will fail at the Identity Provider.
615625
@@ -660,7 +670,7 @@ def sp_logout_request
660670
delete_session
661671
else
662672
663-
logout_request = OneLogin::RubySaml::Logoutrequest.new()
673+
logout_request = OneLogin::RubySaml::Logoutrequest.new
664674
logger.info "New SP SLO for userid '#{session[:userid]}' transactionid '#{logout_request.uuid}'"
665675
666676
if settings.name_identifier_value.nil?
@@ -676,7 +686,7 @@ def sp_logout_request
676686
session[:transaction_id] = logout_request.uuid
677687
session[:logged_out_user] = logged_user
678688
679-
relayState = url_for controller: 'saml', action: 'index'
689+
relayState = url_for(controller: 'saml', action: 'index')
680690
redirect_to(logout_request.create(settings, :RelayState => relayState))
681691
end
682692
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,

0 commit comments

Comments
 (0)