ruby-saml 0.9.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-saml might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/LICENSE +1 -1
  4. data/README.md +71 -15
  5. data/changelog.md +15 -6
  6. data/lib/onelogin/ruby-saml.rb +1 -0
  7. data/lib/onelogin/ruby-saml/attribute_service.rb +25 -2
  8. data/lib/onelogin/ruby-saml/attributes.rb +42 -23
  9. data/lib/onelogin/ruby-saml/authrequest.rb +33 -8
  10. data/lib/onelogin/ruby-saml/http_error.rb +7 -0
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +65 -10
  12. data/lib/onelogin/ruby-saml/logging.rb +14 -10
  13. data/lib/onelogin/ruby-saml/logoutrequest.rb +39 -14
  14. data/lib/onelogin/ruby-saml/logoutresponse.rb +166 -39
  15. data/lib/onelogin/ruby-saml/metadata.rb +40 -23
  16. data/lib/onelogin/ruby-saml/response.rb +562 -88
  17. data/lib/onelogin/ruby-saml/saml_message.rb +80 -14
  18. data/lib/onelogin/ruby-saml/settings.rb +62 -23
  19. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +210 -20
  20. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +44 -13
  21. data/lib/onelogin/ruby-saml/utils.rb +163 -40
  22. data/lib/onelogin/ruby-saml/version.rb +1 -1
  23. data/lib/schemas/saml-schema-metadata-2.0.xsd +0 -2
  24. data/lib/xml_security.rb +87 -29
  25. data/ruby-saml.gemspec +1 -0
  26. data/test/certificates/{r1_certificate2_base64 → certificate_without_head_foot} +0 -0
  27. data/test/certificates/formatted_certificate +14 -0
  28. data/test/certificates/formatted_private_key +12 -0
  29. data/test/certificates/formatted_rsa_private_key +12 -0
  30. data/test/certificates/invalid_certificate1 +1 -0
  31. data/test/certificates/invalid_certificate2 +1 -0
  32. data/test/certificates/invalid_certificate3 +12 -0
  33. data/test/certificates/invalid_private_key1 +1 -0
  34. data/test/certificates/invalid_private_key2 +1 -0
  35. data/test/certificates/invalid_private_key3 +10 -0
  36. data/test/certificates/invalid_rsa_private_key1 +1 -0
  37. data/test/certificates/invalid_rsa_private_key2 +1 -0
  38. data/test/certificates/invalid_rsa_private_key3 +10 -0
  39. data/test/idp_metadata_parser_test.rb +41 -4
  40. data/test/logging_test.rb +62 -0
  41. data/test/logout_requests/invalid_slo_request.xml +6 -0
  42. data/test/{responses → logout_requests}/slo_request.xml +0 -0
  43. data/test/logout_requests/slo_request.xml.base64 +1 -0
  44. data/test/logout_requests/slo_request_deflated.xml.base64 +1 -0
  45. data/test/logout_requests/slo_request_with_session_index.xml +5 -0
  46. data/test/{responses → logout_responses}/logoutresponse_fixtures.rb +6 -6
  47. data/test/logoutrequest_test.rb +79 -52
  48. data/test/logoutresponse_test.rb +206 -59
  49. data/test/metadata_test.rb +77 -7
  50. data/test/request_test.rb +80 -65
  51. data/test/response_test.rb +862 -189
  52. data/test/responses/attackxee.xml +13 -0
  53. data/test/responses/invalids/invalid_audience.xml.base64 +1 -0
  54. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +1 -0
  55. data/test/responses/invalids/invalid_issuer_message.xml.base64 +1 -0
  56. data/test/responses/invalids/invalid_signature_position.xml.base64 +1 -0
  57. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +1 -0
  58. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +1 -0
  59. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +1 -0
  60. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +1 -0
  61. data/test/responses/invalids/multiple_assertions.xml.base64 +2 -0
  62. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  63. data/test/responses/invalids/no_id.xml.base64 +1 -0
  64. data/test/responses/invalids/no_saml2.xml.base64 +1 -0
  65. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  66. data/test/responses/invalids/no_status.xml.base64 +1 -0
  67. data/test/responses/invalids/no_status_code.xml.base64 +1 -0
  68. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +1 -0
  69. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +1 -0
  70. data/test/responses/invalids/response_encrypted_attrs.xml.base64 +1 -0
  71. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +1 -0
  72. data/test/responses/invalids/status_code_responder.xml.base64 +1 -0
  73. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +1 -0
  74. data/test/responses/{response4.xml.base64 → response_assertion_wrapped.xml.base64} +0 -0
  75. data/test/responses/response_encrypted_nameid.xml.base64 +1 -0
  76. data/test/responses/response_unsigned_xml_base64 +1 -0
  77. data/test/responses/{response5.xml.base64 → response_with_saml2_namespace.xml.base64} +0 -0
  78. data/test/responses/{response3.xml.base64 → response_with_signed_assertion.xml.base64} +0 -0
  79. data/test/responses/{r1_response6.xml.base64 → response_with_signed_assertion_2.xml.base64} +0 -0
  80. data/test/responses/{response1.xml.base64 → response_with_undefined_recipient.xml.base64} +0 -0
  81. data/test/responses/{response2.xml.base64 → response_without_attributes.xml.base64} +0 -0
  82. data/test/responses/{wrapped_response_2.xml.base64 → response_wrapped.xml.base64} +0 -0
  83. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +1 -0
  84. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +1 -0
  85. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +1 -0
  86. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +1 -0
  87. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +1 -0
  88. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +1 -0
  89. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +1 -0
  90. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +1 -0
  91. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +1 -0
  92. data/test/responses/valid_response.xml.base64 +1 -0
  93. data/test/saml_message_test.rb +56 -0
  94. data/test/settings_test.rb +138 -1
  95. data/test/slo_logoutrequest_test.rb +239 -28
  96. data/test/slo_logoutresponse_test.rb +93 -71
  97. data/test/test_helper.rb +138 -31
  98. data/test/utils_test.rb +129 -25
  99. data/test/xml_security_test.rb +140 -71
  100. metadata +142 -25
  101. data/test/responses/response_node_text_attack.xml.base64 +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e6899da69ca7253760c8766c25579be80e078459
4
- data.tar.gz: a38aa8ac9f56af0ecc11d2a41143570f3ba2c55f
3
+ metadata.gz: 381e8f35422cfa0bbb991272a777f7fdfcdd2081
4
+ data.tar.gz: 0371c2cbd05ee2b482fca1feda05a82162550295
5
5
  SHA512:
6
- metadata.gz: 9bbe6c965d9d01e30e48e7378d98bfe0daae344f83e3a63349a51df674c9e59bf9f4d1304c01a3e040f1c1aabeb87040d2e1ee9a6866a7161c58fef251ecafcc
7
- data.tar.gz: ee92e4423bedfb8889b56cb763754cdafd24e4f5ec42cd36e904169af827c14422412f0a5537899abab47a1a210bb9f960439b988f30ff343a1853954a85bafc
6
+ metadata.gz: a3553e3802bba3fe72375cf5865dfce58a5bf46efa335a43e49f020ee12691bd099ecc3496be389a2556808ad4428bd79d4c4a51171c582df8ac74d66187e2a0
7
+ data.tar.gz: 473180d499b2ffd2648438ce2c4fd103a8b314ccfa18145cb72215edeecc0864f53dbf016ccd66f6025cdb45aca241df14ca3e9f7ec36731ba4a4004ef0b3a6f
data/.gitignore CHANGED
@@ -4,6 +4,7 @@ coverage
4
4
  rdoc
5
5
  pkg
6
6
  Gemfile.lock
7
+ gemfiles/*.lock
7
8
  .idea/*
8
9
  lib/Lib.iml
9
10
  test/Test.iml
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 OneLogin, LLC
1
+ Copyright (c) 2010-2015 OneLogin, LLC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,7 +1,19 @@
1
1
  # Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.png)](http://travis-ci.org/onelogin/ruby-saml)
2
2
 
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
+
3
15
  ## 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.
5
17
 
6
18
  ## Updating from 0.7.x to 0.8.x
7
19
  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
18
30
  * 1.8.7
19
31
  * 1.9.x
20
32
  * 2.1.x
21
- * 2.2.0
33
+ * 2.2.x
22
34
 
23
35
  ## Adding Features, Pull Requests
24
36
  * Fork the repository
@@ -35,7 +47,7 @@ Using `Gemfile`
35
47
 
36
48
  ```ruby
37
49
  # latest stable
38
- gem 'ruby-saml', '~> 0.9.1'
50
+ gem 'ruby-saml', '~> 1.0.0'
39
51
 
40
52
  # or track master for bleeding-edge
41
53
  gem 'ruby-saml', :github => 'onelogin/ruby-saml'
@@ -74,6 +86,19 @@ Using RubyGems
74
86
  gem install nokogiri --version '~> 1.5.10'
75
87
  ````
76
88
 
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
+
77
102
  ## The Initialization Phase
78
103
 
79
104
  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,13 +114,12 @@ Once you've redirected back to the identity provider, it will ensure that the us
89
114
 
90
115
  ```ruby
91
116
  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)
94
118
 
95
119
  # We validate the SAML Response and check if the user already exists in the system
96
120
  if response.is_valid?
97
121
  # authorize_success, log the user
98
- session[:userid] = response.name_id
122
+ session[:userid] = response.nameid
99
123
  session[:attributes] = response.attributes
100
124
  else
101
125
  authorize_failure # This method shows an error message
@@ -103,14 +127,24 @@ def consume
103
127
  end
104
128
  ```
105
129
 
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).
107
141
 
108
142
  ```ruby
109
143
  def saml_settings
110
144
  settings = OneLogin::RubySaml::Settings.new
111
145
 
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"
114
148
  settings.idp_sso_target_url = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
115
149
  settings.idp_entity_id = "https://app.onelogin.com/saml/metadata/#{OneLoginAppId}"
116
150
  settings.idp_sso_target_url = "https://app.onelogin.com/trust/saml2/http-post/sso/#{OneLoginAppId}"
@@ -124,7 +158,7 @@ def saml_settings
124
158
 
125
159
  # Optional bindings (defaults to Redirect for logout POST for acs)
126
160
  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"
128
162
 
129
163
  settings
130
164
  end
@@ -147,7 +181,7 @@ class SamlController < ApplicationController
147
181
  # We validate the SAML Response and check if the user already exists in the system
148
182
  if response.is_valid?
149
183
  # authorize_success, log the user
150
- session[:userid] = response.name_id
184
+ session[:userid] = response.nameid
151
185
  session[:attributes] = response.attributes
152
186
  else
153
187
  authorize_failure # This method shows an error message
@@ -160,7 +194,7 @@ class SamlController < ApplicationController
160
194
  settings = OneLogin::RubySaml::Settings.new
161
195
 
162
196
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
163
- settings.issuer = request.host
197
+ settings.issuer = "http://#{request.host}/saml/metadata"
164
198
  settings.idp_sso_target_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
165
199
  settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
166
200
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
@@ -196,7 +230,7 @@ def saml_settings
196
230
  settings = idp_metadata_parser.parse_remote("https://example.com/auth/saml2/idp/metadata")
197
231
 
198
232
  settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
199
- settings.issuer = request.host
233
+ settings.issuer = "http://#{request.host}/saml/metadata"
200
234
  settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
201
235
  # Optional for most SAML IdPs
202
236
  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
330
364
  In order to be able to sign we need first to define the private key and the public cert of the service provider
331
365
 
332
366
  ```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"
335
369
  ```
336
370
 
337
371
  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
354
388
  remember to provide it to the Signature builder if you are sending a GET RelayState parameter or
355
389
  Signature validation process will fail at the Identity Provider.
356
390
 
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.
357
413
 
358
414
  ## Single Log Out
359
415
 
@@ -1,10 +1,20 @@
1
1
  # RubySaml Changelog
2
2
 
3
- ### 0.9.4 (March 5, 2018)
4
- * Improve the fix for CVE-2017-11428 to parse CDATA properly
5
-
6
- ### 0.9.3 (Feb 27, 2018)
7
- * Fix vulnerability CVE-2017-11428. Process text of nodes properly, ignoring comments
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).
8
18
 
9
19
  ### 0.9.2 (Apr 28, 2015)
10
20
  * [#216](https://github.com/onelogin/ruby-saml/pull/216) Add fingerprint algorithm support
@@ -22,7 +32,6 @@
22
32
  * [#179](https://github.com/onelogin/ruby-saml/pull/179) Add support for setting the entity ID and name ID format when parsing metadata
23
33
  * [#175](https://github.com/onelogin/ruby-saml/pull/175) Introduce thread safety to SAML schema validation
24
34
  * [#171](https://github.com/onelogin/ruby-saml/pull/171) Fix inconsistent results with using regex matches in decode_raw_saml
25
- *
26
35
 
27
36
  ### 0.9.1 (Feb 10, 2015)
28
37
  * [#194](https://github.com/onelogin/ruby-saml/pull/194) Relax nokogiri gem requirements
@@ -9,6 +9,7 @@ require 'onelogin/ruby-saml/slo_logoutresponse'
9
9
  require 'onelogin/ruby-saml/response'
10
10
  require 'onelogin/ruby-saml/settings'
11
11
  require 'onelogin/ruby-saml/attribute_service'
12
+ require 'onelogin/ruby-saml/http_error'
12
13
  require 'onelogin/ruby-saml/validation_error'
13
14
  require 'onelogin/ruby-saml/metadata'
14
15
  require 'onelogin/ruby-saml/idp_metadata_parser'
@@ -1,10 +1,15 @@
1
1
  module OneLogin
2
2
  module RubySaml
3
+
4
+ # SAML2 AttributeService. Auxiliary class to build the AttributeService of the SP Metadata
5
+ #
3
6
  class AttributeService
4
7
  attr_reader :attributes
5
8
  attr_reader :name
6
9
  attr_reader :index
7
10
 
11
+ # Initializes the AttributeService, set the index value as 1 and an empty array as attributes
12
+ #
8
13
  def initialize
9
14
  @index = "1"
10
15
  @attributes = []
@@ -14,20 +19,38 @@ module OneLogin
14
19
  instance_eval &block
15
20
  end
16
21
 
22
+ # @return [Boolean] True if the AttributeService object has been initialized and set with the required values
23
+ # (has attributes and a name)
17
24
  def configured?
18
25
  @attributes.length > 0 && !@name.nil?
19
26
  end
20
27
 
28
+ # Set a name to the service
29
+ # @param name [String] The service name
30
+ #
21
31
  def service_name(name)
22
32
  @name = name
23
33
  end
24
34
 
35
+ # Set an index to the service
36
+ # @param index [Integer] An index
37
+ #
25
38
  def service_index(index)
26
39
  @index = index
27
40
  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
+ #
29
52
  def add_attribute(options={})
30
- attributes << options
53
+ attributes << options
31
54
  end
32
55
  end
33
56
  end
@@ -1,91 +1,110 @@
1
1
  module OneLogin
2
2
  module RubySaml
3
- # Wraps all attributes and provides means to query them for single or multiple values.
4
- #
5
- # For backwards compatibility Attributes#[] returns *first* value for the attribute.
6
- # Turn off compatibility to make it return all values as an array:
7
- # Attributes.single_value_compatibility = false
3
+
4
+ # SAML2 Attributes. Parse the Attributes from the AttributeStatement of the SAML Response.
5
+ #
8
6
  class Attributes
9
7
  include Enumerable
10
8
 
9
+ attr_reader :attributes
10
+
11
11
  # By default Attributes#[] is backwards compatible and
12
12
  # returns only the first value for the attribute
13
13
  # Setting this to `false` returns all values for an attribute
14
14
  @@single_value_compatibility = true
15
15
 
16
- # Get current status of backwards compatibility mode.
16
+ # @return [Boolean] Get current status of backwards compatibility mode.
17
+ #
17
18
  def self.single_value_compatibility
18
19
  @@single_value_compatibility
19
20
  end
20
21
 
21
22
  # Sets the backwards compatibility mode on/off.
23
+ # @param value [Boolean]
24
+ #
22
25
  def self.single_value_compatibility=(value)
23
26
  @@single_value_compatibility = value
24
27
  end
25
28
 
26
- # Initialize Attributes collection, optionally taking a Hash of attribute names and values.
27
- #
28
- # The +attrs+ must be a Hash with attribute names as keys and **arrays** as values:
29
+ # @param attrs [Hash] The +attrs+ must be a Hash with attribute names as keys and **arrays** as values:
29
30
  # Attributes.new({
30
31
  # 'name' => ['value1', 'value2'],
31
32
  # 'mail' => ['value1'],
32
33
  # })
34
+ #
33
35
  def initialize(attrs = {})
34
36
  @attributes = attrs
35
37
  end
36
38
 
37
39
 
38
40
  # Iterate over all attributes
41
+ #
39
42
  def each
40
43
  attributes.each{|name, values| yield name, values}
41
44
  end
42
45
 
46
+
43
47
  # Test attribute presence by name
48
+ # @param name [String] The attribute name to be checked
49
+ #
44
50
  def include?(name)
45
51
  attributes.has_key?(canonize_name(name))
46
52
  end
47
53
 
48
54
  # Return first value for an attribute
55
+ # @param name [String] The attribute name
56
+ # @return [String] The value (First occurrence)
57
+ #
49
58
  def single(name)
50
59
  attributes[canonize_name(name)].first if include?(name)
51
60
  end
52
61
 
53
62
  # Return all values for an attribute
63
+ # @param name [String] The attribute name
64
+ # @return [Array] Values of the attribute
65
+ #
54
66
  def multi(name)
55
67
  attributes[canonize_name(name)]
56
68
  end
57
69
 
58
- # By default returns first value for an attribute.
59
- #
60
- # Depending on the single value compatibility status this returns first value
61
- # Attributes.single_value_compatibility = true # Default
62
- # response.attributes['mail'] # => 'user@example.com'
70
+ # Retrieve attribute value(s)
71
+ # @param name [String] The attribute name
72
+ # @return [String|Array] Depending on the single value compatibility status this returns:
73
+ # - First value if single_value_compatibility = true
74
+ # response.attributes['mail'] # => 'user@example.com'
75
+ # - All values if single_value_compatibility = false
76
+ # response.attributes['mail'] # => ['user@example.com','user@example.net']
63
77
  #
64
- # Or all values:
65
- # Attributes.single_value_compatibility = false
66
- # response.attributes['mail'] # => ['user@example.com','user@example.net']
67
78
  def [](name)
68
79
  self.class.single_value_compatibility ? single(canonize_name(name)) : multi(canonize_name(name))
69
80
  end
70
81
 
71
- # Return all attributes as an array
82
+ # @return [Array] Return all attributes as an array
83
+ #
72
84
  def all
73
85
  attributes
74
86
  end
75
87
 
76
- # Set values for an attribute, overwriting all existing values
88
+ # @param name [String] The attribute name
89
+ # @param values [Array] The values
90
+ #
77
91
  def set(name, values)
78
92
  attributes[canonize_name(name)] = values
79
93
  end
80
94
  alias_method :[]=, :set
81
95
 
82
- # Add new attribute or new value(s) to an existing attribute
96
+ # @param name [String] The attribute name
97
+ # @param values [Array] The values
98
+ #
83
99
  def add(name, values = [])
84
100
  attributes[canonize_name(name)] ||= []
85
101
  attributes[canonize_name(name)] += Array(values)
86
102
  end
87
103
 
88
104
  # Make comparable to another Attributes collection based on attributes
105
+ # @param other [Attributes] An Attributes object to compare with
106
+ # @return [Boolean] True if are contains the same attributes and values
107
+ #
89
108
  def ==(other)
90
109
  if other.is_a?(Attributes)
91
110
  all == other.all
@@ -97,13 +116,13 @@ module OneLogin
97
116
  protected
98
117
 
99
118
  # stringifies all names so both 'email' and :email return the same result
119
+ # @param name [String] The attribute name
120
+ # @return [String] stringified name
121
+ #
100
122
  def canonize_name(name)
101
123
  name.to_s
102
124
  end
103
125
 
104
- def attributes
105
- @attributes
106
- end
107
126
  end
108
127
  end
109
128
  end
@@ -4,17 +4,30 @@ require "rexml/document"
4
4
  require "onelogin/ruby-saml/logging"
5
5
  require "onelogin/ruby-saml/saml_message"
6
6
 
7
+ # Only supports SAML 2.0
7
8
  module OneLogin
8
9
  module RubySaml
9
10
  include REXML
11
+
12
+ # SAML2 Authentication. AuthNRequest (SSO SP initiated, Builder)
13
+ #
10
14
  class Authrequest < SamlMessage
11
15
 
12
- attr_reader :uuid # Can be obtained if neccessary
16
+ # AuthNRequest ID
17
+ attr_reader :uuid
13
18
 
19
+ # Initializes the AuthNRequest. An Authrequest Object that is an extension of the SamlMessage class.
20
+ # Asigns an ID, a random uuid.
21
+ #
14
22
  def initialize
15
23
  @uuid = "_" + UUID.new.generate
16
24
  end
17
25
 
26
+ # Creates the AuthNRequest string.
27
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
28
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
29
+ # @return [String] AuthNRequest string that includes the SAMLRequest
30
+ #
18
31
  def create(settings, params = {})
19
32
  params = create_params(settings, params)
20
33
  params_prefix = (settings.idp_sso_target_url =~ /\?/) ? '&' : '?'
@@ -26,6 +39,11 @@ module OneLogin
26
39
  @login_url = settings.idp_sso_target_url + request_params
27
40
  end
28
41
 
42
+ # Creates the Get parameters for the request.
43
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
44
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
45
+ # @return [Hash] Parameters
46
+ #
29
47
  def create_params(settings, params={})
30
48
  # The method expects :RelayState but sometimes we get 'RelayState' instead.
31
49
  # Based on the HashWithIndifferentAccess value in Rails we could experience
@@ -46,11 +64,14 @@ module OneLogin
46
64
 
47
65
  if settings.security[:authn_requests_signed] && !settings.security[:embed_sign] && settings.private_key
48
66
  params['SigAlg'] = settings.security[:signature_method]
49
- url_string = "SAMLRequest=#{CGI.escape(base64_request)}"
50
- url_string << "&RelayState=#{CGI.escape(relay_state)}" if relay_state
51
- url_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
52
- private_key = settings.get_sp_key()
53
- signature = private_key.sign(XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method]).new, url_string)
67
+ url_string = OneLogin::RubySaml::Utils.build_query(
68
+ :type => 'SAMLRequest',
69
+ :data => base64_request,
70
+ :relay_state => relay_state,
71
+ :sig_alg => params['SigAlg']
72
+ )
73
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
74
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
54
75
  params['Signature'] = encode(signature)
55
76
  end
56
77
 
@@ -61,6 +82,10 @@ module OneLogin
61
82
  request_params
62
83
  end
63
84
 
85
+ # Creates the SAMLRequest String.
86
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
87
+ # @return [String] The SAMLRequest String.
88
+ #
64
89
  def create_authentication_xml_doc(settings)
65
90
  time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
66
91
 
@@ -118,8 +143,8 @@ module OneLogin
118
143
 
119
144
  # embed signature
120
145
  if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
121
- private_key = settings.get_sp_key()
122
- cert = settings.get_sp_cert()
146
+ private_key = settings.get_sp_key
147
+ cert = settings.get_sp_cert
123
148
  request_doc.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
124
149
  end
125
150