omniauth-cas 1.0.4 → 2.0.0
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 +6 -14
- data/.editorconfig +16 -0
- data/.travis.yml +16 -3
- data/CHANGELOG.md +27 -0
- data/Gemfile +5 -0
- data/README.md +47 -16
- data/lib/omniauth-cas.rb +1 -1
- data/lib/omniauth/cas/version.rb +1 -1
- data/lib/omniauth/strategies/cas.rb +105 -45
- data/lib/omniauth/strategies/cas/logout_request.rb +58 -0
- data/lib/omniauth/strategies/cas/service_ticket_validator.rb +24 -9
- data/omniauth-cas.gemspec +7 -9
- data/spec/fixtures/cas_success.xml +3 -0
- data/spec/fixtures/cas_success_jasig.xml +3 -0
- data/spec/omniauth/strategies/cas/logout_request_spec.rb +105 -0
- data/spec/omniauth/strategies/cas/service_ticket_validator_spec.rb +54 -13
- data/spec/omniauth/strategies/cas_spec.rb +180 -84
- data/spec/spec_helper.rb +0 -4
- metadata +44 -59
- data/.rvmrc +0 -1
- data/History.md +0 -58
- data/lib/omniauth/strategies/cas/configuration.rb +0 -34
- data/spec/omniauth/strategies/cas/configuration_spec.rb +0 -60
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
ZTdkZjEzMDY4ODVjMzY1NDQ2MmUxZTAyMzRkMGUwNzcxYzAyOGM5MzBlNDZi
|
10
|
-
ZjU1OTk0OWU1ODIzNTIwYTIxNWM5ZDEzNzFiY2UyODJhYzY3NDRkZmM5ODcy
|
11
|
-
NTBlMGM5YWFhZWU1MDBlMTI2YWQ0NTRmODRkZjhiYmVmMjc2ZDI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
OTY0NjU1NTFhZGZmNjdlN2E2OTY5MjNkMTU0NDY5NWQ1ZjQ3N2RiZWFjNmZj
|
14
|
-
MDA3MmY4M2U1MjMwOThkZmRhNzYwZDI5NzljYjRiYzk5YjY5MWFlNjBjYjY0
|
15
|
-
NzBhNjE1OWViZjMzMGVmYzkzMWM5MTk5MGNmNjk1MTU3YjYxYWU=
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 20d02177b4bdbd637993a8d225133ada4d6d40092b59db98e54b38bbe8aef780
|
4
|
+
data.tar.gz: 9143ccd826882b5f1228b7686958cfa62c9527ab1fef041d6ce1bfb39e7e0f6d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a9edd4d3c46a7c7349a0ebf05a67747cb25cfda51fc2c4ebfbc054726e4e8b7034f969291f5f184d609999250507bdfe1da01f659cb43682b837d4fa44292271
|
7
|
+
data.tar.gz: e64e3311e11537b2abc77d25189ef38eebdcbb147eb6db53deb7562530371f40851e035eae08370f3621843873c36c47e9690d1e5f2a0678b31ea8dd87f79bca
|
data/.editorconfig
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# EditorConfig helps developers define and maintain consistent
|
2
|
+
# coding styles between different editors and IDEs
|
3
|
+
# editorconfig.org
|
4
|
+
|
5
|
+
root = true
|
6
|
+
|
7
|
+
[*]
|
8
|
+
# Change these settings to your own preference
|
9
|
+
indent_style = space
|
10
|
+
indent_size = 2
|
11
|
+
|
12
|
+
# We recommend you to keep these unchanged
|
13
|
+
end_of_line = lf
|
14
|
+
charset = utf-8
|
15
|
+
trim_trailing_whitespace = true
|
16
|
+
insert_final_newline = true
|
data/.travis.yml
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
+
dist: xenial
|
2
|
+
os: linux
|
3
|
+
language: ruby
|
1
4
|
rvm:
|
2
|
-
- 1
|
3
|
-
-
|
5
|
+
- 2.1
|
6
|
+
- 2.2
|
7
|
+
- 2.3
|
8
|
+
- 2.4
|
9
|
+
- 2.5
|
10
|
+
- 2.6
|
11
|
+
- 2.7
|
12
|
+
- ruby-edge
|
4
13
|
branches:
|
5
14
|
only:
|
6
15
|
- master
|
7
16
|
before_install:
|
8
|
-
- gem
|
17
|
+
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
|
18
|
+
- gem install bundler -v '< 2'
|
19
|
+
jobs:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: ruby-edge
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this
|
6
|
+
project adheres to [Semantic Versioning](http://semver.org/)
|
7
|
+
|
8
|
+
## 2.0.0 - 2010-11-14
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
* Add support for multivalued attributes ([#59](https://github.com/dlindahl/omniauth-cas/pull/59))
|
13
|
+
* Successfully test against Ruby 2.4 and up ([#60](https://github.com/dlindahl/omniauth-cas/pull/60))
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
* Forward success response to `fetch_raw_info` callback ([#51](https://github.com/dlindahl/omniauth-cas/pull/51))
|
18
|
+
* Relax development dependencies to the latest versions
|
19
|
+
|
20
|
+
## 1.1.1 - 2016-09-19
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
|
24
|
+
* Relax gemspec requirements, to add support for Rails 5.
|
25
|
+
|
26
|
+
Note that the only tested versions of Ruby are now 2.1, 2.2, and 2.3 - older
|
27
|
+
versions of Ruby should work, but are no longer officially supported.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
# OmniAuth CAS Strategy [![Gem Version][version_badge]][version] [![Build Status][travis_status]][travis]
|
2
2
|
|
3
|
-
[version_badge]: https://badge.fury.io/rb/omniauth-cas.
|
4
|
-
[version]:
|
5
|
-
[travis]:
|
6
|
-
[travis_status]: https://secure.travis-ci.org/dlindahl/omniauth-cas.
|
3
|
+
[version_badge]: https://badge.fury.io/rb/omniauth-cas.svg
|
4
|
+
[version]: https://badge.fury.io/rb/omniauth-cas
|
5
|
+
[travis]: https://travis-ci.org/dlindahl/omniauth-cas
|
6
|
+
[travis_status]: https://secure.travis-ci.org/dlindahl/omniauth-cas.svg
|
7
|
+
[releases]: https://github.com/dlindahl/omniauth-cas/releases
|
7
8
|
|
8
9
|
This is a OmniAuth 1.0 compatible port of the previously available
|
9
10
|
[OmniAuth CAS strategy][old_omniauth_cas] that was bundled with OmniAuth 0.3.
|
10
11
|
|
11
|
-
[View the documentation][document_up]
|
12
|
+
* [View the documentation][document_up]
|
13
|
+
* [Changelog][releases]
|
12
14
|
|
13
15
|
## Installation
|
14
16
|
|
@@ -41,21 +43,49 @@ end
|
|
41
43
|
OmniAuth CAS requires at least one of the following two configuration options:
|
42
44
|
|
43
45
|
* `url` - Defines the URL of your CAS server (i.e. `http://example.org:8080`)
|
44
|
-
* `host` - Defines the host of your CAS server.
|
45
|
-
* `login_url` - Defines the URL used to prompt users for their login information. Defaults to `/login`
|
46
|
-
If no `host` is configured, the host application's domain will be used.
|
46
|
+
* `host` - Defines the host of your CAS server (i.e. `example.org`).
|
47
47
|
|
48
48
|
#### Optional
|
49
49
|
|
50
50
|
Other configuration options:
|
51
51
|
|
52
|
-
* `port` - The port to use for your configured CAS `host`. Optional if using `url
|
53
|
-
* `ssl` - TRUE to connect to your CAS server over SSL. Optional if using `url
|
54
|
-
* `service_validate_url` - The URL to use to validate a user. Defaults to `'/serviceValidate'
|
55
|
-
* `
|
56
|
-
* `
|
57
|
-
* `
|
52
|
+
* `port` - The port to use for your configured CAS `host`. Optional if using `url`.
|
53
|
+
* `ssl` - TRUE to connect to your CAS server over SSL. Optional if using `url`.
|
54
|
+
* `service_validate_url` - The URL to use to validate a user. Defaults to `'/serviceValidate'`.
|
55
|
+
* `callback_url` - The URL custom URL path which CAS uses to call back to the service. Defaults to `/users/auth/cas/callback`.
|
56
|
+
* `logout_url` - The URL to use to logout a user. Defaults to `'/logout'`.
|
57
|
+
* `login_url` - Defines the URL used to prompt users for their login information. Defaults to `/login` If no `host` is configured, the host application's domain will be used.
|
58
|
+
* `uid_field` - The user data attribute to use as your user's unique identifier. Defaults to `'user'` (which usually contains the user's login name).
|
59
|
+
* `ca_path` - Optional when `ssl` is `true`. Sets path of a CA certification directory. See [Net::HTTP][net_http] for more details.
|
58
60
|
* `disable_ssl_verification` - Optional when `ssl` is true. Disables verification.
|
61
|
+
* `merge_multivalued_attributes` - When set to `true` returns attributes with multiple values as arrays. Defaults to `false` and returns the last value as a string.
|
62
|
+
* `on_single_sign_out` - Optional. Callback used when a [CAS 3.1 Single Sign Out][sso]
|
63
|
+
request is received.
|
64
|
+
* `fetch_raw_info` - Optional. Callback used to return additional "raw" user
|
65
|
+
info from other sources.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
provider :cas,
|
69
|
+
fetch_raw_info: Proc.new { |strategy, opts, ticket, user_info, rawxml|
|
70
|
+
return {} if user_info.empty? || rawxml.nil? # Auth failed
|
71
|
+
|
72
|
+
extra_info = ExternalService.get(user_info[:user]).attributes
|
73
|
+
extra_info.merge!({'roles' => rawxml.xpath('//cas:roles').map(&:text)})
|
74
|
+
extra_info
|
75
|
+
}
|
76
|
+
```
|
77
|
+
|
78
|
+
Configurable options for values returned by CAS:
|
79
|
+
|
80
|
+
* `uid_key` - The user ID data attribute to use as your user's unique identifier. Defaults to `'user'` (which usually contains the user's login name).
|
81
|
+
* `name_key` - The data attribute containing user first and last name. Defaults to `'name'`.
|
82
|
+
* `email_key` - The data attribute containing user email address. Defaults to `'email'`.
|
83
|
+
* `nickname_key` - The data attribute containing user's nickname. Defaults to `'user'`.
|
84
|
+
* `first_name_key` - The data attribute containing user first name. Defaults to `'first_name'`.
|
85
|
+
* `last_name_key` - The data attribute containing user last name. Defaults to `'last_name'`.
|
86
|
+
* `location_key` - The data attribute containing user location/address. Defaults to `'location'`.
|
87
|
+
* `image_key` - The data attribute containing user image/picture. Defaults to `'image'`.
|
88
|
+
* `phone_key` - The data attribute containing user contact phone number. Defaults to `'phone'`.
|
59
89
|
|
60
90
|
## Migrating from OmniAuth 0.3
|
61
91
|
|
@@ -93,5 +123,6 @@ Special thanks go out to the following people
|
|
93
123
|
* @rbq for README updates and OmniAuth 0.3 migration guide
|
94
124
|
|
95
125
|
[old_omniauth_cas]: https://github.com/intridea/omniauth/blob/0-3-stable/oa-enterprise/lib/omniauth/strategies/cas.rb
|
96
|
-
[document_up]:
|
97
|
-
[net_http]:
|
126
|
+
[document_up]: https://dlindahl.github.io/omniauth-cas/
|
127
|
+
[net_http]: https://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html
|
128
|
+
[sso]: https://wiki.jasig.org/display/CASUM/Single+Sign+Out
|
data/lib/omniauth-cas.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'omniauth/cas'
|
data/lib/omniauth/cas/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'omniauth
|
1
|
+
require 'omniauth'
|
2
2
|
require 'addressable/uri'
|
3
3
|
|
4
4
|
module OmniAuth
|
@@ -10,8 +10,8 @@ module OmniAuth
|
|
10
10
|
class MissingCASTicket < StandardError; end
|
11
11
|
class InvalidCASTicket < StandardError; end
|
12
12
|
|
13
|
-
autoload :Configuration, 'omniauth/strategies/cas/configuration'
|
14
13
|
autoload :ServiceTicketValidator, 'omniauth/strategies/cas/service_ticket_validator'
|
14
|
+
autoload :LogoutRequest, 'omniauth/strategies/cas/logout_request'
|
15
15
|
|
16
16
|
attr_accessor :raw_info
|
17
17
|
alias_method :user_info, :raw_info
|
@@ -22,84 +22,125 @@ module OmniAuth
|
|
22
22
|
option :port, nil
|
23
23
|
option :path, nil
|
24
24
|
option :ssl, true
|
25
|
+
option :merge_multivalued_attributes, false
|
25
26
|
option :service_validate_url, '/serviceValidate'
|
26
27
|
option :login_url, '/login'
|
27
28
|
option :logout_url, '/logout'
|
28
|
-
option :
|
29
|
+
option :on_single_sign_out, Proc.new {}
|
30
|
+
# A Proc or lambda that returns a Hash of additional user info to be
|
31
|
+
# merged with the info returned by the CAS server.
|
32
|
+
#
|
33
|
+
# @param [Object] An instance of OmniAuth::Strategies::CAS for the current request
|
34
|
+
# @param [String] The user's Service Ticket value
|
35
|
+
# @param [Hash] The user info for the Service Ticket returned by the CAS server
|
36
|
+
#
|
37
|
+
# @return [Hash] Extra user info
|
38
|
+
option :fetch_raw_info, Proc.new { Hash.new }
|
39
|
+
# Make all the keys configurable with some defaults set here
|
40
|
+
option :uid_field, 'user'
|
41
|
+
option :name_key, 'name'
|
42
|
+
option :email_key, 'email'
|
43
|
+
option :nickname_key, 'user'
|
44
|
+
option :first_name_key, 'first_name'
|
45
|
+
option :last_name_key, 'last_name'
|
46
|
+
option :location_key, 'location'
|
47
|
+
option :image_key, 'image'
|
48
|
+
option :phone_key, 'phone'
|
29
49
|
|
30
50
|
# As required by https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
|
31
|
-
AuthHashSchemaKeys = %w{name email first_name last_name location image phone}
|
51
|
+
AuthHashSchemaKeys = %w{name email nickname first_name last_name location image phone}
|
32
52
|
info do
|
33
53
|
prune!({
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
38
|
-
:
|
39
|
-
:
|
40
|
-
:
|
54
|
+
name: raw_info[options[:name_key].to_s],
|
55
|
+
email: raw_info[options[:email_key].to_s],
|
56
|
+
nickname: raw_info[options[:nickname_key].to_s],
|
57
|
+
first_name: raw_info[options[:first_name_key].to_s],
|
58
|
+
last_name: raw_info[options[:last_name_key].to_s],
|
59
|
+
location: raw_info[options[:location_key].to_s],
|
60
|
+
image: raw_info[options[:image_key].to_s],
|
61
|
+
phone: raw_info[options[:phone_key].to_s]
|
41
62
|
})
|
42
63
|
end
|
43
64
|
|
44
65
|
extra do
|
45
|
-
prune!
|
66
|
+
prune!(
|
67
|
+
raw_info.delete_if{ |k,v| AuthHashSchemaKeys.include?(k) }
|
68
|
+
)
|
46
69
|
end
|
47
70
|
|
48
71
|
uid do
|
49
|
-
raw_info[
|
72
|
+
raw_info[options[:uid_field].to_s]
|
50
73
|
end
|
51
74
|
|
52
75
|
credentials do
|
53
|
-
prune!({
|
54
|
-
:ticket => @ticket
|
55
|
-
})
|
56
|
-
end
|
57
|
-
|
58
|
-
def initialize( app, *args, &block )
|
59
|
-
super
|
60
|
-
@configuration = Configuration.new( @options )
|
76
|
+
prune!({ ticket: @ticket })
|
61
77
|
end
|
62
78
|
|
63
79
|
def callback_phase
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
80
|
+
if on_sso_path?
|
81
|
+
single_sign_out_phase
|
82
|
+
else
|
83
|
+
@ticket = request.params['ticket']
|
84
|
+
return fail!(:no_ticket, MissingCASTicket.new('No CAS Ticket')) unless @ticket
|
85
|
+
fetch_raw_info(@ticket)
|
86
|
+
return fail!(:invalid_ticket, InvalidCASTicket.new('Invalid CAS Ticket')) if raw_info.empty?
|
87
|
+
super
|
88
|
+
end
|
73
89
|
end
|
74
90
|
|
75
91
|
def request_phase
|
76
|
-
service_url = append_params(
|
92
|
+
service_url = append_params(callback_url, return_url)
|
77
93
|
|
78
94
|
[
|
79
95
|
302,
|
80
96
|
{
|
81
|
-
'Location' => login_url(
|
97
|
+
'Location' => login_url(service_url),
|
82
98
|
'Content-Type' => 'text/plain'
|
83
99
|
},
|
84
100
|
["You are being redirected to CAS for sign-in."]
|
85
101
|
]
|
86
102
|
end
|
87
103
|
|
104
|
+
def on_sso_path?
|
105
|
+
request.post? && request.params.has_key?('logoutRequest')
|
106
|
+
end
|
107
|
+
|
108
|
+
def single_sign_out_phase
|
109
|
+
logout_request_service.new(self, request).call(options)
|
110
|
+
end
|
111
|
+
|
88
112
|
# Build a CAS host with protocol and port
|
89
113
|
#
|
90
114
|
#
|
91
115
|
def cas_url
|
116
|
+
extract_url if options['url']
|
117
|
+
validate_cas_setup
|
92
118
|
@cas_url ||= begin
|
93
119
|
uri = Addressable::URI.new
|
94
|
-
uri.host
|
95
|
-
uri.scheme =
|
96
|
-
uri.port
|
97
|
-
uri.path
|
98
|
-
|
120
|
+
uri.host = options.host
|
121
|
+
uri.scheme = options.ssl ? 'https' : 'http'
|
122
|
+
uri.port = options.port
|
123
|
+
uri.path = options.path
|
99
124
|
uri.to_s
|
100
125
|
end
|
101
126
|
end
|
102
127
|
|
128
|
+
def extract_url
|
129
|
+
url = Addressable::URI.parse(options.delete('url'))
|
130
|
+
options.merge!(
|
131
|
+
'host' => url.host,
|
132
|
+
'port' => url.port,
|
133
|
+
'path' => url.path,
|
134
|
+
'ssl' => url.scheme == 'https'
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
def validate_cas_setup
|
139
|
+
if options.host.nil? || options.login_url.nil?
|
140
|
+
raise ArgumentError.new(":host and :login_url MUST be provided")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
103
144
|
# Build a service-validation URL from +service+ and +ticket+.
|
104
145
|
# If +service+ has a ticket param, first remove it. URL-encode
|
105
146
|
# +service+ and add it and the +ticket+ as paraemters to the
|
@@ -110,10 +151,12 @@ module OmniAuth
|
|
110
151
|
#
|
111
152
|
# @return [String] a URL like `http://cas.mycompany.com/serviceValidate?service=...&ticket=...`
|
112
153
|
def service_validate_url(service_url, ticket)
|
113
|
-
service_url = Addressable::URI.parse(
|
154
|
+
service_url = Addressable::URI.parse(service_url)
|
114
155
|
service_url.query_values = service_url.query_values.tap { |qs| qs.delete('ticket') }
|
115
|
-
|
116
|
-
|
156
|
+
cas_url + append_params(options.service_validate_url, {
|
157
|
+
service: service_url.to_s,
|
158
|
+
ticket: ticket
|
159
|
+
})
|
117
160
|
end
|
118
161
|
|
119
162
|
# Build a CAS login URL from +service+.
|
@@ -122,7 +165,7 @@ module OmniAuth
|
|
122
165
|
#
|
123
166
|
# @return [String] a URL like `http://cas.mycompany.com/login?service=...`
|
124
167
|
def login_url(service)
|
125
|
-
cas_url + append_params(
|
168
|
+
cas_url + append_params(options.login_url, { service: service })
|
126
169
|
end
|
127
170
|
|
128
171
|
# Adds URL-escaped +parameters+ to +base+.
|
@@ -133,14 +176,28 @@ module OmniAuth
|
|
133
176
|
# @return [String] the new joined URL.
|
134
177
|
def append_params(base, params)
|
135
178
|
params = params.each { |k,v| v = Rack::Utils.escape(v) }
|
136
|
-
|
137
179
|
Addressable::URI.parse(base).tap do |base_uri|
|
138
|
-
base_uri.query_values = (base_uri.query_values || {}).merge(
|
180
|
+
base_uri.query_values = (base_uri.query_values || {}).merge(params)
|
139
181
|
end.to_s
|
140
182
|
end
|
141
183
|
|
184
|
+
# Validate the Service Ticket
|
185
|
+
# @return [Object] the validated Service Ticket
|
186
|
+
def validate_service_ticket(ticket)
|
187
|
+
ServiceTicketValidator.new(self, options, callback_url, ticket).call
|
188
|
+
end
|
189
|
+
|
142
190
|
private
|
143
191
|
|
192
|
+
def fetch_raw_info(ticket)
|
193
|
+
validator = validate_service_ticket(ticket)
|
194
|
+
ticket_user_info = validator.user_info
|
195
|
+
ticket_success_body = validator.success_body
|
196
|
+
custom_user_info = options.fetch_raw_info.call(self,
|
197
|
+
options, ticket, ticket_user_info, ticket_success_body)
|
198
|
+
self.raw_info = ticket_user_info.merge(custom_user_info)
|
199
|
+
end
|
200
|
+
|
144
201
|
# Deletes Hash pairs with `nil` values.
|
145
202
|
# From https://github.com/mkdynamic/omniauth-facebook/blob/972ed5e3456bcaed7df1f55efd7c05c216c8f48e/lib/omniauth/strategies/facebook.rb#L122-127
|
146
203
|
def prune!(hash)
|
@@ -152,13 +209,16 @@ module OmniAuth
|
|
152
209
|
|
153
210
|
def return_url
|
154
211
|
# If the request already has a `url` parameter, then it will already be appended to the callback URL.
|
155
|
-
if request.params
|
212
|
+
if request.params && request.params['url']
|
156
213
|
{}
|
157
214
|
else
|
158
|
-
{ :
|
215
|
+
{ url: request.referer }
|
159
216
|
end
|
160
217
|
end
|
161
218
|
|
219
|
+
def logout_request_service
|
220
|
+
LogoutRequest
|
221
|
+
end
|
162
222
|
end
|
163
223
|
end
|
164
224
|
end
|