Skip to content
This repository was archived by the owner on Mar 12, 2026. It is now read-only.

Commit 9d419b8

Browse files
committed
merge v1.0.0
2 parents 3c2336d + 05c82d9 commit 9d419b8

98 files changed

Lines changed: 4226 additions & 941 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ coverage
44
rdoc
55
pkg
66
Gemfile.lock
7+
gemfiles/*.lock
78
.idea/*
89
lib/Lib.iml
910
test/Test.iml

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2010 OneLogin, LLC
1+
Copyright (c) 2010-2015 OneLogin, LLC
22

33
Permission is hereby granted, free of charge, to any person obtaining a copy
44
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
# Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.png)](http://travis-ci.org/onelogin/ruby-saml)
22

3+
4+
## Updating from 0.9.x to 1.0.X
5+
6+
Version `1.0` is a recommended update for all Ruby SAML users as it includes security fixes.
7+
8+
Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decrypt support.
9+
10+
For more details, please review [the changelog](changelog.md).
11+
12+
### Important Changes
13+
Please note the `get_idp_metadata` method raises an exception when it is not able to fetch the idp metadata, so review your integration if you are using this functionality.
14+
315
## Updating from 0.8.x to 0.9.x
4-
Version `0.9` adds many new features and improvements. It is a recommended update for all Ruby SAML users. For more details, please review [the changelog](changelog.md)
16+
Version `0.9` adds many new features and improvements.
517

618
## Updating from 0.7.x to 0.8.x
719
Version `0.8.x` changes the namespace of the gem from `OneLogin::Saml` to `OneLogin::RubySaml`. Please update your implementations of the gem accordingly.
@@ -18,7 +30,7 @@ We created a demo project for Rails4 that uses the latest version of this librar
1830
* 1.8.7
1931
* 1.9.x
2032
* 2.1.x
21-
* 2.2.0
33+
* 2.2.x
2234

2335
## Adding Features, Pull Requests
2436
* Fork the repository
@@ -35,7 +47,7 @@ Using `Gemfile`
3547

3648
```ruby
3749
# latest stable
38-
gem 'ruby-saml', '~> 0.9.1'
50+
gem 'ruby-saml', '~> 1.0.0'
3951

4052
# or track master for bleeding-edge
4153
gem 'ruby-saml', :github => 'onelogin/ruby-saml'
@@ -74,6 +86,19 @@ Using RubyGems
7486
gem install nokogiri --version '~> 1.5.10'
7587
````
7688

89+
### Configuring Logging
90+
91+
When troubleshooting SAML integration issues, you will find it extremely helpful to examine the
92+
output of this gem's business logic. By default, log messages are emitted to RAILS_DEFAULT_LOGGER
93+
when the gem is used in a Rails context, and to STDOUT when the gem is used outside of Rails.
94+
95+
To override the default behavior and control the destination of log messages, provide
96+
a ruby Logger object to the gem's logging singleton:
97+
98+
```ruby
99+
OneLogin::RubySaml::Logging.logger = Logger.new(File.open('/var/log/ruby-saml.log', 'w')
100+
```
101+
77102
## The Initialization Phase
78103
79104
This is the first request you will get from the identity provider. It will hit your application at a specific URL (that you've announced as being your SAML initialization point). The response to this initialization, is a redirect back to the identity provider, which can look something like this (ignore the saml_settings method call for now):
@@ -89,28 +114,37 @@ Once you've redirected back to the identity provider, it will ensure that the us
89114
90115
```ruby
91116
def consume
92-
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
93-
response.settings = saml_settings
117+
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], :settings => saml_settings)
94118
95119
# We validate the SAML Response and check if the user already exists in the system
96120
if response.is_valid?
97121
# authorize_success, log the user
98-
session[:userid] = response.name_id
122+
session[:userid] = response.nameid
99123
session[:attributes] = response.attributes
100124
else
101125
authorize_failure # This method shows an error message
102126
end
103127
end
104128
```
105129
106-
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:
130+
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:
131+
132+
If the assertion of the SAMLResponse is not encrypted, you can initialize the Response without the :settings parameter and set it later,
133+
134+
```
135+
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
136+
response.settings = saml_settings
137+
```
138+
but if the SAMLResponse contains an encrypted assertion, you need to provide the settings in the
139+
initialize method in order to be able to obtain the decrypted assertion, using the service provider private key in order to decrypt.
140+
If you don't know what expect, use always the first proposed way (always set the settings on the initialize method).
107141
108142
```ruby
109143
def saml_settings
110144
settings = OneLogin::RubySaml::Settings.new
111145
112-
settings.assertion_consumer_service_url = "http://#{request.host}/saml/finalize"
113-
settings.issuer = request.host
146+
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
147+
settings.issuer = "http://#{request.host}/saml/metadata"
114148
settings.idp_sso_target_url = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
115149
settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
116150
settings.idp_sso_target_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
@@ -124,7 +158,7 @@ def saml_settings
124158
125159
# Optional bindings (defaults to Redirect for logout POST for acs)
126160
settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
127-
settings.single_logout_service_url_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
161+
settings.assertion_consumer_logout_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
128162
129163
settings
130164
end
@@ -147,7 +181,7 @@ class SamlController < ApplicationController
147181
# We validate the SAML Response and check if the user already exists in the system
148182
if response.is_valid?
149183
# authorize_success, log the user
150-
session[:userid] = response.name_id
184+
session[:userid] = response.nameid
151185
session[:attributes] = response.attributes
152186
else
153187
authorize_failure # This method shows an error message
@@ -160,7 +194,7 @@ class SamlController < ApplicationController
160194
settings = OneLogin::RubySaml::Settings.new
161195
162196
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
163-
settings.issuer = request.host
197+
settings.issuer = "http://#{request.host}/saml/metadata"
164198
settings.idp_sso_target_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
165199
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
166200
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -196,7 +230,7 @@ def saml_settings
196230
settings = idp_metadata_parser.parse_remote("https://example.com/auth/saml2/idp/metadata")
197231
198232
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
199-
settings.issuer = request.host
233+
settings.issuer = "http://#{request.host}/saml/metadata"
200234
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
201235
# Optional for most SAML IdPs
202236
settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
@@ -330,8 +364,8 @@ The Ruby Toolkit supports 2 different kinds of signature: Embeded and as GET par
330364
In order to be able to sign we need first to define the private key and the public cert of the service provider
331365
332366
```ruby
333-
settings.certificate = "CERTIFICATE TEXT WITH HEADS"
334-
settings.private_key = "PRIVATE KEY TEXT WITH HEADS"
367+
settings.certificate = "CERTIFICATE TEXT WITH HEAD AND FOOT"
368+
settings.private_key = "PRIVATE KEY TEXT WITH HEAD AND FOOT"
335369
```
336370
337371
The settings related to sign are stored in the `security` attribute of the settings:
@@ -354,6 +388,28 @@ Notice that the RelayState parameter is used when creating the Signature on the
354388
remember to provide it to the Signature builder if you are sending a GET RelayState parameter or
355389
Signature validation process will fail at the Identity Provider.
356390
391+
The Service Provider will sign the request/responses with its private key.
392+
The Identity Provider will validate the sign of the received request/responses with the public x500 cert of the
393+
Service Provider.
394+
395+
Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and the decrypt process.
396+
397+
398+
## Decrypting
399+
400+
The Ruby Toolkit supports EncryptedAssertion.
401+
402+
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.
403+
404+
```ruby
405+
settings.certificate = "CERTIFICATE TEXT WITH HEAD AND FOOT"
406+
settings.private_key = "PRIVATE KEY TEXT WITH HEAD AND FOOT"
407+
```
408+
409+
The Identity Provider will encrypt the Assertion with the public cert of the Service Provider.
410+
The Service Provider will decrypt the EncryptedAssertion with its private key.
411+
412+
Notice that this toolkit uses 'settings.certificate' and 'settings.private_key' for the sign and the decrypt process.
357413
358414
## Single Log Out
359415

changelog.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
11
# RubySaml Changelog
2+
3+
### 1.0.0 (June 30, 2015)
4+
* [#247](https://github.com/onelogin/ruby-saml/pull/247) Avoid entity expansion (XEE attacks)
5+
* [#246](https://github.com/onelogin/ruby-saml/pull/246) Fix bug generating Logout Response (issuer was at wrong order)
6+
* [#243](https://github.com/onelogin/ruby-saml/issues/243) and [#244](https://github.com/onelogin/ruby-saml/issues/244) Fix metadata builder errors. Fix metadata xsd.
7+
* [#241](https://github.com/onelogin/ruby-saml/pull/241) Add decrypt support (EncryptID and EncryptedAssertion). Improve compatibility with namespaces.
8+
* [#240](https://github.com/onelogin/ruby-saml/pull/240) and [#238](https://github.com/onelogin/ruby-saml/pull/238) Improve test coverage and refactor.
9+
* [#239](https://github.com/onelogin/ruby-saml/pull/239) Improve security: Add more validations to SAMLResponse, LogoutRequest and LogoutResponse. Refactor code and improve tests coverage.
10+
* [#237](https://github.com/onelogin/ruby-saml/pull/237) Don't pretty print metadata by default.
11+
* [#235](https://github.com/onelogin/ruby-saml/pull/235) Remove the soft parameter from validation methods. Now can be configured on the settings and each class read it and store as an attribute of the class. Adding some validations and refactor old ones.
12+
* [#232](https://github.com/onelogin/ruby-saml/pull/232) Improve validations: Store the causes in the errors array, code refactor
13+
* [#231](https://github.com/onelogin/ruby-saml/pull/231) Refactor HTTP-Redirect Sign method, Move test data to right folder
14+
* [#226](https://github.com/onelogin/ruby-saml/pull/226) Ensure IdP certificate is formatted properly
15+
* [#225](https://github.com/onelogin/ruby-saml/pull/225) Add documentation to several methods. Fix xpath injection on xml_security.rb
16+
* [#223](https://github.com/onelogin/ruby-saml/pull/223) Allow logging to be delegated to an arbitrary Logger
17+
* [#222](https://github.com/onelogin/ruby-saml/pull/222) No more silent failure fetching idp metadata (OneLogin::RubySaml::HttpError raised).
18+
219
### 0.9.2 (Apr 28, 2015)
320
* [#216](https://github.com/onelogin/ruby-saml/pull/216) Add fingerprint algorithm support
421
* [#218](https://github.com/onelogin/ruby-saml/pull/218) Update README.md
@@ -15,7 +32,6 @@
1532
* [#179](https://github.com/onelogin/ruby-saml/pull/179) Add support for setting the entity ID and name ID format when parsing metadata
1633
* [#175](https://github.com/onelogin/ruby-saml/pull/175) Introduce thread safety to SAML schema validation
1734
* [#171](https://github.com/onelogin/ruby-saml/pull/171) Fix inconsistent results with using regex matches in decode_raw_saml
18-
*
1935

2036
### 0.9.1 (Feb 10, 2015)
2137
* [#194](https://github.com/onelogin/ruby-saml/pull/194) Relax nokogiri gem requirements

lib/onelogin/ruby-saml.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
require 'onelogin/ruby-saml/response'
1010
require 'onelogin/ruby-saml/settings'
1111
require 'onelogin/ruby-saml/attribute_service'
12+
require 'onelogin/ruby-saml/http_error'
1213
require 'onelogin/ruby-saml/validation_error'
1314
require 'onelogin/ruby-saml/metadata'
1415
require 'onelogin/ruby-saml/idp_metadata_parser'

lib/onelogin/ruby-saml/attribute_service.rb

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
module OneLogin
22
module RubySaml
3+
4+
# SAML2 AttributeService. Auxiliary class to build the AttributeService of the SP Metadata
5+
#
36
class AttributeService
47
attr_reader :attributes
58
attr_reader :name
69
attr_reader :index
710

11+
# Initializes the AttributeService, set the index value as 1 and an empty array as attributes
12+
#
813
def initialize
914
@index = "1"
1015
@attributes = []
@@ -14,20 +19,38 @@ def configure(&block)
1419
instance_eval &block
1520
end
1621

22+
# @return [Boolean] True if the AttributeService object has been initialized and set with the required values
23+
# (has attributes and a name)
1724
def configured?
1825
@attributes.length > 0 && !@name.nil?
1926
end
2027

28+
# Set a name to the service
29+
# @param name [String] The service name
30+
#
2131
def service_name(name)
2232
@name = name
2333
end
2434

35+
# Set an index to the service
36+
# @param index [Integer] An index
37+
#
2538
def service_index(index)
2639
@index = index
2740
end
28-
41+
42+
# Add an AttributeService
43+
# @param options [Hash] AttributeService option values
44+
# add_attribute(
45+
# :name => "Name",
46+
# :name_format => "Name Format",
47+
# :index => 1,
48+
# :friendly_name => "Friendly Name",
49+
# :attribute_value => "Attribute Value"
50+
# )
51+
#
2952
def add_attribute(options={})
30-
attributes << options
53+
attributes << options
3154
end
3255
end
3356
end

0 commit comments

Comments
 (0)