lastobelus-rubycas-client 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ CHANGELOG.txt
2
+ History.txt
3
+ LICENSE.txt
4
+ Manifest.txt
5
+ README.txt
6
+ Rakefile
7
+ init.rb
8
+ lib/casclient.rb
9
+ lib/casclient/client.rb
10
+ lib/casclient/rest_client.rb
11
+ lib/casclient/frameworks/rails/cas_proxy_callback_controller.rb
12
+ lib/casclient/frameworks/rails/filter.rb
13
+ lib/casclient/frameworks/merb/filter.rb
14
+ lib/casclient/responses.rb
15
+ lib/casclient/tickets.rb
16
+ lib/casclient/version.rb
17
+ lib/rubycas-client.rb
18
+ setup.rb
data/README.txt ADDED
@@ -0,0 +1,275 @@
1
+ = RubyCAS-Client
2
+
3
+ Author:: Matt Zukowski <matt AT roughest DOT net>; inspired by code by Ola Bini <ola.bini AT ki DOT se> and Matt Walker <mwalker AT tamu DOT edu>
4
+ Copyright:: (c) 2008 Urbacon Ltd.
5
+ License:: GNU Lesser General Public License v2.1 (LGPL 2.1)
6
+ Website:: http://code.google.com/p/rubycas-client and http://rubyforge.org/projects/rubycas-client
7
+
8
+
9
+ === RubyCAS-Client is a Ruby client library for Yale's Central Authentication Service (CAS) protocol.
10
+
11
+ CAS provides a secure single sign on solution for web-based applications. The user logs in to your
12
+ organization's CAS server, and is automatically authenticated for all other CAS-enabled applications.
13
+
14
+ For general information about the open CAS protocol, please have a look at http://www.ja-sig.org/products/cas.
15
+
16
+ If your organization does not already have a CAS server, you may be interested in RubyCAS-Client's sister project,
17
+ RubyCAS-Server[http://code.google.com/p/rubycas-server/].
18
+
19
+
20
+ == Getting help and reporting problems
21
+
22
+ If you need help, try posting to the RubyCAS discussion group at http://groups.google.com/group/rubycas-server.
23
+
24
+ To report problems, please use the Google Code issue tracker at http://code.google.com/p/rubycas-client/issues/list.
25
+
26
+
27
+ == Installation
28
+
29
+ You can download the latest version of RubyCAS-Client from the project's rubyforge page at
30
+ http://rubyforge.org/projects/rubycas-client.
31
+
32
+ However, it is easier to install the CAS client into a Ruby on Rails app as a plugin:
33
+
34
+ cd <your rails app>
35
+ ./script/plugin install http://rubycas-client.googlecode.com/svn/trunk/rubycas-client
36
+
37
+ Alternatively, the library is also installable as a RubyGem[http://rubygems.org]:
38
+
39
+ gem install rubycas-client
40
+
41
+ If your Rails application is under Subversion control, you can also install the plugin as an svn:external, ensuring that
42
+ you always have the latest bleeding-edge version of RubyCAS-Client:
43
+
44
+ ./script/plugin install -x http://rubycas-client.googlecode.com/svn/trunk/rubycas-client
45
+
46
+
47
+ == Usage Examples
48
+
49
+ Although RubyCAS-Client can be used with other web Frameworks (for example Camping), the following examples
50
+ are aimed at {Ruby on Rails}[http://rubyonrails.org].
51
+
52
+ ==== Using RubyCAS-Client in Rails controllers
53
+
54
+ <i>Note that from this point on we are assuming that you have a working CAS server up and running!</i>
55
+
56
+ After installing RubyCAS-Client as a plugin (see above), add the following to your app's <tt>config/environment.rb</tt>:
57
+
58
+ CASClient::Frameworks::Rails::Filter.configure(
59
+ :cas_base_url => "https://cas.example.foo/"
60
+ )
61
+
62
+ (Change the <tt>:cas_base_url</tt> value to your CAS server's base URL; also note that many CAS servers are configured
63
+ with a base URL that looks more like "https://cas.example.foo/cas".)
64
+
65
+ Then, in your <tt>app/controllers/application.rb</tt> (or in whichever controller you want to add the CAS filter for):
66
+
67
+ before_filter CASClient::Frameworks::Rails::Filter
68
+
69
+ That's it. You should now find that you are redirected to your CAS login page whenever you try to access any action
70
+ in your protected controller. You can of course qualify the <tt>before_filter</tt> as you would with any other ActionController
71
+ filter. For example:
72
+
73
+ before_filter CASClient::Frameworks::Rails::Filter, :except => [ :unprotected_action, :another_unprotected_action ]
74
+
75
+ <b>Once the user has been authenticated, their authenticated username is available under <tt>session[:cas_user]</tt>,</b>
76
+ If you want to do something with this username (for example load a user record from the database), you can append another
77
+ filter method that checks for this value and does whatever you need it to do.
78
+
79
+
80
+ ==== A more complicated example
81
+
82
+ Here is a more complicated configuration showing most of the configuration options along with their default values
83
+ (this does not show proxy options, which are covered in the next section):
84
+
85
+ # enable detailed CAS logging
86
+ cas_logger = CASClient::Logger.new(RAILS_ROOT+'/log/cas.log')
87
+ cas_logger.level = Logger::DEBUG
88
+
89
+ CASClient::Frameworks::Rails::Filter.configure(
90
+ :cas_base_url => "https://cas.example.foo/",
91
+ :login_url => "https://cas.example.foo/login",
92
+ :logout_url => "https://cas.example.foo/logout",
93
+ :validate_url => "https://cas.example.foo/proxyValidate",
94
+ :session_username_key => :cas_user,
95
+ :session_extra_attributes_key => :cas_extra_attributes
96
+ :logger => cas_logger,
97
+ :authenticate_on_every_request => true
98
+ )
99
+
100
+ Note that it is normally not necessary to specify <tt>:login_url</tt>, <tt>:logout_url</tt>, and <tt>:validate_url</tt>.
101
+ These values are automatically set to standard CAS defaults based on the given <tt>:cas_base_url</tt>.
102
+
103
+ The <tt>:session_username_key</tt> value determines the key under which you can find the CAS username in the Rails session hash.
104
+
105
+ Any additional info that the CAS server might have supplied about the user during authentication will be found under the
106
+ <tt>:session_extra_attributes_key</tt> value in the Rails session hash (i.e. given the above configuration, you would find this
107
+ info under <tt>session[:cas_extra_attributes]</tt>).
108
+
109
+ An arbitrary Logger instance can be given as the :logger parameter. In the example above we log all CAS activity to a
110
+ <tt>log/cas.log</tt> file in your Rails app's directory.
111
+
112
+ ==== Re-authenticating on every request (i.e. the "single sign-out problem")
113
+
114
+ By default, the Rails filter will only authenticate with the CAS server when no session[:cas_user] value exists. Once the user
115
+ has been authenticated, no further CAS forwarding is done until the user's session is wiped. This saves you
116
+ the trouble of having to do this check yourself (since in most cases it is not advisable to go through the CAS server
117
+ on every request -- this is slow and would potentially lead to problems, for example for AJAX requests). However,
118
+ the disadvantage is that the filter no longer checks to make sure that the user's CAS session is still actually open.
119
+ In other words it is possible for the user's authentication session to be closed on the CAS server without the
120
+ client application knowing about it.
121
+
122
+ In the future RubyCAS-Client will support the new "Single Sign-Out" functionality in CAS 3.1, allowing the server to
123
+ notify the client application that the CAS session is closed, but for now it is up to you to handle this by, for example,
124
+ by wiping the local session[:cas_user] value periodically to force a CAS re-check.
125
+
126
+ Alternatively, it is possible to disable this authentication persistence behaviour by setting the <tt>:authenticate_on_every_request</tt>
127
+ configuration option to true as in the example above.
128
+
129
+
130
+ ==== Defining a 'logout' action
131
+
132
+ Your Rails application's controller(s) will probably have some sort of logout function. In it you will likely reset the
133
+ 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:
134
+
135
+ class ApplicationController < ActionController::Base
136
+
137
+ # ...
138
+
139
+ def logout
140
+ reset_session
141
+ redirect_to CAS::Filter.logout_url(self, request.referer)
142
+ end
143
+ end
144
+
145
+
146
+ ==== Gatewayed (i.e. optional) authentication
147
+
148
+ "Gatewaying" essentially allows for optional CAS authentication. Users who already have a pre-existing CAS SSO session
149
+ will be automatically authenticated for the gatewayed service, while those who do not will be allowed to access the service
150
+ without authentication. This is useful for example when you want to show some additional private content on a homepage to
151
+ authenticated users, but also want anonymous users to be able to access the page without first logging in.
152
+
153
+ To allow users to access a page without authenticatin, simply use <tt>CASClient::Frameworks::Rails::GatewayFilter</tt>
154
+ in place of <tt>CASClient::Frameworks::Rails::Filter</tt> in your controller. For example, you may want to require
155
+ CAS authentication for all actions in a controller except the index action:
156
+
157
+ class ExampleController < ApplicationController
158
+ before_filter CASClient::Frameworks::Rails::GatewayFilter, :only => :index
159
+ before_filter CASClient::Frameworks::Rails::Filter, :except => :index
160
+
161
+ # ...
162
+ end
163
+
164
+
165
+ ==== How to act as a CAS proxy
166
+
167
+ CAS 2.0 has a built-in mechanism that allows a CAS-authenticated application to pass on its authentication to other applications.
168
+ 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
169
+ various other sites that run independently of the portal system (but are always accessed via the portal). The exact mechanism
170
+ 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
171
+ is available at http://www.ja-sig.org/wiki/display/CAS/Proxy+CAS+Walkthrough.
172
+
173
+ RubyCAS-Client fully supports proxying, so a CAS-protected Rails application can act as a CAS proxy.
174
+
175
+ Additionally, RubyCAS-Client comes with a controller that can act as a CAS proxy callback receiver. This is necessary because
176
+ when your application requests to act as a CAS proxy, the CAS server must contact your application to deposit the proxy-granting-ticket
177
+ (PGT). Note that in this case the CAS server CONTACTS YOU, rather than you contacting the CAS server (as in all other CAS operations).
178
+
179
+ 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,
180
+ all you need to do is this:
181
+
182
+ In your <tt>config/environment.rb</tt>:
183
+
184
+ # enable detailed CAS logging for easier troubleshooting
185
+ cas_logger = CASClient::Logger.new(RAILS_ROOT+'/log/cas.log')
186
+ cas_logger.level = Logger::DEBUG
187
+
188
+ CASClient::Frameworks::Rails::Filter.configure(
189
+ :cas_base_url => "https://cas.example.foo/",
190
+ :proxy_retrieval_url => "https://cas-proxy-callback.example.foo/cas_proxy_callback/retrieve_pgt",
191
+ :proxy_callback_url => "https://cas-proxy-callback.example.foo/cas_proxy_callback/receive_pgt",
192
+ :logger => cas_logger
193
+ )
194
+
195
+ 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
196
+ CasProxyCallbackController. This should work as-is with the standard Rails routes setup, but if you have disabled the default
197
+ route, you should add the following:
198
+
199
+ map.cas_proxy_callback 'cas_proxy_callback/:action', :controller => 'cas_proxy_callback'
200
+
201
+ Now here's a big giant caveat: <b>your CAS callback application and your CAS proxy application must run on separate Rails servers</b>.
202
+ In other words, if you want a Rails app to act as a CAS ticket-granting proxy, the cas_proxy_callback controller
203
+ must run on a different server. This is because Rails does not properly support handling of concurrent requests. The CAS proxy mechanism
204
+ acts in such a way that if your proxy application and your callback controller were on the same server
205
+ you would end up with a deadlock (the CAS server would be waiting for its callback to be accepted by your Rails server,
206
+ but your Rails server wouldn't respond to the CAS server's callback until the CAS server responded back first).
207
+
208
+ The simplest workaround is this:
209
+
210
+ 1. Create an empty rails app (i.e. something like <tt>rails cas_proxy_callback</tt>)
211
+ 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
212
+ it is already installed. If you want to install as a plugin, see the instructions in the "Installing" section above.
213
+ 3. Make sure that the server is up and running, and configure your proxy_callback_url and proxy_retrieval_url to point
214
+ to the new server as described above (or rather, make Pound point to the new server, if that's how you're handling https).
215
+
216
+ That's it. The proxy_callback_controller doesn't require any additional configuration. It doesn't access the database
217
+ or anything of that sort.
218
+
219
+ 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
220
+ to authenticate another application:
221
+
222
+ service_uri = "http://some-other-application.example.foo"
223
+ proxy_granting_ticket = session[:cas_pgt]
224
+ ticket = CASClient::Frameworks::Rails::Filter.client.request_proxy_ticket(service_uri, proxy_granting_ticket).ticket
225
+
226
+ <tt>ticket</tt> should now contain a valid service ticket. You can use it to authenticate other services by sending it and
227
+ the service URI as parameters to your target application:
228
+
229
+ http://some-other-application.example.foo?service=#{CGI.encode(ticket.target_service)}&ticket=#{ticket.proxy_ticket}
230
+
231
+ This is of course assuming that http://some-other-application.example.foo is also protected by the CAS filter.
232
+ Note that you should always URI-encode your service parameter inside URIs!
233
+
234
+ Note that #request_proxy_ticket returns a CASClient::ProxyTicket object, which is why we need to call #ticket on it
235
+ to retrieve the actual service ticket string.
236
+
237
+ ===== Additional proxying notes and caveats
238
+
239
+ <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
240
+ the bundled cas_proxy_callback controller, you will have to host your application on an https-enabled server. This can be a bit
241
+ tricky with Rails. WEBrick's SSL support is difficult to configure, and Mongrel doesn't support SSL at all. One workaround is to
242
+ use a reverse proxy like Pound[http://www.apsis.ch/pound/], which will accept https connections and locally re-route them
243
+ to your Rails application. Also, note that <i>self-signed SSL certificates likely won't work</i>. You will probably need to use
244
+ a real certificate purchased from a trusted CA authority (there are ways around this, but good luck :)
245
+
246
+
247
+ == SSL Support
248
+
249
+ Make sure you have the Ruby OpenSSL library installed. Otherwise you may get errors like:
250
+
251
+ no such file to load -- net/https
252
+
253
+ To install the library on an Debian/Ubuntu system:
254
+
255
+ sudo apt-get install libopenssl-ruby
256
+
257
+ For other platforms you'll have to figure it out yourself.
258
+
259
+
260
+
261
+ == License
262
+
263
+ This program is free software; you can redistribute it and/or modify
264
+ it under the terms of the GNU Lesser General Public License as published by
265
+ the Free Software Foundation; either version 2 of the License, or
266
+ (at your option) any later version.
267
+
268
+ This program is distributed in the hope that it will be useful,
269
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
270
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
271
+ GNU General Public License for more details.
272
+
273
+ You should have received a copy of the GNU Lesser General Public License
274
+ along with this program (see the file called LICENSE); if not, write to the
275
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ require 'hoe'
11
+ include FileUtils
12
+ require File.join(File.dirname(__FILE__), 'lib', 'casclient', 'version')
13
+
14
+ AUTHOR = ["Matt Zukowski", "Matt Walker"] # can also be an array of Authors
15
+ EMAIL = "matt at roughest dot net"
16
+ DESCRIPTION = "Client library for the Central Authentication Service (CAS) protocol."
17
+ GEM_NAME = "rubycas-client" # what ppl will type to install your gem
18
+ RUBYFORGE_PROJECT = "rubycas-client" # The unix name for your project
19
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
+
21
+
22
+ NAME = "rubycas-client"
23
+ REV = nil
24
+ #REV = `svn info`[/Revision: (\d+)/, 1] rescue nil
25
+ VERS = ENV['VERSION'] || (CASClient::VERSION::STRING + (REV ? ".#{REV}" : ""))
26
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
27
+ RDOC_OPTS = ['--quiet', '--title', "rubycas-client documentation",
28
+ "--opname", "index.html",
29
+ "--line-numbers",
30
+ "--main", "README",
31
+ "--inline-source"]
32
+
33
+ class Hoe
34
+ def extra_deps
35
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
36
+ end
37
+ end
38
+
39
+ # Generate all the Rake tasks
40
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
41
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
42
+ p.author = AUTHOR
43
+ p.description = DESCRIPTION
44
+ p.email = EMAIL
45
+ p.summary = DESCRIPTION
46
+ p.url = HOMEPATH
47
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
48
+ p.test_globs = ["test/**/*_test.rb"]
49
+ p.clean_globs = CLEAN #An array of file patterns to delete on clean.
50
+
51
+ # == Optional
52
+ #p.changes - A description of the release's latest changes.
53
+ #p.extra_deps - An array of rubygem dependencies.
54
+ #p.spec_extras - A hash of extra values to set in the gemspec.
55
+ p.extra_deps = ['activesupport']
56
+ end
data/init.rb ADDED
@@ -0,0 +1,6 @@
1
+ # This file makes it possible to install RubyCAS-Client as a Rails plugin.
2
+
3
+ $: << File.expand_path(File.dirname(__FILE__))+'/lib'
4
+
5
+ require 'casclient'
6
+ require 'casclient/frameworks/rails/filter'
data/lib/casclient.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'net/https'
4
+ require 'rexml/document'
5
+
6
+ begin
7
+ require 'active_support'
8
+ rescue LoadError
9
+ require 'rubygems'
10
+ require 'active_support'
11
+ end
12
+
13
+ $: << File.expand_path(File.dirname(__FILE__))
14
+
15
+ module CASClient
16
+ class CASException < Exception
17
+ end
18
+
19
+ # Customized logger for the client.
20
+ # This is useful if you're trying to do logging in Rails, since Rails'
21
+ # clean_logger.rb pretty much completely breaks the base Logger class.
22
+ class Logger < ::Logger
23
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
24
+ @default_formatter = Formatter.new
25
+ super
26
+ end
27
+
28
+ def format_message(severity, datetime, progrname, msg)
29
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
30
+ end
31
+
32
+ def break
33
+ self << $/
34
+ end
35
+
36
+ class Formatter < ::Logger::Formatter
37
+ Format = "[%s#%d] %5s -- %s: %s\n"
38
+
39
+ def call(severity, time, progname, msg)
40
+ Format % [format_datetime(time), $$, severity, progname, msg2str(msg)]
41
+ end
42
+ end
43
+ end
44
+
45
+ # Wraps a real Logger. If no real Logger is set, then this wrapper
46
+ # will quietly swallow any logging calls.
47
+ class LoggerWrapper
48
+ def initialize(real_logger=nil)
49
+ set_logger(real_logger)
50
+ end
51
+ # Assign the 'real' Logger instance that this dummy instance wraps around.
52
+ def set_real_logger(real_logger)
53
+ @real_logger = real_logger
54
+ end
55
+ # Log using the appropriate method if we have a logger
56
+ # if we dont' have a logger, gracefully ignore.
57
+ def method_missing(name, *args)
58
+ if @real_logger && @real_logger.respond_to?(name)
59
+ @real_logger.send(name, *args)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ require 'casclient/tickets'
66
+ require 'casclient/responses'
67
+ require 'casclient/client'
68
+ require 'casclient/rest_client'
69
+ require 'casclient/version'
70
+
71
+ # Detect legacy configuration and show appropriate error message
72
+ module CAS
73
+ module Filter
74
+ class << self
75
+ def method_missing(method, *args)
76
+ $stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
77
+ $stderr.puts
78
+ $stderr.puts "WARNING: Your RubyCAS-Client configuration is no longer valid!!"
79
+ $stderr.puts
80
+ $stderr.puts "For information on the new configuration format please see: "
81
+ $stderr.puts
82
+ $stderr.puts " http://rubycas-client.googlecode.com/svn/trunk/rubycas-client/README.txt"
83
+ $stderr.puts
84
+ $stderr.puts "After upgrading your configuration you should also clear your application's session store."
85
+ $stderr.puts
86
+ $stderr.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
87
+ end
88
+ end
89
+ end
90
+ end