rubycas-client-rails-vpsa 0.1.1

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.
data/.project ADDED
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>rubycas-client-rails</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>com.aptana.ide.core.unifiedBuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>org.radrails.rails.core.railsnature</nature>
16
+ <nature>com.aptana.ruby.core.rubynature</nature>
17
+ </natures>
18
+ </projectDescription>
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 University of Toronto
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,4 @@
1
+ RubyCAS-Client-Rails
2
+ ====================
3
+
4
+ Fork do projeto [RubyCAS-Client-Rails](https://github.com/rubycas/rubycas-client-rails) adaptado para a VPSA.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the rubycas_client_rails plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the rubycas_client_rails plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'RubycasClientRails'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ # Include hook code here
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,430 @@
1
+
2
+ require 'casclient'
3
+
4
+ module RubyCAS
5
+ class Railtie < Rails::Railtie
6
+ config.rubycas = ActiveSupport::OrderedOptions.new
7
+
8
+ initializer 'rubycas.initialize' do |app|
9
+ RubyCAS::Filter.setup(config.rubycas)
10
+ end
11
+ end
12
+
13
+ class Filter
14
+ cattr_reader :config, :log, :client
15
+
16
+ # These are initialized when you call setup.
17
+ @@client = nil
18
+ @@log = nil
19
+ @@fake_user = nil
20
+ @@fake_extra_attributes = nil
21
+
22
+ class << self
23
+ def setup(config)
24
+ @@config = config
25
+ @@config[:logger] = Rails.logger unless @@config[:logger]
26
+ @@client = CASClient::Client.new(@@config)
27
+ @@log = @@client.log
28
+ end
29
+
30
+ def filter(controller)
31
+ raise "Cannot use the CASClient filter because it has not yet been configured." if config.nil?
32
+
33
+ if @@fake_user
34
+ controller.session[client.username_session_key] = @@fake_user
35
+ controller.session[:casfilteruser] = @@fake_user
36
+ controller.session[client.extra_attributes_session_key] = @@fake_extra_attributes
37
+ return true
38
+ end
39
+
40
+ ### patch this line to recreate the 2 items from cookie
41
+ last_st = controller.session[:cas_last_valid_ticket]
42
+ last_st_service = controller.session[:cas_last_valid_ticket_service]
43
+
44
+ if single_sign_out(controller)
45
+ controller.send(:render, :text => "CAS Single-Sign-Out request intercepted.")
46
+ return false
47
+ end
48
+
49
+ st = read_ticket(controller)
50
+
51
+ # is_new_session = true
52
+
53
+ if st && last_st &&
54
+ last_st == st.ticket &&
55
+ last_st_service == st.service
56
+ # warn() rather than info() because we really shouldn't be re-validating the same ticket.
57
+ # The only situation where this is acceptable is if the user manually does a refresh and
58
+ # the same ticket happens to be in the URL.
59
+ log.warn("Re-using previously validated ticket since the ticket id and service are the same.")
60
+ #st = last_st
61
+ return true
62
+ elsif last_st &&
63
+ !config[:authenticate_on_every_request] &&
64
+ controller.session[client.username_session_key]
65
+ # Re-use the previous ticket if the user already has a local CAS session (i.e. if they were already
66
+ # previously authenticated for this service). This is to prevent redirection to the CAS server on every
67
+ # request.
68
+ #
69
+ # This behaviour can be disabled (so that every request is routed through the CAS server) by setting
70
+ # the :authenticate_on_every_request config option to true. However, this is not desirable since
71
+ # it will almost certainly break POST request, AJAX calls, etc.
72
+ log.debug "Existing local CAS session detected for #{controller.session[client.username_session_key].inspect}. "+
73
+ "Previous ticket #{last_st_service} will be re-used."
74
+ #st = last_st
75
+ return true
76
+ end
77
+
78
+ if st
79
+ client.validate_service_ticket(st) unless st.has_been_validated?
80
+ #vr = st.success
81
+
82
+ if st.is_valid?
83
+ #if is_new_session
84
+ log.info("Ticket #{st.ticket.inspect} for service #{st.service.inspect} belonging to user #{st.user.inspect} is VALID.")
85
+ controller.session[client.username_session_key] = st.user.dup
86
+ controller.session[client.extra_attributes_session_key] = HashWithIndifferentAccess.new(st.extra_attributes) if st.extra_attributes
87
+
88
+ if st.extra_attributes
89
+ log.debug("Extra user attributes provided along with ticket #{st.ticket.inspect}: #{st.extra_attributes.inspect}.")
90
+ end
91
+
92
+ # RubyCAS-Client 1.x used :casfilteruser as it's username session key,
93
+ # so we need to set this here to ensure compatibility with configurations
94
+ # built around the old client.
95
+ controller.session[:casfilteruser] = st.user
96
+
97
+ if config[:enable_single_sign_out]
98
+ f = store_service_session_lookup(st, controller.request.session_options[:id] || controller.session.session_id)
99
+ log.debug("Wrote service session lookup file to #{f.inspect} with session id #{controller.request.session_options[:id] || controller.session.session_id.inspect}.")
100
+ end
101
+ #end
102
+
103
+ # Store the ticket in the session to avoid re-validating the same service
104
+ # ticket with the CAS server.
105
+ controller.session[:cas_last_valid_ticket] = st.ticket
106
+ controller.session[:cas_last_valid_ticket_service] = st.service
107
+
108
+ if st.pgt_iou
109
+ unless controller.session[:cas_pgt] && controller.session[:cas_pgt].ticket && controller.session[:cas_pgt].iou == st.pgt_iou
110
+ log.info("Receipt has a proxy-granting ticket IOU. Attempting to retrieve the proxy-granting ticket...")
111
+ pgt = client.retrieve_proxy_granting_ticket(st.pgt_iou)
112
+
113
+ if pgt
114
+ log.debug("Got PGT #{pgt.ticket.inspect} for PGT IOU #{pgt.iou.inspect}. This will be stored in the session.")
115
+ controller.session[:cas_pgt] = pgt
116
+ # For backwards compatibility with RubyCAS-Client 1.x configurations...
117
+ controller.session[:casfilterpgt] = pgt
118
+ else
119
+ log.error("Failed to retrieve a PGT for PGT IOU #{st.pgt_iou}!")
120
+ end
121
+ else
122
+ log.info("PGT is present in session and PGT IOU #{st.pgt_iou} matches the saved PGT IOU. Not retrieving new PGT.")
123
+ end
124
+
125
+ end
126
+
127
+ return true
128
+ else
129
+ log.warn("Ticket #{st.ticket.inspect} failed validation -- #{st.failure_code}: #{st.failure_message}")
130
+ unauthorized!(controller, st)
131
+ return false
132
+ end
133
+ else # no service ticket was present in the request
134
+ if returning_from_gateway?(controller)
135
+ log.info "Returning from CAS gateway without authentication."
136
+
137
+ # unset, to allow for the next request to be authenticated if necessary
138
+ controller.session[:cas_sent_to_gateway] = false
139
+
140
+ if use_gatewaying?
141
+ log.info "This CAS client is configured to use gatewaying, so we will permit the user to continue without authentication."
142
+ controller.session[client.username_session_key] = nil
143
+ return true
144
+ else
145
+ log.warn "The CAS client is NOT configured to allow gatewaying, yet this request was gatewayed. Something is not right!"
146
+ end
147
+ end
148
+
149
+ unauthorized!(controller)
150
+ return false
151
+ end
152
+ rescue OpenSSL::SSL::SSLError => sslexception
153
+ log.error("SSL Error: #{sslexception}")
154
+ unauthorized!(controller)
155
+ return false
156
+ end
157
+
158
+ # used to allow faking for testing
159
+ # with cucumber and other tools.
160
+ # use like
161
+ # CASClient::Frameworks::Rails::Filter.fake("homer")
162
+ # you can also fake extra attributes by including a second parameter
163
+ # CASClient::Frameworks::Rails::Filter.fake("homer", {:roles => ['dad', 'husband']})
164
+ def fake(username, extra_attributes = nil)
165
+ @@fake_user = username
166
+ @@fake_extra_attributes = extra_attributes
167
+ end
168
+
169
+ def use_gatewaying?
170
+ @@config[:use_gatewaying]
171
+ end
172
+
173
+ # Returns the login URL for the current controller.
174
+ # Useful when you want to provide a "Login" link in a GatewayFilter'ed
175
+ # action.
176
+ def login_url(controller)
177
+ service_url = read_service_url(controller)
178
+ url = client.add_service_to_login_url(service_url)
179
+ log.debug("Generated login url: #{url}")
180
+ return url
181
+ end
182
+
183
+ # allow controllers to reuse the existing config to auto-login to
184
+ # the service
185
+ #
186
+ # Use this from within a controller. Pass the controller, the
187
+ # login-credentials and the path that you want the user
188
+ # resdirected to on success.
189
+ #
190
+ # When writing a login-action you must check the return-value of
191
+ # the response to see if it failed!
192
+ #
193
+ # If it worked - you need to redirect the user to the service -
194
+ # path, because that has the ticket that will *actually* log them
195
+ # into your system
196
+ #
197
+ # example:
198
+ # def autologin
199
+ # resp = CASClient::Frameworks::Rails::Filter.login_to_service(self, credentials, dashboard_url)
200
+ # if resp.is_faiulure?
201
+ # flash[:error] = 'Login failed'
202
+ # render :action => 'login'
203
+ # else
204
+ # return redirect_to(@resp.service_redirect_url)
205
+ # end
206
+ # end
207
+ def login_to_service(controller, credentials, return_path)
208
+ resp = @@client.login_to_service(credentials, return_path)
209
+ if resp.is_failure?
210
+ log.info("Validation failed for service #{return_path.inspect} reason: '#{resp.failure_message}'")
211
+ else
212
+ log.info("Ticket #{resp.ticket.inspect} for service #{return_path.inspect} is VALID.")
213
+ end
214
+
215
+ resp
216
+ end
217
+
218
+ # Clears the given controller's local Rails session, does some local
219
+ # CAS cleanup, and redirects to the CAS logout page. Additionally, the
220
+ # <tt>request.referer</tt> value from the <tt>controller</tt> instance
221
+ # is passed to the CAS server as a 'destination' parameter. This
222
+ # allows RubyCAS server to provide a follow-up login page allowing
223
+ # the user to log back in to the service they just logged out from
224
+ # using a different username and password. Other CAS server
225
+ # implemenations may use this 'destination' parameter in different
226
+ # ways.
227
+ # If given, the optional <tt>service</tt> URL overrides
228
+ # <tt>request.referer</tt>.
229
+ def logout(controller, service = nil)
230
+ referer = service || controller.request.referer
231
+ st = controller.session[:cas_last_valid_ticket]
232
+ delete_service_session_lookup(st) if st
233
+ controller.send(:reset_session)
234
+ controller.send(:redirect_to, client.logout_url(referer))
235
+ end
236
+
237
+ def unauthorized!(controller, vr = nil)
238
+ if controller.params[:format] == "xml"
239
+ if vr
240
+ controller.send(:render, :xml => "<errors><error>#{vr.failure_message}</error></errors>", :status => 401)
241
+ else
242
+ controller.send(:head, 401)
243
+ end
244
+ else
245
+ redirect_to_cas_for_authentication(controller)
246
+ end
247
+ end
248
+
249
+ def redirect_to_cas_for_authentication(controller)
250
+ redirect_url = login_url(controller)
251
+
252
+ if use_gatewaying?
253
+ controller.session[:cas_sent_to_gateway] = true
254
+ redirect_url << "&gateway=true"
255
+ else
256
+ controller.session[:cas_sent_to_gateway] = false
257
+ end
258
+
259
+ if controller.session[:previous_redirect_to_cas] &&
260
+ controller.session[:previous_redirect_to_cas] > (Time.now - 1.second)
261
+ log.warn("Previous redirect to the CAS server was less than a second ago. The client at #{controller.request.remote_ip.inspect} may be stuck in a redirection loop!")
262
+ controller.session[:cas_validation_retry_count] ||= 0
263
+
264
+ if controller.session[:cas_validation_retry_count] > 3
265
+ log.error("Redirection loop intercepted. Client at #{controller.request.remote_ip.inspect} will be redirected back to login page and forced to renew authentication.")
266
+ redirect_url += "&renew=1&redirection_loop_intercepted=1"
267
+ end
268
+
269
+ controller.session[:cas_validation_retry_count] += 1
270
+ else
271
+ controller.session[:cas_validation_retry_count] = 0
272
+ end
273
+ controller.session[:previous_redirect_to_cas] = Time.now
274
+
275
+ log.debug("Redirecting to #{redirect_url.inspect}")
276
+ controller.send(:redirect_to, redirect_url)
277
+ end
278
+
279
+ private
280
+ def single_sign_out(controller)
281
+
282
+ # Avoid calling raw_post (which may consume the post body) if
283
+ # this seems to be a file upload
284
+ if content_type = controller.request.headers["CONTENT_TYPE"] &&
285
+ content_type =~ %r{^multipart/}
286
+ return false
287
+ end
288
+
289
+ if controller.request.post? &&
290
+ controller.params['logoutRequest'] &&
291
+ URI.unescape(controller.params['logoutRequest']) =~
292
+ %r{^<samlp:LogoutRequest.*?<samlp:SessionIndex>(.*)</samlp:SessionIndex>}m
293
+ # TODO: Maybe check that the request came from the registered CAS server? Although this might be
294
+ # pointless since it's easily spoofable...
295
+ si = $~[1]
296
+
297
+ unless config[:enable_single_sign_out]
298
+ log.warn "Ignoring single-sign-out request for CAS session #{si.inspect} because ssout functionality is not enabled (see the :enable_single_sign_out config option)."
299
+ return false
300
+ end
301
+
302
+ log.debug "Intercepted single-sign-out request for CAS session #{si.inspect}."
303
+
304
+ # Rails 2.3
305
+ ##required_sess_store = ActiveRecord::SessionStore
306
+ ##current_sess_store = ActionController::Base.session_store
307
+
308
+ # Rails 2.2
309
+ ## required_sess_store = CGI::Session::ActiveRecordStore
310
+ ## current_sess_store = ActionController::Base.session_options[:database_manager]
311
+
312
+ # Rails 3.0
313
+ #required_sess_store = ActiveRecord::SessionStore
314
+ current_sess_store = ::Rails.application.config.session_store
315
+
316
+ #if current_sess_store == required_sess_store
317
+ session_id = read_service_session_lookup(si)
318
+
319
+ if session_id
320
+ session = current_sess_store::Session.find_by_session_id(session_id)
321
+ if session
322
+ st = session.data[:cas_last_valid_ticket] || si
323
+ delete_service_session_lookup(st) if st
324
+ session.destroy
325
+ log.debug("Destroyed #{session.inspect} for session #{session_id.inspect} corresponding to service ticket #{si.inspect}.")
326
+ else
327
+ log.debug("Data for session #{session_id.inspect} was not found. It may have already been cleared by a local CAS logout request.")
328
+ end
329
+
330
+ log.info("Single-sign-out for session #{session_id.inspect} completed successfuly.")
331
+ else
332
+ log.warn("Couldn't destroy session with SessionIndex #{si} because no corresponding session id could be looked up.")
333
+ end
334
+ #else
335
+ # log.error "Cannot process logout request because this Rails application's session store is "+
336
+ # " #{current_sess_store.name.inspect}. Single Sign-Out only works with the "+
337
+ # " #{required_sess_store.name.inspect} session store."
338
+ #end
339
+
340
+ # Return true to indicate that a single-sign-out request was detected
341
+ # and that further processing of the request is unnecessary.
342
+ return true
343
+ end
344
+
345
+ # This is not a single-sign-out request.
346
+ return false
347
+ end
348
+
349
+ def read_ticket(controller)
350
+ # Note that we are now deleting the 'ticket' and 'renew' parameters, since they really
351
+ # have no business getting passed on to the controller action.
352
+
353
+ ticket = controller.params.delete(:ticket)
354
+
355
+ return nil unless ticket
356
+
357
+ log.debug("Request contains ticket #{ticket.inspect}.")
358
+
359
+ if ticket =~ /^PT-/
360
+ CASClient::ProxyTicket.new(ticket, read_service_url(controller), controller.params.delete(:renew))
361
+ else
362
+ CASClient::ServiceTicket.new(ticket, read_service_url(controller), controller.params.delete(:renew))
363
+ end
364
+ end
365
+
366
+ def returning_from_gateway?(controller)
367
+ controller.session[:cas_sent_to_gateway]
368
+ end
369
+
370
+ def read_service_url(controller)
371
+ if config[:service_url]
372
+ log.debug("Using explicitly set service url: #{config[:service_url]}")
373
+ return config[:service_url]
374
+ end
375
+
376
+ params = controller.params.dup
377
+ params.delete(:ticket)
378
+ service_url = controller.url_for(params)
379
+ log.debug("Guessed service url: #{service_url.inspect}")
380
+ return service_url
381
+ end
382
+
383
+ # Creates a file in tmp/sessions linking a SessionTicket
384
+ # with the local Rails session id. The file is named
385
+ # cas_sess.<session ticket> and its text contents is the corresponding
386
+ # Rails session id.
387
+ # Returns the filename of the lookup file created.
388
+ def store_service_session_lookup(st, sid)
389
+ st = st.ticket if st.kind_of? CASClient::ServiceTicket
390
+ f = File.new(filename_of_service_session_lookup(st), 'w')
391
+ f.write(sid)
392
+ f.close
393
+ return f.path
394
+ end
395
+
396
+ # Returns the local Rails session ID corresponding to the given
397
+ # ServiceTicket. This is done by reading the contents of the
398
+ # cas_sess.<session ticket> file created in a prior call to
399
+ # #store_service_session_lookup.
400
+ def read_service_session_lookup(st)
401
+ st = st.ticket if st.kind_of? CASClient::ServiceTicket
402
+ ssl_filename = filename_of_service_session_lookup(st)
403
+ return File.exists?(ssl_filename) && IO.read(ssl_filename)
404
+ end
405
+
406
+ # Removes a stored relationship between a ServiceTicket and a local
407
+ # Rails session id. This should be called when the session is being
408
+ # closed.
409
+ #
410
+ # See #store_service_session_lookup.
411
+ def delete_service_session_lookup(st)
412
+ st = st.ticket if st.kind_of? CASClient::ServiceTicket
413
+ ssl_filename = filename_of_service_session_lookup(st)
414
+ File.delete(ssl_filename) if File.exists?(ssl_filename)
415
+ end
416
+
417
+ # Returns the path and filename of the service session lookup file.
418
+ def filename_of_service_session_lookup(st)
419
+ st = st.ticket if st.kind_of? CASClient::ServiceTicket
420
+ return "#{Rails.root}/tmp/sessions/cas_sess.#{st}"
421
+ end
422
+ end
423
+ end
424
+
425
+ class GatewayFilter < Filter
426
+ def self.use_gatewaying?
427
+ return true unless @@config[:use_gatewaying] == false
428
+ end
429
+ end
430
+ end
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{rubycas-client-rails-vpsa}
3
+ s.version = "0.1.1"
4
+
5
+ s.authors = ["VPSA"]
6
+ s.date = %q{2012-11-21}
7
+ s.description = %q{Cliente CAS para a VPSA.}
8
+ s.summary = %q{Adaptacao do rubycas-client-rails para a VPSA.}
9
+ s.email = %q{suporte at vpsa dot com dot br}
10
+ s.files = `git ls-files`.split("\n")
11
+ s.homepage = %q{http://rubycas-client.rubyforge.org}
12
+ s.rdoc_options = ["--main", "README.txt"]
13
+ s.require_paths = ["lib"]
14
+ s.rubyforge_project = %q{rubycas-client}
15
+
16
+ s.add_dependency('rails', '>= 3.0.0')
17
+ s.add_dependency('rubycas-client', '~> 2.3.9.rc1')
18
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubycas-client-rails-vpsa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - VPSA
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rubycas-client
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 2.3.9.rc1
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.3.9.rc1
46
+ description: Cliente CAS para a VPSA.
47
+ email: suporte at vpsa dot com dot br
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - .project
53
+ - MIT-LICENSE
54
+ - README.markdown
55
+ - Rakefile
56
+ - init.rb
57
+ - install.rb
58
+ - lib/rubycas-client-rails-vpsa.rb
59
+ - rubycas-client-rails-vpsa-0.1.1.gem
60
+ - rubycas-client-rails-vpsa.gemspec
61
+ - uninstall.rb
62
+ homepage: http://rubycas-client.rubyforge.org
63
+ licenses: []
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --main
67
+ - README.txt
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project: rubycas-client
84
+ rubygems_version: 1.8.23
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Adaptacao do rubycas-client-rails para a VPSA.
88
+ test_files: []