rubycas-client 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,62 +1,82 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.2
3
- specification_version: 1
4
2
  name: rubycas-client
5
3
  version: !ruby/object:Gem::Version
6
- version: 1.1.0
7
- date: 2007-12-21 12:37:15.306028 -05:00
8
- summary: Client library for the CAS single-sign-on protocol.
9
- require_paths:
10
- - lib
11
- email: matt@roughest.net
12
- homepage: http://rubycas-client.rubyforge.org
13
- rubyforge_project: rubycas-client
14
- description: RubyCAS-Client is a Ruby client library for Yale's Central Authentication Service (CAS) single-sign-on protocol for web-based applications.
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 2.0.0
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Matt Zukowski
31
- - Ola Bini
32
8
  - Matt Walker
33
- files:
34
- - install.rb
35
- - init.rb
36
- - lib/cas.rb
37
- - lib/cas_proxy_callback_controller.rb
38
- - lib/cas_auth.rb
39
- - lib/cas_logger.rb
40
- - CHANGES
41
- - Rakefile
42
- - README
43
- - LICENSE
44
- test_files: []
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
45
12
 
46
- rdoc_options:
47
- - --title
48
- - RubyCAS-Client RDocs
49
- - --main
50
- - README
51
- - --line-numbers
52
- extra_rdoc_files:
53
- - README
54
- - LICENSE
13
+ date: 2008-02-19 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activesupport
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Client library for the Central Authentication Service (CAS) protocol.
26
+ email: matt at roughest dot net
55
27
  executables: []
56
28
 
57
29
  extensions: []
58
30
 
31
+ extra_rdoc_files:
32
+ - CHANGELOG.txt
33
+ - History.txt
34
+ - LICENSE.txt
35
+ - Manifest.txt
36
+ - README.txt
37
+ files:
38
+ - CHANGELOG.txt
39
+ - History.txt
40
+ - LICENSE.txt
41
+ - Manifest.txt
42
+ - README.txt
43
+ - Rakefile
44
+ - init.rb
45
+ - lib/casclient.rb
46
+ - lib/casclient/client.rb
47
+ - lib/casclient/frameworks/rails/cas_proxy_callback_controller.rb
48
+ - lib/casclient/frameworks/rails/filter.rb
49
+ - lib/casclient/responses.rb
50
+ - lib/casclient/tickets.rb
51
+ - lib/casclient/version.rb
52
+ - lib/rubycas-client.rb
53
+ - setup.rb
54
+ has_rdoc: true
55
+ homepage: http://rubycas-client.rubyforge.org
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --main
59
+ - README.txt
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
59
74
  requirements: []
60
75
 
61
- dependencies: []
76
+ rubyforge_project: rubycas-client
77
+ rubygems_version: 1.0.1
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: Client library for the Central Authentication Service (CAS) protocol.
81
+ test_files: []
62
82
 
data/README DELETED
@@ -1,223 +0,0 @@
1
- = RubyCAS-Client
2
-
3
- Author:: Matt Zukowski <matt AT roughest DOT net>, Ola Bini <ola.bini AT ki DOT se>, Matt Walker <mwalker AT tamu DOT edu>
4
- Copyright:: (c) 2006 Karolinska Institutet, portions (c) 2006 Urbacon Ltd.
5
- License:: GNU Lesser General Public License v2.1 (LGPL 2.1)
6
- Website:: http://rubyforge.org/projects/rubycas-client and http://code.google.com/p/rubycas-client
7
-
8
- === RubyCAS-Client is a Ruby client library for Yale's Central Authentication Service (CAS) protocol.
9
-
10
- CAS provides a solid and secure single sign on solution for web-based applications. When a user logs on to your
11
- CAS-enabled website, the CAS client checks with the CAS server to see if the user has been centrally authenticated.
12
- If not, the user is redirected to your CAS server's web-based login page where they enter their credentials, and upon
13
- successful authentication are redirected back to your client web application. If the user has been previously
14
- authenticated with the CAS server (with their "ticket" being held as a session cookie), they are transparently
15
- allowed to go about their business.
16
-
17
- This client requires a CAS server to talk to. You can obtain a Java implementation of such a server as well as more info
18
- about the CAS protocol here: http://www.ja-sig.org/products/cas
19
-
20
- This CAS client library is designed to work easily with Rails, but can of course be used elsewhere.
21
-
22
- == Installing
23
-
24
- You can always download the latest version of RubyCAS-Client from the project's rubyforge page at http://rubyforge.org/projects/rubycas-client.
25
- However, probably the easiest way to install CAS support into your Rails app is via the plugins facility:
26
-
27
- ./script/plugin install http://rubycas-client.googlecode.com/svn/trunk/rubycas-client
28
-
29
- Alternatively, the library is also available as a gem, which can be installed by:
30
-
31
- gem install rubycas-client
32
-
33
- If your Rails application is under Subversion control, you can also install the plugin as an svn:external, which will ensure that
34
- you always have the latest version of RubyCAS-Client:
35
-
36
- ./script/plugin install -x http://rubycas-client.googlecode.com/svn/trunk/rubycas-client
37
-
38
- Please contact the developers via the {RubyForge page}[http://rubyforge.org/projects/rubycas-client] if you have bug fixes
39
- or enhancements you would like to contribute back.
40
-
41
- == Examples
42
-
43
- ==== Using RubyCAS-Client in Rails controllers
44
-
45
- <i>Note that from this point on we are assuming that you have a working CAS server up and running at an https URI.</i>
46
-
47
- Somewhere in your <tt>config/environment.rb</tt> file add this:
48
-
49
- require 'cas_auth'
50
- CAS::Filter.cas_base_url = "https://login.example.com/cas"
51
-
52
- You will also need to specify the server name where your CAS-protected app is running (i.e. the hostname of the app you are
53
- adding CAS protection to, not the CAS server):
54
-
55
- CAS::Filter.server_name = "yourapplication.example.com:3000"
56
-
57
- Then, in your <tt>app/controllers/application.rb</tt> (or in whatever controller you want to add the CAS filter for):
58
-
59
- before_filter CAS::Filter
60
-
61
- That's it. You should now find that you are redirected to your CAS login page whenever you try to access any action
62
- in your protected controller. You can of course qualify the <tt>before_filter</tt> as you would with any other ActionController
63
- filter. For example:
64
-
65
- before_filter CAS::Filter, :except => [ :unprotected_action, :another_unprotected_action ]
66
-
67
- <b>Once the user has been authenticated, their authenticated username is available under <tt>request.username</tt></b>
68
- (and also under <tt>session[:casfilteruser]</tt>). If you want to do something with this username (for example load a
69
- user record from the database), you can append another filter method that checks for this value and does whatever you need
70
- it to do.
71
-
72
- ==== A more complicated example
73
-
74
- Here is a more complicated configuration showing most of the configuration options (this does not show proxy options however,
75
- which are covered in the next section):
76
-
77
- CAS::Filter.login_url = "https://login.example.com/cas/login" # the URI of the CAS login page
78
- CAS::Filter.validate_url = "https://login.example.com/cas/serviceValidate" # the URI where CAS ticket validation requests are sent
79
- CAS::Filter.server_name = "yourapplication.example.com:3000" # the server name of your CAS-protected application
80
- CAS::Filter.renew = false # force re-authentication? see http://www.ja-sig.org/products/cas/overview/protocol
81
- CAS::Filter.wrap_request = true # make the username available under request.username?
82
- CAS::Filter.gateway = false # act as cas gateway? see http://www.ja-sig.org/products/cas/overview/protocol
83
- CAS::Filter.session_username = :casfilteruser # this is the hash in the session where the authenticated username will be stored
84
-
85
- Note that in this example we explicitly specified the login and validate URLs instead of letting RubyCAS-Client figure them out
86
- based on <tt>CAS::Filter.cas_base_url</tt>.
87
-
88
- ==== Defining a 'logout' action
89
-
90
- Your Rails application's controller(s) will probably have some sort of logout function. In it you will likely want reset the
91
- user's session for your application, and then redirect to the CAS server's logout URL. Here's an example of how to do this:
92
-
93
- def logout
94
- reset_session
95
- redirect_to CAS::Filter.logout_url(self, request.referer)
96
- end
97
-
98
- ==== Gatewayed authentication
99
-
100
- RubyCAS-Client supports gatewaying as of version 1.1.0. Gatewaying allows for optional CAS authentication, so that users who
101
- already have a pre-existing CAS SSO session will be automatically authenticated for the gatewayed service, while those who
102
- do not, will be allowed to access the service without authentication. This is useful for example when you want to show
103
- some additional private content on a homepage to authenticated users, but also want unauthenticated users to be able to
104
- access the page without first logging in.
105
-
106
- For more information on using gatewaying, see CAS::GatewayFilter.
107
-
108
- ==== How to act as a CAS proxy
109
-
110
- CAS 2.0 has a built-in mechanism that allows a CAS-authenticated application to pass on its authentication to other applications.
111
- An example where this is useful might be a portal site, where the user logs in to a central website and then gets forwarded to
112
- various other sites that run independently of the portal system (but are always accessed via the portal). The exact mechanism
113
- behind this is rather complicated so I won't go over it here. If you wish to learn more about CAS proxying, a great walkthrough
114
- is available at http://www.ja-sig.org/wiki/display/CAS/Proxy+CAS+Walkthrough.
115
-
116
- RubyCAS-Client fully supports proxying, so a CAS-protected Rails application can act as a CAS proxy.
117
-
118
- Additionally, RubyCAS-Client comes with a controller that can act as a CAS proxy callback receiver. This is necessary because
119
- when your application requests to act as a CAS proxy, the CAS server must contact your application to deposit the proxy-granting-ticket
120
- (PGT). Note that in this case the CAS server CONTACTS YOU, rather than you contacting the CAS server (as in all other CAS operations).
121
-
122
- Confused? Don't worry, you don't really have to understand this to use it. To enable your Rails app to act as a CAS proxy,
123
- all you need to do is this:
124
-
125
- In your <tt>config/environment.rb</tt>:
126
-
127
- CAS::Filter.cas_base_url = "https://login.example.com/cas"
128
- CAS::Filter.proxy_callback_url = "https://yourrailsapp.com/cas_proxy_callback/receive_pgt"
129
- CAS::Filter.proxy_retrieval_url = "https://yourrailsapp.com/cas_proxy_callback/retrieve_pgt"
130
-
131
- In <tt>config/routes.rb</tt> make sure that you have a route that will allow requests to /cas_proxy_callback/:action to be routed to the
132
- CasProxyCallbackController. This should work as-is with the standard Rails routes setup, but if you have disabled the default
133
- route, you should add the following:
134
-
135
- map.cas_proxy_callback 'cas_proxy_callback/:action', :controller => 'cas_proxy_callback'
136
-
137
- Now here's a big giant caveat: <b>your CAS callback application and your CAS proxy application must run on separate Rails servers</b>.
138
- In other words, if you want a Rails app to act as a CAS ticket-granting proxy, the cas_proxy_callback controller
139
- must run on a different server. This is because Rails does not properly support handling of concurrent requests. The CAS proxy mechanism
140
- acts in such a way that if your proxy application and your callback controller were on the same server
141
- you would end up with a deadlock (the CAS server would be waiting for its callback to be accepted by your Rails server,
142
- but your Rails server wouldn't respond to the CAS server's callback until the CAS server responded back first).
143
-
144
- The simplest workaround is this:
145
-
146
- 1. Create an empty rails app (i.e. something like <tt>rails cas_proxy_callback</tt>)
147
- 2. Make sure that you have the CAS plugin installed. If you installed it as a gem, you don't have to do anything since
148
- it is already installed. If you want to install as a plugin, see the instructions in the "Installing" section above.
149
- 3. Make sure that the server is up and running, and configure your proxy_callback_url and proxy_retrieval_url to point
150
- to the new server as described above (or rather, make Pound point to the new server, if that's how you're handling https).
151
-
152
- That's it. The proxy_callback_controller doesn't require any additional configuration. It doesn't access the database
153
- or anything of that sort.
154
-
155
- Once your user logs in to CAS via your application, you can do the following to obtain a service ticket that can then be used
156
- to authenticate another application:
157
-
158
- service_uri = "http://some.other.application"
159
- proxy_granting_ticket = session[:casfilterpgt]
160
- ticket = CAS::Filter.request_proxy_ticket(service_uri, proxy_granting_ticket).proxy_ticket
161
-
162
- <tt>ticket</tt> should now contain a valid service ticket. You can use it to authenticate by sending it and the service URI
163
- as query parameters to your target application:
164
-
165
- http://some.other.application?service=#{CGI.encode(ticket.target_service)}&ticket=#{ticket.proxy_ticket}
166
-
167
- This is of course assuming that some.other.application is also protected by the CAS filter.
168
- Note that you should always URI-encode your service parameter inside URIs!
169
-
170
- Note that CAS::Filter#request_proxy_ticket actually returns a CAS::ProxyTicketRequest object, which is why we need to call
171
- #proxy_ticket on it to retrieve the actual service ticket.
172
-
173
- For extra security -- and you will likely want to do this on production machines in the wild -- in the proxied app's configuration
174
- (some.other.appliction in this example) you can specify the list of authorized proxies. For example, on your proxied app the CAS
175
- configuration might look something like this:
176
-
177
- CAS::Filter.cas_base_url = "https://login.example.com/cas"
178
- CAS::Filter.server_name = "some.other.application"
179
- CAS::Filter.authorized_proxies = ["https://yourrailsapp.com/cas/proxy_callback/receive_pgt"]
180
-
181
- If no authorized proxies are given, the filter will accept receipts from any proxy.
182
-
183
- ===== Additional notes and caveats:
184
-
185
- Note that when the CAS filter runs, the PGT is stored in session[:casfilterpgt]. This value must be passed to CAS::Filter#request_proxy_ticket.
186
- Also, note that CAS::Filter#request_proxy_ticket will URI-encode the service_uri before passing it to the CAS server, and the service
187
- value must henceforth always be passed as URI-encoded (this can be problematic when your proxied application uses some CAS client other than
188
- RubyCAS-Client).
189
-
190
- <b>The proxy url must be an https address.</b> Otherwise CAS will refuse to communicate with it. This means that if you are using
191
- the bundled cas_proxy_callback controller, you will have to host your application on an https-enabled server. This can be a bit
192
- tricky with Rails. WEBrick's SSL support is difficult to configure, and Mongrel doesn't support SSL at all. One workaround is to
193
- use a reverse proxy like Pound[http://www.apsis.ch/pound/], which will accept https connections and locally re-route them
194
- to your Rails application. Also, note that <i>self-signed SSL certificates likely won't work</i>. You will probably need to use
195
- a real certificate purchased from a trusted CA authority (there are ways around this, but good luck :)
196
-
197
-
198
- == SSL Support
199
-
200
- If you are getting an error on net/https -- something like this:
201
-
202
- no such file to load -- net/https
203
-
204
- Then make sure the library for open SSL is installed. For example, on an Debian/Ubuntu system issue the following:
205
-
206
- sudo apt-get install libopenssl-ruby
207
-
208
-
209
- == License
210
-
211
- This program is free software; you can redistribute it and/or modify
212
- it under the terms of the GNU Lesser General Public License as published by
213
- the Free Software Foundation; either version 2 of the License, or
214
- (at your option) any later version.
215
-
216
- This program is distributed in the hope that it will be useful,
217
- but WITHOUT ANY WARRANTY; without even the implied warranty of
218
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
219
- GNU General Public License for more details.
220
-
221
- You should have received a copy of the GNU Lesser General Public License
222
- along with this program (see the file called LICENSE); if not, write to the
223
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
data/install.rb DELETED
@@ -1,5 +0,0 @@
1
- # Install hook code here
2
- #parent_dir = File.dirname(File.expand_path(__FILE__))
3
- #grandparent_dir = File.dirname(parent_dir)
4
- #
5
- #File.rename(parent_dir, grandparent_dir+"/rubycas-client")
data/lib/cas.rb DELETED
@@ -1,194 +0,0 @@
1
- require 'net/https'
2
- require 'rexml/document'
3
-
4
- module CAS
5
- class CASException < Exception
6
- end
7
- class AuthenticationException < CASException
8
- end
9
- class ValidationException < CASException
10
- end
11
- class MalformedServerResponseException < CASException
12
- end
13
-
14
- class Receipt
15
- attr_accessor :validate_url, :pgt_iou, :primary_authentication, :proxy_callback_url, :proxy_list, :user_name
16
-
17
- def primary_authentication?
18
- primary_authentication
19
- end
20
-
21
- def initialize(ptv)
22
- if !ptv.successful_authentication?
23
- begin
24
- ptv.validate
25
- rescue ValidationException=>vald
26
- raise AuthenticationException, "Unable to validate ProxyTicketValidator [#{ptv}] [#{vald}]"
27
- end
28
- raise AuthenticationException, "Unable to validate ProxyTicketValidator because of no success with validation[#{ptv}]" unless ptv.successful_authentication?
29
- end
30
- self.validate_url = ptv.validate_url
31
- self.pgt_iou = ptv.pgt_iou
32
- self.user_name = ptv.user
33
- self.proxy_callback_url = ptv.proxy_callback_url
34
- self.proxy_list = ptv.proxy_list
35
- self.primary_authentication = ptv.renewed?
36
- raise AuthenticationException, "Validation of [#{ptv}] did not result in an internally consistent Receipt" unless validate
37
- end
38
-
39
- def proxied?
40
- !proxy_list.empty?
41
- end
42
-
43
- def proxying_service
44
- proxy_list.first
45
- end
46
-
47
- def to_s
48
- "[#{super} - userName=[#{user_name}] validateUrl=[#{validate_url}] proxyCallbackUrl=[#{proxy_callback_url}] pgtIou=[#{pgt_iou}] proxyList=[#{proxy_list}]"
49
- end
50
-
51
- def validate
52
- user_name &&
53
- validate_url &&
54
- proxy_list &&
55
- !(primary_authentication? && !proxy_list.empty?) # May not be both primary authenitication and proxied.
56
- end
57
- end
58
-
59
- class AbstractCASResponse
60
- attr_reader :error_code, :error_message, :successful_authentication
61
-
62
- def self.retrieve(uri_str)
63
- prs = URI.parse(uri_str)
64
- https = Net::HTTP.new(prs.host,prs.port)
65
- https.use_ssl = (prs.scheme == 'https') # patch by rubywmg to allow non-SSL URLs for demo purposes
66
- https.start { |conn|
67
- # TODO: make sure that HTTP status code in the response is 200... maybe throw exception if is 500?
68
- conn.get("#{prs.path}?#{prs.query}").body.strip
69
- }
70
- end
71
-
72
- protected
73
- def parse_unsuccessful(elm)
74
- @error_message = elm.text.strip
75
- @error_code = elm.attributes["code"].strip
76
- @successful_authentication = false
77
- end
78
-
79
- def parse(str)
80
- begin
81
- doc = REXML::Document.new str
82
- rescue REXML::ParseException => e
83
- raise MalformedServerResponseException, "BAD RESPONSE FROM CAS SERVER:\n#{str.inspect}\n\nEXCEPTION:\n#{e}"
84
- end
85
-
86
- unless doc.elements && doc.elements["cas:serviceResponse"]
87
- raise MalformedServerResponseException, "BAD RESPONSE FROM CAS SERVER:\n#{str.inspect}\n\nXML DOC:\n#{doc.inspect}"
88
- end
89
-
90
- resp = doc.elements["cas:serviceResponse"].elements[1]
91
-
92
- if successful_response? resp
93
- parse_successful(resp)
94
- else
95
- parse_unsuccessful(resp)
96
- end
97
- end
98
- end
99
-
100
- class ServiceTicketValidator < AbstractCASResponse
101
- attr_accessor :validate_url, :proxy_callback_url, :renew, :service_ticket, :service
102
- attr_reader :pgt_iou, :user, :entire_response
103
-
104
- def renewed?
105
- renew
106
- end
107
-
108
- def successful_authentication?
109
- successful_authentication
110
- end
111
-
112
- def validate
113
- raise ValidationException, "must set validation URL and ticket" if validate_url.nil? || service_ticket.nil?
114
- clear!
115
- @attempted_authentication = true
116
- url_building = "#{validate_url}#{(url_building =~ /\?/)?'&':'?'}service=#{CGI.escape(service)}&ticket=#{service_ticket}"
117
- url_building += "&pgtUrl=#{proxy_callback_url}" if proxy_callback_url
118
- url_building += "&renew=true" if renew
119
- @@entire_response = ServiceTicketValidator.retrieve url_building
120
- parse @@entire_response
121
- end
122
-
123
- def clear!
124
- @user = @pgt_iou = @error_message = nil
125
- @successful_authentication = @attempted_authentication = false
126
- end
127
-
128
- def to_s
129
- "[#{super} - validateUrl=[#{validate_url}] proxyCallbackUrl=[#{proxy_callback_url}] ticket=[#{service_ticket}] service=[#{service} pgtIou=[#{pgt_iou}] user=[#{user}] errorCode=[#{error_message}] errorMessage=[#{error_message}] renew=[#{renew}] entireResponse=[#{entire_response}]]"
130
- end
131
-
132
- protected
133
- def parse_successful(elm)
134
- # puts "successful"
135
- @user = elm.elements["cas:user"] && elm.elements["cas:user"].text.strip
136
- # puts "user: #{@user}"
137
- @pgt_iou = elm.elements["cas:proxyGrantingTicket"] && elm.elements["cas:proxyGrantingTicket"].text.strip
138
- # puts "pgt_iou: #{@pgt_iou}"
139
- @successful_authentication = true
140
- end
141
-
142
- def successful_response?(resp)
143
- resp.name == "authenticationSuccess"
144
- end
145
- end
146
-
147
- class ProxyTicketValidator < ServiceTicketValidator
148
- attr_reader :proxy_list
149
- @@response_prefix = "proxy"
150
-
151
- def initialize
152
- super
153
- @proxy_list = []
154
- end
155
-
156
- def clear!
157
- super
158
- @proxy_list = []
159
- end
160
-
161
- protected
162
- def parse_successful(elm)
163
- super(elm)
164
-
165
- proxies = elm.elements["cas:proxies"]
166
- if proxies
167
- proxies.elements.each("cas:proxy") { |prox|
168
- @proxy_list ||= []
169
- @proxy_list << prox.text.strip
170
- }
171
- end
172
- end
173
- end
174
-
175
- class ProxyTicketRequest < AbstractCASResponse
176
- attr_accessor :proxy_url, :target_service, :pgt
177
- attr_reader :proxy_ticket
178
-
179
- def request
180
- url_building = "#{proxy_url}#{(url_building =~ /\?/)?'&':'?'}pgt=#{pgt}&targetService=#{CGI.escape(target_service)}"
181
- @@entire_response = ServiceTicketValidator.retrieve url_building
182
- parse @@entire_response
183
- end
184
-
185
- protected
186
- def parse_successful(elm)
187
- @proxy_ticket = elm.elements["cas:proxyTicket"] && elm.elements["cas:proxyTicket"].text.strip
188
- end
189
-
190
- def successful_response?(resp)
191
- resp.name == "proxySuccess"
192
- end
193
- end
194
- end