saml_idp 0.9.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -45
- data/lib/saml_idp.rb +2 -1
- data/lib/saml_idp/assertion_builder.rb +28 -3
- data/lib/saml_idp/configurator.rb +4 -1
- data/lib/saml_idp/controller.rb +11 -9
- data/lib/saml_idp/encryptor.rb +0 -1
- data/lib/saml_idp/fingerprint.rb +19 -0
- data/lib/saml_idp/incoming_metadata.rb +13 -0
- data/lib/saml_idp/metadata_builder.rb +23 -8
- data/lib/saml_idp/persisted_metadata.rb +4 -0
- data/lib/saml_idp/request.rb +9 -3
- data/lib/saml_idp/response_builder.rb +19 -5
- data/lib/saml_idp/saml_response.rb +37 -16
- data/lib/saml_idp/service_provider.rb +1 -6
- data/lib/saml_idp/signable.rb +1 -2
- data/lib/saml_idp/version.rb +1 -1
- data/saml_idp.gemspec +8 -8
- data/spec/lib/saml_idp/assertion_builder_spec.rb +73 -0
- data/spec/lib/saml_idp/configurator_spec.rb +1 -0
- data/spec/lib/saml_idp/controller_spec.rb +24 -0
- data/spec/lib/saml_idp/fingerprint_spec.rb +14 -0
- data/spec/lib/saml_idp/incoming_metadata_spec.rb +15 -1
- data/spec/lib/saml_idp/metadata_builder_spec.rb +23 -0
- data/spec/lib/saml_idp/response_builder_spec.rb +3 -1
- data/spec/lib/saml_idp/saml_response_spec.rb +25 -2
- data/spec/rails_app/app/controllers/saml_controller.rb +1 -5
- data/spec/rails_app/app/controllers/saml_idp_controller.rb +47 -8
- data/{app → spec/rails_app/app}/views/saml_idp/idp/new.html.erb +1 -5
- data/{app → spec/rails_app/app}/views/saml_idp/idp/saml_post.html.erb +1 -1
- data/spec/rails_app/config/environments/development.rb +2 -0
- data/spec/spec_helper.rb +20 -1
- data/spec/support/certificates/sp_cert_req.csr +12 -0
- data/spec/support/certificates/sp_private_key.pem +16 -0
- data/spec/support/certificates/sp_x509_cert.crt +18 -0
- data/spec/support/saml_request_macros.rb +62 -3
- data/spec/support/security_helpers.rb +10 -0
- metadata +51 -28
- data/app/controllers/saml_idp/idp_controller.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 847e2cafec28e67417685e6ba1173aa88ac489172e0e31fa51f2bbab37ef5d10
|
4
|
+
data.tar.gz: 8d9ace44b46770b3ca7481461bd16fce9dfc0e2b9925a4a2b5460a780cfddce3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6aa29d58babddddc81037fe220276241a355d81a15acb3639a9cc6df935f531bf1fe53e3c5599d49640080776c357ebf6348559ac034313ad64f82f80a7824a0
|
7
|
+
data.tar.gz: 9f5b83fd6459476d81c2dc2d3f0e79c401ba01474856f201c5a32615da8e22e4c416d220ef82985205f69f1d87a560a80c3bbae552a39ec4bdb49cc0a1baafa0
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ruby SAML Identity Provider (IdP)
|
2
2
|
|
3
|
-
Forked from https://github.com/lawrencepit/ruby-saml-idp
|
3
|
+
Forked from <https://github.com/lawrencepit/ruby-saml-idp>
|
4
4
|
|
5
5
|
[![Build Status](https://travis-ci.org/saml-idp/saml_idp.svg)](https://travis-ci.org/saml-idp/saml_idp)
|
6
6
|
[![Gem Version](https://badge.fury.io/rb/saml_idp.svg)](http://badge.fury.io/rb/saml_idp)
|
@@ -13,13 +13,15 @@ protocol. It provides a means for managing authentication requests and confirmat
|
|
13
13
|
This was originally setup by @lawrencepit to test SAML Clients. I took it closer to a real
|
14
14
|
SAML IDP implementation.
|
15
15
|
|
16
|
-
|
16
|
+
## Installation and Usage
|
17
17
|
|
18
18
|
Add this to your Gemfile:
|
19
19
|
|
20
|
+
```ruby
|
20
21
|
gem 'saml_idp'
|
22
|
+
```
|
21
23
|
|
22
|
-
|
24
|
+
### Not using rails?
|
23
25
|
|
24
26
|
Include `SamlIdp::Controller` and see the examples that use rails. It should be straightforward for you.
|
25
27
|
|
@@ -27,50 +29,32 @@ Basically you call `decode_request(params[:SAMLRequest])` on an incoming request
|
|
27
29
|
`saml_acs_url` to determine the source for which you need to authenticate a user. How you authenticate
|
28
30
|
a user is entirely up to you.
|
29
31
|
|
30
|
-
Once a user has successfully authenticated on your system send the Service Provider a
|
32
|
+
Once a user has successfully authenticated on your system send the Service Provider a SAMLResponse by
|
31
33
|
posting to `saml_acs_url` the parameter `SAMLResponse` with the return value from a call to
|
32
34
|
`encode_response(user_email)`.
|
33
35
|
|
34
|
-
|
36
|
+
### Using rails?
|
35
37
|
|
36
|
-
|
38
|
+
Check out our Wiki page for Rails integration
|
39
|
+
[Rails Integration guide](https://github.com/saml-idp/saml_idp/wiki/Rails_Integration)
|
37
40
|
|
38
|
-
|
39
|
-
get '/saml/auth' => 'saml_idp#new'
|
40
|
-
get '/saml/metadata' => 'saml_idp#show'
|
41
|
-
post '/saml/auth' => 'saml_idp#create'
|
42
|
-
match '/saml/logout' => 'saml_idp#logout', via: [:get, :post, :delete]
|
43
|
-
```
|
41
|
+
### Configuration
|
44
42
|
|
45
|
-
|
43
|
+
#### Signed assertions and Signed Response
|
46
44
|
|
47
|
-
|
48
|
-
class SamlIdpController < SamlIdp::IdpController
|
49
|
-
def idp_authenticate(email, password) # not using params intentionally
|
50
|
-
user = User.by_email(email).first
|
51
|
-
user && user.valid_password?(password) ? user : nil
|
52
|
-
end
|
53
|
-
private :idp_authenticate
|
54
|
-
|
55
|
-
def idp_make_saml_response(found_user) # not using params intentionally
|
56
|
-
# NOTE encryption is optional
|
57
|
-
encode_response found_user, encryption: {
|
58
|
-
cert: saml_request.service_provider.cert,
|
59
|
-
block_encryption: 'aes256-cbc',
|
60
|
-
key_transport: 'rsa-oaep-mgf1p'
|
61
|
-
}
|
62
|
-
end
|
63
|
-
private :idp_make_saml_response
|
45
|
+
By default SAML Assertion will be signed with an algorithm which defined to `config.algorithm`. Because SAML assertions contain secure information used for authentication such as NameID.
|
64
46
|
|
65
|
-
|
66
|
-
|
67
|
-
user.logout
|
68
|
-
end
|
69
|
-
private :idp_logout
|
70
|
-
end
|
71
|
-
```
|
47
|
+
Signing SAML Response is optional, but some security perspective SP services might require Response message itself must be signed.
|
48
|
+
For that, you can enable it with `config.signed_message` option. [More about SAML spec](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=68)
|
72
49
|
|
73
|
-
|
50
|
+
#### Signing algorithm
|
51
|
+
|
52
|
+
Following algorithms you can set in your response signing algorithm
|
53
|
+
:sha1 - RSA-SHA1 default value but not recommended to production environment
|
54
|
+
Highly recommended to use one of following algorithm, suit with your computing power.
|
55
|
+
:sha256 - RSA-SHA256
|
56
|
+
:sha384 - RSA-SHA384
|
57
|
+
:sha512 - RSA-SHA512
|
74
58
|
|
75
59
|
Be sure to load a file like this during your app initialization:
|
76
60
|
|
@@ -91,16 +75,17 @@ KEY DATA
|
|
91
75
|
CERT
|
92
76
|
|
93
77
|
# config.password = "secret_key_password"
|
94
|
-
# config.algorithm = :sha256
|
78
|
+
# config.algorithm = :sha256 # Default: sha1 only for development.
|
95
79
|
# config.organization_name = "Your Organization"
|
96
80
|
# config.organization_url = "http://example.com"
|
97
81
|
# config.base_saml_location = "#{base}/saml"
|
98
|
-
# config.reference_id_generator # Default: -> {
|
82
|
+
# config.reference_id_generator # Default: -> { SecureRandom.uuid }
|
99
83
|
# config.single_logout_service_post_location = "#{base}/saml/logout"
|
100
84
|
# config.single_logout_service_redirect_location = "#{base}/saml/logout"
|
101
85
|
# config.attribute_service_location = "#{base}/saml/attributes"
|
102
86
|
# config.single_service_post_location = "#{base}/saml/auth"
|
103
87
|
# config.session_expiry = 86400 # Default: 0 which means never
|
88
|
+
# config.signed_message = true # Default: false which means unsigned SAML Response
|
104
89
|
|
105
90
|
# Principal (e.g. User) is passed in when you `encode_response`
|
106
91
|
#
|
@@ -213,7 +198,7 @@ CERT
|
|
213
198
|
end
|
214
199
|
```
|
215
200
|
|
216
|
-
|
201
|
+
## Keys and Secrets
|
217
202
|
|
218
203
|
To generate the SAML Response it uses a default X.509 certificate and secret key... which isn't so secret.
|
219
204
|
You can find them in `SamlIdp::Default`. The X.509 certificate is valid until year 2032.
|
@@ -224,22 +209,31 @@ and `SamlIdp.config.secret_key` properties.
|
|
224
209
|
|
225
210
|
The fingerprint to use, if you use the default X.509 certificate of this gem, is:
|
226
211
|
|
212
|
+
```bash
|
213
|
+
9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D
|
227
214
|
```
|
228
|
-
|
215
|
+
|
216
|
+
## Fingerprint
|
217
|
+
|
218
|
+
The gem provides an helper to generate a fingerprint for a X.509 certificate.
|
219
|
+
The second parameter is optional and default to your configuration `SamlIdp.config.algorithm`
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
Fingerprint.certificate_digest(x509_cert, :sha512)
|
229
223
|
```
|
230
224
|
|
231
|
-
|
225
|
+
## Service Providers
|
232
226
|
|
233
227
|
To act as a Service Provider which generates SAML Requests and can react to SAML Responses use the
|
234
228
|
excellent [ruby-saml](https://github.com/onelogin/ruby-saml) gem.
|
235
229
|
|
236
|
-
|
230
|
+
## Author
|
237
231
|
|
238
232
|
Jon Phenow, jon@jphenow.com, jphenow.com, @jphenow
|
239
233
|
|
240
234
|
Lawrence Pit, lawrence.pit@gmail.com, lawrencepit.com, @lawrencepit
|
241
235
|
|
242
|
-
|
236
|
+
## Copyright
|
243
237
|
|
244
238
|
Copyright (c) 2012 Sport Ngin.
|
245
239
|
Portions Copyright (c) 2010 OneLogin, LLC
|
data/lib/saml_idp.rb
CHANGED
@@ -8,7 +8,8 @@ module SamlIdp
|
|
8
8
|
require 'saml_idp/default'
|
9
9
|
require 'saml_idp/metadata_builder'
|
10
10
|
require 'saml_idp/version'
|
11
|
-
require 'saml_idp/
|
11
|
+
require 'saml_idp/fingerprint'
|
12
|
+
require 'saml_idp/engine' if defined?(::Rails)
|
12
13
|
|
13
14
|
def self.config
|
14
15
|
@config ||= SamlIdp::Configurator.new
|
@@ -16,10 +16,26 @@ module SamlIdp
|
|
16
16
|
attr_accessor :expiry
|
17
17
|
attr_accessor :encryption_opts
|
18
18
|
attr_accessor :session_expiry
|
19
|
+
attr_accessor :name_id_formats_opts
|
20
|
+
attr_accessor :asserted_attributes_opts
|
19
21
|
|
20
22
|
delegate :config, to: :SamlIdp
|
21
23
|
|
22
|
-
def initialize(
|
24
|
+
def initialize(
|
25
|
+
reference_id,
|
26
|
+
issuer_uri,
|
27
|
+
principal,
|
28
|
+
audience_uri,
|
29
|
+
saml_request_id,
|
30
|
+
saml_acs_url,
|
31
|
+
raw_algorithm,
|
32
|
+
authn_context_classref,
|
33
|
+
expiry=60*60,
|
34
|
+
encryption_opts=nil,
|
35
|
+
session_expiry=nil,
|
36
|
+
name_id_formats_opts = nil,
|
37
|
+
asserted_attributes_opts = nil
|
38
|
+
)
|
23
39
|
self.reference_id = reference_id
|
24
40
|
self.issuer_uri = issuer_uri
|
25
41
|
self.principal = principal
|
@@ -31,6 +47,8 @@ module SamlIdp
|
|
31
47
|
self.expiry = expiry
|
32
48
|
self.encryption_opts = encryption_opts
|
33
49
|
self.session_expiry = session_expiry.nil? ? config.session_expiry : session_expiry
|
50
|
+
self.name_id_formats_opts = name_id_formats_opts
|
51
|
+
self.asserted_attributes_opts = asserted_attributes_opts
|
34
52
|
end
|
35
53
|
|
36
54
|
def fresh
|
@@ -98,7 +116,9 @@ module SamlIdp
|
|
98
116
|
end
|
99
117
|
|
100
118
|
def asserted_attributes
|
101
|
-
if
|
119
|
+
if asserted_attributes_opts.present? && !asserted_attributes_opts.empty?
|
120
|
+
asserted_attributes_opts
|
121
|
+
elsif principal.respond_to?(:asserted_attributes)
|
102
122
|
principal.send(:asserted_attributes)
|
103
123
|
elsif !config.attributes.nil? && !config.attributes.empty?
|
104
124
|
config.attributes
|
@@ -139,10 +159,15 @@ module SamlIdp
|
|
139
159
|
private :name_id_getter
|
140
160
|
|
141
161
|
def name_id_format
|
142
|
-
@name_id_format ||= NameIdFormatter.new(
|
162
|
+
@name_id_format ||= NameIdFormatter.new(name_id_formats).chosen
|
143
163
|
end
|
144
164
|
private :name_id_format
|
145
165
|
|
166
|
+
def name_id_formats
|
167
|
+
@name_id_formats ||= (name_id_formats_opts || config.name_id.formats)
|
168
|
+
end
|
169
|
+
private :name_id_formats
|
170
|
+
|
146
171
|
def reference_string
|
147
172
|
"_#{reference_id}"
|
148
173
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'ostruct'
|
3
|
+
require 'securerandom'
|
4
|
+
|
3
5
|
module SamlIdp
|
4
6
|
class Configurator
|
5
7
|
attr_accessor :x509_certificate
|
@@ -13,6 +15,7 @@ module SamlIdp
|
|
13
15
|
attr_accessor :reference_id_generator
|
14
16
|
attr_accessor :attribute_service_location
|
15
17
|
attr_accessor :single_service_post_location
|
18
|
+
attr_accessor :single_service_redirect_location
|
16
19
|
attr_accessor :single_logout_service_post_location
|
17
20
|
attr_accessor :single_logout_service_redirect_location
|
18
21
|
attr_accessor :attributes
|
@@ -24,7 +27,7 @@ module SamlIdp
|
|
24
27
|
self.x509_certificate = Default::X509_CERTIFICATE
|
25
28
|
self.secret_key = Default::SECRET_KEY
|
26
29
|
self.algorithm = :sha1
|
27
|
-
self.reference_id_generator = ->() {
|
30
|
+
self.reference_id_generator = ->() { SecureRandom.uuid }
|
28
31
|
self.service_provider = OpenStruct.new
|
29
32
|
self.service_provider.finder = ->(_) { Default::SERVICE_PROVIDER }
|
30
33
|
self.service_provider.metadata_persister = ->(id, settings) { }
|
data/lib/saml_idp/controller.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'openssl'
|
3
3
|
require 'base64'
|
4
4
|
require 'time'
|
5
|
-
require '
|
5
|
+
require 'securerandom'
|
6
6
|
require 'saml_idp/request'
|
7
7
|
require 'saml_idp/logout_response_builder'
|
8
8
|
module SamlIdp
|
@@ -37,11 +37,7 @@ module SamlIdp
|
|
37
37
|
decode_request(raw_saml_request)
|
38
38
|
return true if valid_saml_request?
|
39
39
|
if defined?(::Rails)
|
40
|
-
|
41
|
-
head :forbidden
|
42
|
-
else
|
43
|
-
render nothing: true, status: :forbidden
|
44
|
-
end
|
40
|
+
head :forbidden
|
45
41
|
end
|
46
42
|
false
|
47
43
|
end
|
@@ -64,6 +60,9 @@ module SamlIdp
|
|
64
60
|
expiry = opts[:expiry] || 60*60
|
65
61
|
session_expiry = opts[:session_expiry]
|
66
62
|
encryption_opts = opts[:encryption] || nil
|
63
|
+
signed_message_opts = opts[:signed_message] || false
|
64
|
+
name_id_formats_opts = opts[:name_id_formats] || nil
|
65
|
+
asserted_attributes_opts = opts[:attributes] || nil
|
67
66
|
|
68
67
|
SamlResponse.new(
|
69
68
|
reference_id,
|
@@ -77,7 +76,10 @@ module SamlIdp
|
|
77
76
|
my_authn_context_classref,
|
78
77
|
expiry,
|
79
78
|
encryption_opts,
|
80
|
-
session_expiry
|
79
|
+
session_expiry,
|
80
|
+
signed_message_opts,
|
81
|
+
name_id_formats_opts,
|
82
|
+
asserted_attributes_opts
|
81
83
|
).build
|
82
84
|
end
|
83
85
|
|
@@ -124,11 +126,11 @@ module SamlIdp
|
|
124
126
|
end
|
125
127
|
|
126
128
|
def get_saml_response_id
|
127
|
-
|
129
|
+
SecureRandom.uuid
|
128
130
|
end
|
129
131
|
|
130
132
|
def get_saml_reference_id
|
131
|
-
|
133
|
+
SecureRandom.uuid
|
132
134
|
end
|
133
135
|
|
134
136
|
def default_algorithm
|
data/lib/saml_idp/encryptor.rb
CHANGED
@@ -61,7 +61,6 @@ module SamlIdp
|
|
61
61
|
key_info.EncryptedKey Id: 'EK', xmlns: 'http://www.w3.org/2001/04/xmlenc#' do |enc_key|
|
62
62
|
enc_key.EncryptionMethod Algorithm: key_transport_ns
|
63
63
|
enc_key.tag! 'ds:KeyInfo', 'xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#' do |key_info2|
|
64
|
-
key_info2.tag! 'ds:KeyName'
|
65
64
|
key_info2.tag! 'ds:X509Data' do |x509_data|
|
66
65
|
x509_data.tag! 'ds:X509Certificate' do |x509_cert|
|
67
66
|
x509_cert << cert.to_s.gsub(/-+(BEGIN|END) CERTIFICATE-+/, '')
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SamlIdp
|
2
|
+
module Fingerprint
|
3
|
+
def self.certificate_digest(cert, sha_size = nil)
|
4
|
+
sha_size ||= SamlIdp.config.algorithm
|
5
|
+
digest_sha_class(sha_size).hexdigest(OpenSSL::X509::Certificate.new(cert).to_der).scan(/../).join(':')
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.digest_sha_class(sha_size)
|
9
|
+
case sha_size
|
10
|
+
when :sha256
|
11
|
+
Digest::SHA256
|
12
|
+
when :sha512
|
13
|
+
Digest::SHA512
|
14
|
+
else
|
15
|
+
raise ArgumentError, "Unsupported sha size parameter: #{sha_size}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -34,6 +34,19 @@ module SamlIdp
|
|
34
34
|
end
|
35
35
|
hashable :sign_assertions
|
36
36
|
|
37
|
+
def sign_authn_request
|
38
|
+
doc = xpath(
|
39
|
+
"//md:SPSSODescriptor",
|
40
|
+
ds: signature_namespace,
|
41
|
+
md: metadata_namespace
|
42
|
+
).first
|
43
|
+
if (doc && !doc['AuthnRequestsSigned'].nil?)
|
44
|
+
return doc['AuthnRequestsSigned'].strip.downcase == 'true'
|
45
|
+
end
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
hashable :sign_authn_request
|
49
|
+
|
37
50
|
def display_name
|
38
51
|
role_descriptor_document.present? ? role_descriptor_document["ServiceDisplayName"] : ""
|
39
52
|
end
|
@@ -24,13 +24,15 @@ module SamlIdp
|
|
24
24
|
|
25
25
|
entity.IDPSSODescriptor protocolSupportEnumeration: protocol_enumeration do |descriptor|
|
26
26
|
build_key_descriptor descriptor
|
27
|
-
descriptor
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
build_endpoint descriptor, [
|
28
|
+
{ tag: 'SingleLogoutService', url: single_logout_service_post_location, bind: 'HTTP-POST' },
|
29
|
+
{ tag: 'SingleLogoutService', url: single_logout_service_redirect_location, bind: 'HTTP-Redirect'}
|
30
|
+
]
|
31
31
|
build_name_id_formats descriptor
|
32
|
-
descriptor
|
33
|
-
|
32
|
+
build_endpoint descriptor, [
|
33
|
+
{ tag: 'SingleSignOnService', url: single_service_post_location, bind: 'HTTP-POST' },
|
34
|
+
{ tag: 'SingleSignOnService', url: single_service_redirect_location, bind: 'HTTP-Redirect'}
|
35
|
+
]
|
34
36
|
build_attribute descriptor
|
35
37
|
end
|
36
38
|
|
@@ -38,8 +40,9 @@ module SamlIdp
|
|
38
40
|
build_key_descriptor authority_descriptor
|
39
41
|
build_organization authority_descriptor
|
40
42
|
build_contact authority_descriptor
|
41
|
-
authority_descriptor
|
42
|
-
|
43
|
+
build_endpoint authority_descriptor, [
|
44
|
+
{ tag: 'AttributeService', url: attribute_service_location, bind: 'HTTP-Redirect' }
|
45
|
+
]
|
43
46
|
build_name_id_formats authority_descriptor
|
44
47
|
build_attribute authority_descriptor
|
45
48
|
end
|
@@ -69,6 +72,17 @@ module SamlIdp
|
|
69
72
|
end
|
70
73
|
private :build_name_id_formats
|
71
74
|
|
75
|
+
def build_endpoint(el, end_points)
|
76
|
+
end_points.each do |ep|
|
77
|
+
next unless ep[:url].present?
|
78
|
+
|
79
|
+
el.tag! ep[:tag],
|
80
|
+
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:#{ep[:bind]}",
|
81
|
+
Location: ep[:url]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
private :build_endpoint
|
85
|
+
|
72
86
|
def build_attribute(el)
|
73
87
|
attributes.each do |attribute|
|
74
88
|
el.tag! "saml:Attribute",
|
@@ -151,6 +165,7 @@ module SamlIdp
|
|
151
165
|
organization_url
|
152
166
|
attribute_service_location
|
153
167
|
single_service_post_location
|
168
|
+
single_service_redirect_location
|
154
169
|
single_logout_service_post_location
|
155
170
|
single_logout_service_redirect_location
|
156
171
|
technical_contact
|