Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decrypt support. #241

Merged
merged 9 commits into from
Jun 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,30 @@ Once you've redirected back to the identity provider, it will ensure that the us

```ruby
def consume
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
response.settings = saml_settings
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], :settings => saml_settings)

# We validate the SAML Response and check if the user already exists in the system
if response.is_valid?
# authorize_success, log the user
session[:userid] = response.name_id
session[:userid] = response.nameid
session[:attributes] = response.attributes
else
authorize_failure # This method shows an error message
end
end
```

In the above there are a few assumptions in place, one being that the response.name_id is an email address. This is all handled with how you specify the settings that are in play via the saml_settings method. That could be implemented along the lines of this:
In the above there are a few assumptions in place, one being that the response.nameid is an email address. This is all handled with how you specify the settings that are in play via the saml_settings method. That could be implemented along the lines of this:

If the assertion of the SAMLResponse is not encrypted, you can initialize the Response without the :settings parameter and set it later,

```
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
response.settings = saml_settings
```
but if the SAMLResponse contains an encrypted assertion, you need to provide the settings in the
initialize method in order to be able to obtain the decrypted assertion, using the service provider private key in order to decrypt.
If you don't know what expect, use always the first proposed way (always set the settings on the initialize method).

```ruby
def saml_settings
Expand Down Expand Up @@ -147,7 +156,7 @@ class SamlController < ApplicationController
# We validate the SAML Response and check if the user already exists in the system
if response.is_valid?
# authorize_success, log the user
session[:userid] = response.name_id
session[:userid] = response.nameid
session[:attributes] = response.attributes
else
authorize_failure # This method shows an error message
Expand Down Expand Up @@ -330,8 +339,8 @@ The Ruby Toolkit supports 2 different kinds of signature: Embeded and as GET par
In order to be able to sign we need first to define the private key and the public cert of the service provider

```ruby
settings.certificate = "CERTIFICATE TEXT WITH HEADS"
settings.private_key = "PRIVATE KEY TEXT WITH HEADS"
settings.certificate = "CERTIFICATE TEXT WITH HEAD AND FOOT"
settings.private_key = "PRIVATE KEY TEXT WITH HEAD AND FOOT"
```

The settings related to sign are stored in the `security` attribute of the settings:
Expand All @@ -354,6 +363,28 @@ Notice that the RelayState parameter is used when creating the Signature on the
remember to provide it to the Signature builder if you are sending a GET RelayState parameter or
Signature validation process will fail at the Identity Provider.

The Service Provider will sign the request/responses with its private key.
The Identity Provider will validate the sign of the received request/responses with the public x500 cert of the
Service Provider.

Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and the decrypt process.


## Decrypting

The Ruby Toolkit supports EncryptedAssertion.

In order to be able to decrypt a SAML Response that contains a EncryptedAssertion we need first to define the private key and the public cert of the service provider, and share this with the Identity Provider.

```ruby
settings.certificate = "CERTIFICATE TEXT WITH HEAD AND FOOT"
settings.private_key = "PRIVATE KEY TEXT WITH HEAD AND FOOT"
```

The Identity Provider will encrypt the Assertion with the public cert of the Service Provider.
The Service Provider will decrypt the EncryptedAssertion with its private key.

Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and the decrypt process.

## Single Log Out

Expand Down
12 changes: 6 additions & 6 deletions lib/onelogin/ruby-saml/logoutrequest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,15 @@ def create_logout_request_xml_doc(settings)
issuer.text = settings.issuer
end

name_id = root.add_element "saml:NameID"
nameid = root.add_element "saml:NameID"
if settings.name_identifier_value
name_id.attributes['NameQualifier'] = settings.sp_name_qualifier if settings.sp_name_qualifier
name_id.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
name_id.text = settings.name_identifier_value
nameid.attributes['NameQualifier'] = settings.sp_name_qualifier if settings.sp_name_qualifier
nameid.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
nameid.text = settings.name_identifier_value
else
# If no NameID is present in the settings we generate one
name_id.text = "_" + UUID.new.generate
name_id.attributes['Format'] = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
nameid.text = "_" + UUID.new.generate
nameid.attributes['Format'] = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
end

if settings.sessionindex
Expand Down
15 changes: 11 additions & 4 deletions lib/onelogin/ruby-saml/metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ def generate(settings, pretty_print=false)
}
end
if settings.name_identifier_format
name_id = sp_sso.add_element "md:NameIDFormat"
name_id.text = settings.name_identifier_format
nameid = sp_sso.add_element "md:NameIDFormat"
nameid.text = settings.name_identifier_format
end
if settings.assertion_consumer_service_url
sp_sso.add_element "md:AssertionConsumerService", {
Expand All @@ -54,14 +54,21 @@ def generate(settings, pretty_print=false)
}
end

# Add KeyDescriptor if messages will be signed
# Add KeyDescriptor if messages will be signed / encrypted
cert = settings.get_sp_cert
if cert
cert_text = Base64.encode64(cert.to_der).gsub("\n", '')
kd = sp_sso.add_element "md:KeyDescriptor", { "use" => "signing" }
ki = kd.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
xd = ki.add_element "ds:X509Data"
xc = xd.add_element "ds:X509Certificate"
xc.text = Base64.encode64(cert.to_der).gsub("\n", '')
xc.text = cert_text

kd2 = sp_sso.add_element "md:KeyDescriptor", { "use" => "encryption" }
ki2 = kd2.add_element "ds:KeyInfo", {"xmlns:ds" => "http://www.w3.org/2000/09/xmldsig#"}
xd2 = ki2.add_element "ds:X509Data"
xc2 = xd2.add_element "ds:X509Certificate"
xc2.text = cert_text
end

if settings.attribute_consuming_service.configured?
Expand Down
Loading