ruby-saml 0.8.16 → 0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +1 -6
- data/Gemfile +2 -12
- data/README.md +363 -35
- data/Rakefile +14 -0
- data/changelog.md +22 -9
- data/lib/onelogin/ruby-saml/attribute_service.rb +34 -0
- data/lib/onelogin/ruby-saml/attributes.rb +26 -64
- data/lib/onelogin/ruby-saml/authrequest.rb +47 -89
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
- data/lib/onelogin/ruby-saml/logoutrequest.rb +34 -93
- data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -24
- data/lib/onelogin/ruby-saml/metadata.rb +46 -16
- data/lib/onelogin/ruby-saml/response.rb +62 -322
- data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
- data/lib/onelogin/ruby-saml/settings.rb +54 -121
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +26 -61
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -84
- data/lib/onelogin/ruby-saml/utils.rb +32 -199
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +5 -2
- data/lib/schemas/{saml20assertion_schema.xsd → saml-schema-assertion-2.0.xsd} +283 -283
- data/lib/schemas/saml-schema-authn-context-2.0.xsd +23 -0
- data/lib/schemas/saml-schema-authn-context-types-2.0.xsd +821 -0
- data/lib/schemas/saml-schema-metadata-2.0.xsd +339 -0
- data/lib/schemas/{saml20protocol_schema.xsd → saml-schema-protocol-2.0.xsd} +302 -302
- data/lib/schemas/sstc-metadata-attr.xsd +35 -0
- data/lib/schemas/sstc-saml-attribute-ext.xsd +25 -0
- data/lib/schemas/sstc-saml-metadata-algsupport-v1.0.xsd +41 -0
- data/lib/schemas/sstc-saml-metadata-ui-v1.0.xsd +89 -0
- data/lib/schemas/{xenc_schema.xsd → xenc-schema.xsd} +1 -11
- data/lib/schemas/xml.xsd +287 -0
- data/lib/schemas/{xmldsig_schema.xsd → xmldsig-core-schema.xsd} +0 -9
- data/lib/xml_security.rb +83 -235
- data/ruby-saml.gemspec +1 -0
- data/test/idp_metadata_parser_test.rb +54 -0
- data/test/logoutrequest_test.rb +68 -144
- data/test/logoutresponse_test.rb +43 -25
- data/test/metadata_test.rb +87 -0
- data/test/request_test.rb +103 -90
- data/test/response_test.rb +181 -471
- data/test/responses/idp_descriptor.xml +3 -0
- data/test/responses/logoutresponse_fixtures.rb +5 -5
- data/test/responses/response_no_cert_and_encrypted_attrs.xml +29 -0
- data/test/responses/response_with_multiple_attribute_values.xml +1 -1
- data/test/responses/slo_request.xml +4 -0
- data/test/settings_test.rb +25 -112
- data/test/slo_logoutrequest_test.rb +41 -44
- data/test/slo_logoutresponse_test.rb +87 -167
- data/test/test_helper.rb +27 -102
- data/test/xml_security_test.rb +114 -337
- metadata +34 -84
- data/lib/onelogin/ruby-saml/setting_error.rb +0 -6
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/formatted_certificate +0 -14
- data/test/certificates/formatted_chained_certificate +0 -42
- data/test/certificates/formatted_private_key +0 -12
- data/test/certificates/formatted_rsa_private_key +0 -12
- data/test/certificates/invalid_certificate1 +0 -1
- data/test/certificates/invalid_certificate2 +0 -1
- data/test/certificates/invalid_certificate3 +0 -12
- data/test/certificates/invalid_chained_certificate1 +0 -1
- data/test/certificates/invalid_private_key1 +0 -1
- data/test/certificates/invalid_private_key2 +0 -1
- data/test/certificates/invalid_private_key3 +0 -10
- data/test/certificates/invalid_rsa_private_key1 +0 -1
- data/test/certificates/invalid_rsa_private_key2 +0 -1
- data/test/certificates/invalid_rsa_private_key3 +0 -10
- data/test/certificates/ruby-saml-2.crt +0 -15
- data/test/requests/logoutrequest_fixtures.rb +0 -47
- data/test/responses/encrypted_new_attack.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
- data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
- data/test/responses/invalids/no_signature.xml.base64 +0 -1
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
- data/test/responses/response_node_text_attack.xml.base64 +0 -1
- data/test/responses/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
- data/test/responses/response_with_signed_assertion_3.xml +0 -30
- data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
- data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
- data/test/responses/response_wrapped.xml.base64 +0 -150
- data/test/responses/valid_response.xml.base64 +0 -1
- data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
- data/test/utils_test.rb +0 -231
data/Rakefile
CHANGED
|
@@ -25,3 +25,17 @@ end
|
|
|
25
25
|
task :test
|
|
26
26
|
|
|
27
27
|
task :default => :test
|
|
28
|
+
|
|
29
|
+
# require 'rake/rdoctask'
|
|
30
|
+
# Rake::RDocTask.new do |rdoc|
|
|
31
|
+
# if File.exist?('VERSION')
|
|
32
|
+
# version = File.read('VERSION')
|
|
33
|
+
# else
|
|
34
|
+
# version = ""
|
|
35
|
+
# end
|
|
36
|
+
|
|
37
|
+
# rdoc.rdoc_dir = 'rdoc'
|
|
38
|
+
# rdoc.title = "ruby-saml #{version}"
|
|
39
|
+
# rdoc.rdoc_files.include('README*')
|
|
40
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
|
41
|
+
#end
|
data/changelog.md
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
# RubySaml Changelog
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* Fix
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
### 0.9 (Jan 26, 2015)
|
|
3
|
+
* [#169](https://github.com/onelogin/ruby-saml/pull/169) WantAssertionSigned should be either true or false
|
|
4
|
+
* [#167](https://github.com/onelogin/ruby-saml/pull/167) (doc update) make unit of clock drift obvious
|
|
5
|
+
* [#160](https://github.com/onelogin/ruby-saml/pull/160) Extended solution for Attributes method [] can raise NoMethodError
|
|
6
|
+
* [#158](https://github.com/onelogin/ruby-saml/pull/1) Added ability to specify attribute services in metadata
|
|
7
|
+
* [#154](https://github.com/onelogin/ruby-saml/pull/154) Fix incorrect gem declaration statement
|
|
8
|
+
* [#152](https://github.com/onelogin/ruby-saml/pull/152) Fix the PR #99
|
|
9
|
+
* [#150](https://github.com/onelogin/ruby-saml/pull/150) Nokogiri already in gemspec
|
|
10
|
+
* [#147](https://github.com/onelogin/ruby-saml/pull/147) Fix LogoutResponse issuer validation and implement SAML Response issuer validation.
|
|
11
|
+
* [#144](https://github.com/onelogin/ruby-saml/pull/144) Fix DigestMethod lookup bug
|
|
12
|
+
* [#139](https://github.com/onelogin/ruby-saml/pull/139) Fixes handling of some soft and hard validation failures
|
|
13
|
+
* [#138](https://github.com/onelogin/ruby-saml/pull/138) Change logoutrequest.rb to UTC time
|
|
14
|
+
* [#136](https://github.com/onelogin/ruby-saml/pull/136) Remote idp metadata
|
|
15
|
+
* [#135](https://github.com/onelogin/ruby-saml/pull/135) Restored support for NIL as well as empty AttributeValues
|
|
16
|
+
* [#134](https://github.com/onelogin/ruby-saml/pull/134) explicitly require "onelogin/ruby-saml/logging"
|
|
17
|
+
* [#133](https://github.com/onelogin/ruby-saml/pull/133) Added license to gemspec
|
|
18
|
+
* [#132](https://github.com/onelogin/ruby-saml/pull/132) Support AttributeConsumingServiceIndex in AuthnRequest
|
|
19
|
+
* [#131](https://github.com/onelogin/ruby-saml/pull/131) Add ruby 2.1.1 to .travis.yml
|
|
20
|
+
* [#122](https://github.com/onelogin/ruby-saml/pull/122) Fixes #112 and #117 in a backwards compatible manner
|
|
21
|
+
* [#119](https://github.com/onelogin/ruby-saml/pull/119) Add support for extracting IdP details from metadata xml
|
|
22
|
+
|
|
23
|
+
### 0.8.2 (Jan 26, 2015)
|
|
11
24
|
* [#183](https://github.com/onelogin/ruby-saml/pull/183) Resolved a security vulnerability where string interpolation in a `REXML::XPath.first()` method call allowed for arbitrary code execution.
|
|
12
25
|
|
|
13
26
|
### 0.8.0 (Feb 21, 2014)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module OneLogin
|
|
2
|
+
module RubySaml
|
|
3
|
+
class AttributeService
|
|
4
|
+
attr_reader :attributes
|
|
5
|
+
attr_reader :name
|
|
6
|
+
attr_reader :index
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@index = "1"
|
|
10
|
+
@attributes = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def configure(&block)
|
|
14
|
+
instance_eval &block
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def configured?
|
|
18
|
+
@attributes.length > 0 && !@name.nil?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def service_name(name)
|
|
22
|
+
@name = name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def service_index(index)
|
|
26
|
+
@index = index
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add_attribute(options={})
|
|
30
|
+
attributes << options
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -1,118 +1,91 @@
|
|
|
1
1
|
module OneLogin
|
|
2
2
|
module RubySaml
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
#
|
|
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
|
|
6
8
|
class Attributes
|
|
7
9
|
include Enumerable
|
|
8
10
|
|
|
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
|
-
#
|
|
17
|
-
#
|
|
16
|
+
# Get current status of backwards compatibility mode.
|
|
18
17
|
def self.single_value_compatibility
|
|
19
18
|
@@single_value_compatibility
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
# Sets the backwards compatibility mode on/off.
|
|
23
|
-
# @param value [Boolean]
|
|
24
|
-
#
|
|
25
22
|
def self.single_value_compatibility=(value)
|
|
26
23
|
@@single_value_compatibility = value
|
|
27
24
|
end
|
|
28
25
|
|
|
29
|
-
#
|
|
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:
|
|
30
29
|
# Attributes.new({
|
|
31
30
|
# 'name' => ['value1', 'value2'],
|
|
32
31
|
# 'mail' => ['value1'],
|
|
33
32
|
# })
|
|
34
|
-
#
|
|
35
33
|
def initialize(attrs = {})
|
|
36
34
|
@attributes = attrs
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
|
|
40
38
|
# Iterate over all attributes
|
|
41
|
-
#
|
|
42
39
|
def each
|
|
43
40
|
attributes.each{|name, values| yield name, values}
|
|
44
41
|
end
|
|
45
42
|
|
|
46
|
-
|
|
47
43
|
# Test attribute presence by name
|
|
48
|
-
# @param name [String] The attribute name to be checked
|
|
49
|
-
#
|
|
50
44
|
def include?(name)
|
|
51
|
-
attributes.has_key?(canonize_name(name))
|
|
45
|
+
attributes.has_key?(canonize_name(name))
|
|
52
46
|
end
|
|
53
47
|
|
|
54
48
|
# Return first value for an attribute
|
|
55
|
-
# @param name [String] The attribute name
|
|
56
|
-
# @return [String] The value (First occurrence)
|
|
57
|
-
#
|
|
58
49
|
def single(name)
|
|
59
|
-
|
|
50
|
+
attributes[canonize_name(name)].first if include?(name)
|
|
60
51
|
end
|
|
61
52
|
|
|
62
53
|
# Return all values for an attribute
|
|
63
|
-
# @param name [String] The attribute name
|
|
64
|
-
# @return [Array] Values of the attribute
|
|
65
|
-
#
|
|
66
54
|
def multi(name)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if values.is_a?(Array)
|
|
70
|
-
values
|
|
71
|
-
elsif !values.nil?
|
|
72
|
-
Array(values)
|
|
73
|
-
else
|
|
74
|
-
nil
|
|
75
|
-
end
|
|
55
|
+
attributes[canonize_name(name)]
|
|
76
56
|
end
|
|
77
57
|
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# - All values if single_value_compatibility = false
|
|
84
|
-
# response.attributes['mail'] # => ['user@example.com','user@example.net']
|
|
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'
|
|
85
63
|
#
|
|
64
|
+
# Or all values:
|
|
65
|
+
# Attributes.single_value_compatibility = false
|
|
66
|
+
# response.attributes['mail'] # => ['user@example.com','user@example.net']
|
|
86
67
|
def [](name)
|
|
87
|
-
self.class.single_value_compatibility ? single(name) : multi(name)
|
|
68
|
+
self.class.single_value_compatibility ? single(canonize_name(name)) : multi(canonize_name(name))
|
|
88
69
|
end
|
|
89
70
|
|
|
90
|
-
#
|
|
91
|
-
#
|
|
71
|
+
# Return all attributes as an array
|
|
92
72
|
def all
|
|
93
73
|
attributes
|
|
94
74
|
end
|
|
95
75
|
|
|
96
|
-
#
|
|
97
|
-
# @param values [Array] The values
|
|
98
|
-
#
|
|
76
|
+
# Set values for an attribute, overwriting all existing values
|
|
99
77
|
def set(name, values)
|
|
100
78
|
attributes[canonize_name(name)] = values
|
|
101
79
|
end
|
|
102
80
|
alias_method :[]=, :set
|
|
103
81
|
|
|
104
|
-
#
|
|
105
|
-
# @param values [Array] The values
|
|
106
|
-
#
|
|
82
|
+
# Add new attribute or new value(s) to an existing attribute
|
|
107
83
|
def add(name, values = [])
|
|
108
84
|
attributes[canonize_name(name)] ||= []
|
|
109
85
|
attributes[canonize_name(name)] += Array(values)
|
|
110
86
|
end
|
|
111
87
|
|
|
112
88
|
# Make comparable to another Attributes collection based on attributes
|
|
113
|
-
# @param other [Attributes] An Attributes object to compare with
|
|
114
|
-
# @return [Boolean] True if are contains the same attributes and values
|
|
115
|
-
#
|
|
116
89
|
def ==(other)
|
|
117
90
|
if other.is_a?(Attributes)
|
|
118
91
|
all == other.all
|
|
@@ -121,26 +94,15 @@ module OneLogin
|
|
|
121
94
|
end
|
|
122
95
|
end
|
|
123
96
|
|
|
124
|
-
def respond_to?(name)
|
|
125
|
-
attributes.respond_to?(name) || super
|
|
126
|
-
end
|
|
127
|
-
|
|
128
97
|
protected
|
|
129
98
|
|
|
130
99
|
# stringifies all names so both 'email' and :email return the same result
|
|
131
|
-
# @param name [String] The attribute name
|
|
132
|
-
# @return [String] stringified name
|
|
133
|
-
#
|
|
134
100
|
def canonize_name(name)
|
|
135
101
|
name.to_s
|
|
136
102
|
end
|
|
137
103
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
attributes.send(name, *args, &block)
|
|
141
|
-
else
|
|
142
|
-
super
|
|
143
|
-
end
|
|
104
|
+
def attributes
|
|
105
|
+
@attributes
|
|
144
106
|
end
|
|
145
107
|
end
|
|
146
108
|
end
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
require "
|
|
2
|
-
|
|
3
|
-
require "
|
|
4
|
-
require "onelogin/ruby-saml/utils"
|
|
5
|
-
require "onelogin/ruby-saml/setting_error"
|
|
1
|
+
require "uuid"
|
|
2
|
+
|
|
3
|
+
require "onelogin/ruby-saml/logging"
|
|
6
4
|
|
|
7
5
|
module OneLogin
|
|
8
6
|
module RubySaml
|
|
7
|
+
include REXML
|
|
8
|
+
class Authrequest < SamlMessage
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
# AuthNRequest ID
|
|
12
|
-
attr_reader :uuid
|
|
10
|
+
attr_reader :uuid # Can be obtained if neccessary
|
|
13
11
|
|
|
14
|
-
# Initializes the AuthNRequest. An Authrequest Object.
|
|
15
|
-
# Asigns an ID, a random uuid.
|
|
16
|
-
#
|
|
17
12
|
def initialize
|
|
18
|
-
@uuid =
|
|
13
|
+
@uuid = "_" + UUID.new.generate
|
|
19
14
|
end
|
|
20
15
|
|
|
21
16
|
def create(settings, params = {})
|
|
@@ -26,25 +21,11 @@ module OneLogin
|
|
|
26
21
|
params.each_pair do |key, value|
|
|
27
22
|
request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
|
|
28
23
|
end
|
|
29
|
-
raise SettingError.new "Invalid settings, idp_sso_target_url is not set!" if settings.idp_sso_target_url.nil? or settings.idp_sso_target_url.empty?
|
|
30
24
|
@login_url = settings.idp_sso_target_url + request_params
|
|
31
25
|
end
|
|
32
26
|
|
|
33
|
-
# Creates the Get parameters for the request.
|
|
34
|
-
# @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
|
|
35
|
-
# @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
|
|
36
|
-
# @return [Hash] Parameters
|
|
37
|
-
#
|
|
38
27
|
def create_params(settings, params={})
|
|
39
|
-
|
|
40
|
-
# Based on the HashWithIndifferentAccess value in Rails we could experience
|
|
41
|
-
# conflicts so this line will solve them.
|
|
42
|
-
relay_state = params[:RelayState] || params['RelayState']
|
|
43
|
-
|
|
44
|
-
if relay_state.nil?
|
|
45
|
-
params.delete(:RelayState)
|
|
46
|
-
params.delete('RelayState')
|
|
47
|
-
end
|
|
28
|
+
params = {} if params.nil?
|
|
48
29
|
|
|
49
30
|
request_doc = create_authentication_xml_doc(settings)
|
|
50
31
|
request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
|
|
@@ -54,30 +35,18 @@ module OneLogin
|
|
|
54
35
|
|
|
55
36
|
Logging.debug "Created AuthnRequest: #{request}"
|
|
56
37
|
|
|
57
|
-
request =
|
|
58
|
-
|
|
59
|
-
base64_request = Base64.strict_encode64(request)
|
|
60
|
-
else
|
|
61
|
-
base64_request = Base64.encode64(request).gsub(/\n/, "")
|
|
62
|
-
end
|
|
63
|
-
|
|
38
|
+
request = deflate(request) if settings.compress_request
|
|
39
|
+
base64_request = encode(request)
|
|
64
40
|
request_params = {"SAMLRequest" => base64_request}
|
|
65
41
|
|
|
66
42
|
if settings.security[:authn_requests_signed] && !settings.security[:embed_sign] && settings.private_key
|
|
67
|
-
params['SigAlg'] =
|
|
68
|
-
url_string
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
|
|
75
|
-
signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
|
|
76
|
-
if Base64.respond_to?('strict_encode64')
|
|
77
|
-
params['Signature'] = Base64.strict_encode64(signature)
|
|
78
|
-
else
|
|
79
|
-
params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
|
|
80
|
-
end
|
|
43
|
+
params['SigAlg'] = XMLSecurity::Document::SHA1
|
|
44
|
+
url_string = "SAMLRequest=#{CGI.escape(base64_request)}"
|
|
45
|
+
url_string += "&RelayState=#{CGI.escape(params['RelayState'])}" if params['RelayState']
|
|
46
|
+
url_string += "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
|
47
|
+
private_key = settings.get_sp_key()
|
|
48
|
+
signature = private_key.sign(XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method]).new, url_string)
|
|
49
|
+
params['Signature'] = encode(signature)
|
|
81
50
|
end
|
|
82
51
|
|
|
83
52
|
params.each_pair do |key, value|
|
|
@@ -88,12 +57,7 @@ module OneLogin
|
|
|
88
57
|
end
|
|
89
58
|
|
|
90
59
|
def create_authentication_xml_doc(settings)
|
|
91
|
-
|
|
92
|
-
sign_document(document, settings)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def create_xml_document(settings)
|
|
96
|
-
time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
60
|
+
time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
97
61
|
|
|
98
62
|
request_doc = XMLSecurity::Document.new
|
|
99
63
|
request_doc.uuid = uuid
|
|
@@ -102,65 +66,59 @@ module OneLogin
|
|
|
102
66
|
root.attributes['ID'] = uuid
|
|
103
67
|
root.attributes['IssueInstant'] = time
|
|
104
68
|
root.attributes['Version'] = "2.0"
|
|
105
|
-
root.attributes['Destination'] = settings.idp_sso_target_url unless settings.idp_sso_target_url.nil?
|
|
69
|
+
root.attributes['Destination'] = settings.idp_sso_target_url unless settings.idp_sso_target_url.nil?
|
|
106
70
|
root.attributes['IsPassive'] = settings.passive unless settings.passive.nil?
|
|
107
71
|
root.attributes['ProtocolBinding'] = settings.protocol_binding unless settings.protocol_binding.nil?
|
|
72
|
+
root.attributes["AttributeConsumingServiceIndex"] = settings.attributes_index unless settings.attributes_index.nil?
|
|
108
73
|
root.attributes['ForceAuthn'] = settings.force_authn unless settings.force_authn.nil?
|
|
109
74
|
|
|
110
75
|
# Conditionally defined elements based on settings
|
|
111
76
|
if settings.assertion_consumer_service_url != nil
|
|
112
77
|
root.attributes["AssertionConsumerServiceURL"] = settings.assertion_consumer_service_url
|
|
113
78
|
end
|
|
114
|
-
if settings.
|
|
79
|
+
if settings.issuer != nil
|
|
115
80
|
issuer = root.add_element "saml:Issuer"
|
|
116
|
-
issuer.text = settings.
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
if settings.name_identifier_value_requested != nil
|
|
120
|
-
subject = root.add_element "saml:Subject"
|
|
121
|
-
|
|
122
|
-
nameid = subject.add_element "saml:NameID"
|
|
123
|
-
nameid.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
|
|
124
|
-
nameid.text = settings.name_identifier_value_requested
|
|
125
|
-
|
|
126
|
-
subject_confirmation = subject.add_element "saml:SubjectConfirmation"
|
|
127
|
-
subject_confirmation.attributes['Method'] = "urn:oasis:names:tc:SAML:2.0:cm:bearer"
|
|
81
|
+
issuer.text = settings.issuer
|
|
128
82
|
end
|
|
129
|
-
|
|
130
83
|
if settings.name_identifier_format != nil
|
|
131
84
|
root.add_element "samlp:NameIDPolicy", {
|
|
132
|
-
"xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
|
|
133
85
|
# Might want to make AllowCreate a setting?
|
|
134
86
|
"AllowCreate" => "true",
|
|
135
87
|
"Format" => settings.name_identifier_format
|
|
136
88
|
}
|
|
137
89
|
end
|
|
138
90
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
91
|
+
if settings.authn_context || settings.authn_context_decl_ref
|
|
92
|
+
|
|
93
|
+
if settings.authn_context_comparison != nil
|
|
94
|
+
comparison = settings.authn_context_comparison
|
|
95
|
+
else
|
|
96
|
+
comparison = 'exact'
|
|
97
|
+
end
|
|
98
|
+
|
|
143
99
|
requested_context = root.add_element "samlp:RequestedAuthnContext", {
|
|
144
|
-
"
|
|
145
|
-
"Comparison" => "exact",
|
|
146
|
-
}
|
|
147
|
-
class_ref = requested_context.add_element "saml:AuthnContextClassRef", {
|
|
148
|
-
"xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion",
|
|
100
|
+
"Comparison" => comparison,
|
|
149
101
|
}
|
|
150
|
-
|
|
102
|
+
|
|
103
|
+
if settings.authn_context != nil
|
|
104
|
+
class_ref = requested_context.add_element "saml:AuthnContextClassRef"
|
|
105
|
+
class_ref.text = settings.authn_context
|
|
106
|
+
end
|
|
107
|
+
# add saml:AuthnContextDeclRef element
|
|
108
|
+
if settings.authn_context_decl_ref != nil
|
|
109
|
+
class_ref = requested_context.add_element "saml:AuthnContextDeclRef"
|
|
110
|
+
class_ref.text = settings.authn_context_decl_ref
|
|
111
|
+
end
|
|
151
112
|
end
|
|
152
|
-
request_doc
|
|
153
|
-
end
|
|
154
113
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
cert
|
|
160
|
-
document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
|
|
114
|
+
# embebed sign
|
|
115
|
+
if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
|
|
116
|
+
private_key = settings.get_sp_key()
|
|
117
|
+
cert = settings.get_sp_cert()
|
|
118
|
+
request_doc.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
|
|
161
119
|
end
|
|
162
120
|
|
|
163
|
-
|
|
121
|
+
request_doc
|
|
164
122
|
end
|
|
165
123
|
|
|
166
124
|
end
|