bcms_cas 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,92 @@
1
+ # Central Authentication Server Module
2
+
3
+ This module allows BrowserCMS to integrate with a Central Authentication Server (CAS) to allow users to log in to a BrowserCMS site,
4
+ using credentials stored in an external system. This module requires an existing CAS server to be running (See http://code.google.com/p/rubycas-server/)
5
+ as an example of a server.
6
+
7
+ This module will allow user to login to the public area of the CMS, using the Login Form Portlet. It does not handle users that need to
8
+ log into the CMS administrative area. It also handles single logout by redirecting the user to cas /logout service.
9
+
10
+ ## A. Instructions
11
+ Here are the necessary steps to install this module.
12
+
13
+ 1. Configure your CAS server and test that you can login directly via their /login page.
14
+ 2. Install the rubycas-client gem (See B below)
15
+ 3. Install the bcms_cas module, and configure it to point to your CAS server (see C below).
16
+ 4. Migrate the database to add the CAS Group (See D below)
17
+ 5. Alter the Login Form Portlet to submit to the CAS server. (See E below)
18
+
19
+ ## B. Installing RubyCAS-Client
20
+ This project depends on RubyCAS-client (http://code.google.com/p/rubycas-client/). RubyCAS-Client is a standard Rails PluginGem, and the instructions
21
+ for installing in into a Rails project can be found on their website. The following command will probably work though:
22
+
23
+ gem install rubycas-client
24
+
25
+ This will add the latest version of a gem. The bcms_cas module will require the necessary files, so you do not need to
26
+ make any configuration changes in your rails project.
27
+
28
+ ## C. Installing/Configuring the Module
29
+ To install a BrowserCMS module follow the instructions here http://www.browsercms.org/doc/guides/html/installing_modules.html .
30
+ After that you will need to configure the rubycas-client to point to the correct CAS server, along with any other
31
+ configuration options you need. Add the following to your config/initializers/browsercms.rb:
32
+
33
+
34
+ CASClient::Frameworks::Rails::Filter.configure(
35
+ :cas_base_url => "https://cas.yourdomainname.org",
36
+ :extra_attributes_session_key => :cas_extra_attributes
37
+ )
38
+
39
+ Make sure your SITE_DOMAIN variable in production/development is correctly set to the right top level domain. This will be needed
40
+ to allow redirects between the servers to happen correctly (it requires Absolute URLs). For example, in config/environments/production.rb:
41
+
42
+ SITE_DOMAIN="www.yourdomainname.com"
43
+
44
+ ### Extra Attributes (Optional)
45
+ The :extra_attributes_session_key may not be needed, depending on what type of Authenticator your CAS server is using. You can
46
+ safely leave it out if you are just using the normal CMS logic. A CAS server can send additional information back, and these will be stored as
47
+ session variables that can be accessed in other methods.
48
+
49
+ ## D. Add/Configure the 'CAS Authenticated User' Group
50
+ When you run rake db:migrate, this module will add a new group to the CMS called 'CAS Authenticated Users'. All users that
51
+ log in successfully will be assigned to members of this group. You will potentially want to rename this group to something
52
+ that more accurately reflects who these users are (i.e. Members, Staff, etc) and then set which sections of the website this
53
+ group can visit.
54
+
55
+ ## E. Configure Login Form Portlet
56
+ Alter the Login Form portlet to look something like this:
57
+
58
+ <% form_tag "https://cas.yourdomainname.org" do %>
59
+ <%= login_ticket_tag %>
60
+ <%= service_url_tag %>
61
+ <p>
62
+ <%= label_tag :login %>
63
+ <%= text_field_tag :username, @login %>
64
+ </p>
65
+ <p>
66
+ <%= label_tag :password %>
67
+ <%= password_field_tag :password %>
68
+ </p>
69
+ <p>
70
+ <%= label_tag :remember_me %>
71
+ <%= check_box_tag :remember_me, '1', @remember_me %>
72
+ </p>
73
+ <p><%= submit_tag "Login" %></p>
74
+ <% end %>
75
+
76
+ The key changes are:
77
+
78
+ 1. The form needs to submit directly to the CAS server
79
+ 2. You need to add helpers for login_ticket_tag and service_url_tag. These generate hidden parameters CAS services need.
80
+ 3. Change the username parameter from :login to :username
81
+
82
+ F. Known Issues
83
+
84
+ * Every page is secured by the CASClient Gateway Filter, which means a lot of redirects. This is potentially a big performance hit, and would require modifying the filter so it only handles checking login_tickets, rather than redirects.
85
+ * A user logged in using CAS will be assigned to a single group. There is no way to map a user to different groups (i.e. Platnium or Gold Members). Could potentially be done via cas extra info.
86
+ * The internal CMS User database is bypassed/not used for login for front end pages. This means it would fail the cmsadmin user tried to login via the Login Form.
87
+ * [Low] LoginPortlet Form tag should pull from CAS automatically (requires changes to CMS core)
88
+ * [Low] username/login field is different between CMS and CAS (requires core changes)
89
+ * The CAS Login page has to be styled to match the look and feel of the site.
90
+ * If the user types in wrong username/pw on CMS login form, they will be left on the CAS Login page, with message.
91
+ * Every hit to a page with the login form portlet is fetching a LT from CAS. This is potentially slow. [Performance]
92
+
@@ -0,0 +1,20 @@
1
+ #
2
+ # This represents a user was autheniticated using a CAS service. Their user data is not saved in the database (in the users table_,
3
+ # but is retrieved from an external service and stored purely as session data.
4
+ #
5
+ #
6
+ class CasUser < GuestUser
7
+
8
+ GROUP_NAME = "cas_group"
9
+
10
+ def initialize(attributes={})
11
+ super({ :first_name => "CAS", :last_name => "User"}.merge(attributes))
12
+ @guest = false
13
+ end
14
+
15
+ # Using a single group for now. (This will need to be mapped to more groups later).
16
+ def group
17
+ @group ||= Group.find_by_code(GROUP_NAME)
18
+ end
19
+
20
+ end
@@ -0,0 +1,15 @@
1
+ # This assumes there is no existing LoginPortletHelper defined in the Core CMS project, and provides one
2
+ # to simplify what users need to do in the form.
3
+ module LoginPortletHelper
4
+
5
+ # Generates the hidden field for the service_url that the CAS server expects, which tells it where to redirect to. Must create
6
+ # an absolute URL.
7
+ def service_url_tag
8
+ hidden_field_tag :service, Cas::Utils.service_url(@portlet, @page, session[:return_to])
9
+ end
10
+
11
+ # Generates the hidden field for the login ticket that CAS server expects.
12
+ def login_ticket_tag
13
+ hidden_field_tag :lt, Cas::Utils.fetch_lt_from_cas
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ class AddCasUserGroup < ActiveRecord::Migration
2
+ def self.up
3
+ group = Group.create!(:name=>"CAS Authenticated Users", :code=>"cas_group", :group_type=>GroupType.find_by_name("Registered Public User"))
4
+ group.sections = Section.all
5
+ end
6
+
7
+ def self.down
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Cms::Routes
2
+ def routes_for_bcms_cas
3
+ namespace(:cms) do |cms|
4
+ #cms.content_blocks :cas
5
+ end
6
+ end
7
+ end
data/lib/bcms_cas.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'bcms_cas/routes'
2
+ require 'cas/authentication'
@@ -0,0 +1,67 @@
1
+ require 'cas/utils'
2
+ require 'casclient'
3
+ require 'casclient/frameworks/rails/filter'
4
+
5
+ #
6
+ # Augments the core Cms::Controllers to add Cas Authentication behavior.
7
+ #
8
+ module Cas
9
+ module Authentication
10
+
11
+ # Called when this module is included on the given class.
12
+ def self.included(controller_class)
13
+ controller_class.send(:include, InstanceMethods)
14
+
15
+ controller_class.skip_filter :check_access_to_page
16
+ controller_class.before_filter CASClient::Frameworks::Rails::GatewayFilter
17
+ controller_class.before_filter :login_from_cas_ticket
18
+ controller_class.before_filter :check_access_to_page_normally
19
+ end
20
+
21
+ # Each instance of the controller will gain these methods.
22
+ module InstanceMethods
23
+ def check_access_to_page_normally
24
+ logger.warn "Checking auth using normal Cms filter."
25
+ check_access_to_page
26
+ end
27
+
28
+ # Attempts to set the current user based on the session attribute set by CAS.
29
+ def login_from_cas_ticket
30
+ logger.debug "Attempting to login using CAS session variable."
31
+ if session[:cas_user]
32
+ logger.warn "Who is @current_user '#{@current_user.login}'?" if @current_user
33
+ logger.warn "Who is User.current '#{User.current.login}'?" if User.current
34
+
35
+ user = CasUser.new(:login=>session[:cas_user])
36
+
37
+ # Having to set both of these feels very duplicative. Ideally I would like a way
38
+ # to set only once, but calling current_user= has sideeffects.
39
+ @current_user = User.current = user
40
+
41
+ logger.info "Found session[:cas_user]. Created CasUser with login '#{user.login}' and set as current_user." if @current_user
42
+ end
43
+ @current_user
44
+ end
45
+ end
46
+ end
47
+ Cms::ContentController.send(:include, Cas::Authentication)
48
+
49
+
50
+ # Extends the core SessionController to properly destroy the local session on logout, and redirect to CAS for Single Log out.
51
+ module SingleLogOut
52
+ def self.included(controller_class)
53
+ controller_class.send(:include, InstanceMethods)
54
+ controller_class.alias_method_chain :destroy, :cas
55
+ end
56
+
57
+ module InstanceMethods
58
+
59
+ def destroy_with_cas
60
+ logger.info "Handle single logout."
61
+ logout_user
62
+ Cas::Utils.logout(self, "http://#{SITE_DOMAIN}/")
63
+ end
64
+ end
65
+ end
66
+ Cms::SessionsController.send(:include, Cas::SingleLogOut)
67
+ end
data/lib/cas/utils.rb ADDED
@@ -0,0 +1,72 @@
1
+ #
2
+ # Customizes behavior of CASFilter.
3
+ #
4
+ module Cas
5
+ class Utils
6
+ # This is a wrapper around the default behavior of the CASClient Rails filter.
7
+ #
8
+ # The only difference is that it generates a return URL that the user can click on to get back to the homepage.
9
+ def self.logout(controller, service = nil)
10
+ # Copy/Paste from Filter
11
+ referer = reset_session_and_get_referrer(controller, service)
12
+
13
+ # New lines
14
+ client = CASClient::Frameworks::Rails::Filter.client
15
+
16
+ # Adding gateway=true param to this logout URL will cause immediate redirect, which is preferable
17
+ # since it means users aren't left stranded on the CAS server logout page.
18
+ url = client.logout_url(referer, referer)
19
+ controller.send(:redirect_to, "#{url}&gateway=true")
20
+ end
21
+
22
+ # Copy/Paste from CAS Filter
23
+ def self.reset_session_and_get_referrer(controller, service)
24
+ referer = service || controller.request.referer
25
+ st = controller.session[:cas_last_valid_ticket]
26
+ delete_service_session_lookup(st) if st
27
+ controller.send(:reset_session)
28
+ referer
29
+ end
30
+ #
31
+ # Gets a valid login_ticket from the CAS Server, which will allow us to submit directly from our CMS login forms.
32
+ #
33
+ def self.fetch_lt_from_cas
34
+ url = URI.parse("#{self.cas_server_url}/loginTicket")
35
+ post = Net::HTTP::Post.new(url.path)
36
+ post.set_form_data({'dummy'=>'data'})
37
+
38
+ https = Net::HTTP.new(url.host, url.port)
39
+ https.use_ssl = true
40
+
41
+ res = https.start {|http| http.request(post) }
42
+ lt = res.body
43
+ lt
44
+ end
45
+
46
+ def self.check(portlet)
47
+ portlet.current_page.path
48
+ end
49
+
50
+ # Calculates which URL the user should be redirect to, after completing registration on the CAS server.
51
+ def self.service_url(portlet, page, redirect_to = nil)
52
+ path = page.path if page
53
+ path = "" unless page
54
+ goto = redirect_to || portlet.success_url || path
55
+ unless goto.starts_with?("http://")
56
+ goto = to_absolute_url(goto)
57
+ end
58
+ goto
59
+ end
60
+
61
+ # Looks up the URL of the CAS server from the environment
62
+ def self.cas_server_url
63
+ CASClient::Frameworks::Rails::Filter.config[:cas_base_url]
64
+ end
65
+
66
+ private
67
+
68
+ def self.to_absolute_url(path)
69
+ "http://#{SITE_DOMAIN}#{path}"
70
+ end
71
+ end
72
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ gem_root = File.expand_path(File.join(File.dirname(__FILE__), ".."))
2
+ Cms.add_to_rails_paths gem_root
3
+ Cms.add_generator_paths gem_root, "db/migrate/[0-9]*_*.rb"
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+ require 'performance_test_help'
3
+
4
+ # Profiling results for each test method are written to tmp/performance.
5
+ class BrowsingTest < ActionController::PerformanceTest
6
+ def test_homepage
7
+ get '/'
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Transactional fixtures accelerate your tests by wrapping each test method
7
+ # in a transaction that's rolled back on completion. This ensures that the
8
+ # test database remains unchanged so your fixtures don't have to be reloaded
9
+ # between every test method. Fewer database queries means faster tests.
10
+ #
11
+ # Read Mike Clark's excellent walkthrough at
12
+ # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
13
+ #
14
+ # Every Active Record database supports transactions except MyISAM tables
15
+ # in MySQL. Turn off transactional fixtures in this case; however, if you
16
+ # don't care one way or the other, switching from MyISAM to InnoDB tables
17
+ # is recommended.
18
+ #
19
+ # The only drawback to using transactional fixtures is when you actually
20
+ # need to test transactions. Since your test is bracketed by a transaction,
21
+ # any transactions started in your code will be automatically rolled back.
22
+ self.use_transactional_fixtures = true
23
+
24
+ # Instantiated fixtures are slow, but give you @david where otherwise you
25
+ # would need people(:david). If you don't want to migrate your existing
26
+ # test cases which use the @david style and don't mind the speed hit (each
27
+ # instantiated fixtures translates to a database query per test method),
28
+ # then set this back to true.
29
+ self.use_instantiated_fixtures = false
30
+
31
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
32
+ #
33
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
34
+ # -- they do not yet inherit this setting
35
+ fixtures :all
36
+
37
+ # Add more helper methods to be used by all tests here...
38
+ end
@@ -0,0 +1,108 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+
4
+ class MyController < ActionController::Base
5
+ include Cms::Authentication::Controller
6
+
7
+ def get_at_current_user
8
+ @current_user
9
+ end
10
+
11
+ def flash
12
+ {}
13
+ end
14
+
15
+ def destroy
16
+ "Exists only to be alias_method_chained"
17
+ end
18
+ end
19
+
20
+ class CasAuthTest < ActiveSupport::TestCase
21
+
22
+ def setup
23
+ MyController.expects(:skip_filter).with(:check_access_to_page)
24
+ MyController.expects(:before_filter).with(CASClient::Frameworks::Rails::GatewayFilter)
25
+ MyController.expects(:before_filter).with(:login_from_cas_ticket)
26
+ MyController.expects(:before_filter).with(:check_access_to_page_normally)
27
+
28
+ MyController.send(:include, Cas::Authentication)
29
+
30
+ end
31
+
32
+ def teardown
33
+ User.current = nil
34
+ end
35
+
36
+
37
+ test "Alias's the existing filter to a different name." do
38
+ c = MyController.new
39
+ c.expects(:check_access_to_page)
40
+
41
+ c.check_access_to_page_normally
42
+ end
43
+
44
+ test "adds current_user and login from session to class" do
45
+ c = MyController.new
46
+
47
+ assert c.respond_to?(:current_user)
48
+ assert c.respond_to?(:login_from_cas_ticket)
49
+
50
+ end
51
+
52
+
53
+ test "login_from_cas_ticket will create and set the current user and User.current if a session attribute was found." do
54
+ c = MyController.new
55
+ c.session = {}
56
+ c.session[:cas_user] = "1234"
57
+
58
+ User.current = Group.find_by_code("guest")
59
+
60
+ c.login_from_cas_ticket
61
+
62
+ current_user = c.get_at_current_user
63
+ assert_equal CasUser, current_user.class
64
+ assert_equal "1234", current_user.login
65
+ assert_equal current_user, User.current
66
+ end
67
+
68
+ test "Cms::ContentController gets augmented" do
69
+ assert (Cms::ContentController.new.respond_to? :check_access_to_page_normally)
70
+ end
71
+
72
+ end
73
+
74
+ class CasSessionControllerTest < ActiveSupport::TestCase
75
+
76
+
77
+ test "alias_method_chain the normal methods" do
78
+ MyController.send(:include, Cas::SingleLogOut)
79
+
80
+ c = MyController.new
81
+
82
+ assert( c.respond_to? :destroy)
83
+ assert( c.respond_to? :destroy_with_cas)
84
+ assert( c.respond_to? :destroy_without_cas)
85
+
86
+ end
87
+
88
+ test "destroy_with_cas redirects to server and calls logout_user" do
89
+ MyController.send(:include, Cas::SingleLogOut)
90
+ c = MyController.new
91
+
92
+ c.expects(:logout_user)
93
+
94
+ Cas::Utils.expects(:logout).with(c, "http://#{SITE_DOMAIN}/")
95
+
96
+ c.destroy_with_cas
97
+
98
+
99
+ end
100
+
101
+ test "that BrowserCMS 3.0.3 installed." do
102
+ assert Cms::SessionsController.new.respond_to?(:logout_user), "Need to have BrowserCMS 3.0.3 installed for Cas module to work."
103
+ end
104
+
105
+ test "Cms::SessionController gets augmented" do
106
+ assert (Cms::SessionsController.new.respond_to? :destroy_with_cas)
107
+ end
108
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class CasUserTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @s = Section.create!(:name=>"root", :root=>true, :path=>"/")
7
+ @p = Page.create!(:name=>"Home", :section=>@s, :path=>"/p")
8
+ @g = Group.create!(:name=>"G", :code=>"cas_group")
9
+ @g.sections = Section.all
10
+ end
11
+
12
+ test "group returns the cas_group" do
13
+ user = CasUser.new
14
+
15
+ assert_equal @g, user.group
16
+ end
17
+
18
+ test "cas_user should be able to view all sections (based on group)" do
19
+ user = CasUser.new
20
+
21
+ assert user.able_to_view?(@p)
22
+ end
23
+
24
+ test "setting login" do
25
+ user = CasUser.new(:login=>"bob")
26
+ assert_equal "bob", user.login
27
+ end
28
+
29
+ test "that CasUsers are not considered guests" do
30
+ user = CasUser.new
31
+ assert !user.guest?
32
+ end
33
+
34
+
35
+ end
@@ -0,0 +1,83 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+
4
+ class CasUtilsTest < ActiveSupport::TestCase
5
+
6
+ def setup
7
+ @current_page = Page.new(:path=>"/expected")
8
+ @portlet = LoginPortlet.new
9
+ end
10
+
11
+ test "service_url returns absolute success_url if specified" do
12
+ @portlet.success_url = "/stuff"
13
+ assert_equal "http://localhost:3000/stuff", Cas::Utils.service_url(@portlet, @current_page), "This really need to be an absolute path for it work w/ CAS."
14
+ end
15
+
16
+ test "service_url returns current page if specified" do
17
+ p = LoginPortlet.new
18
+ p.current_page = Page.new(:path=>"/expected")
19
+
20
+ s = Cas::Utils.service_url(p, @current_page)
21
+ assert_equal "http://localhost:3000/expected", s
22
+ end
23
+
24
+ test "service_url returns redirect_to if available" do
25
+ s = Cas::Utils.service_url(@portlet, @current_page, "/redirected")
26
+ assert_equal "http://localhost:3000/redirected", s
27
+ end
28
+
29
+ test "Nil page doesn't cause Nil exception" do
30
+ s = Cas::Utils.service_url(@portlet, nil, nil)
31
+ assert_equal "http://localhost:3000", s
32
+ end
33
+
34
+ test "Portlets work as expected (CMS Core check)" do
35
+ p = LoginPortlet.new
36
+
37
+ assert_equal nil, p.success_url, "Validate that LoginPortlet returns nil if no success_url is set (rather than an empty string."
38
+ end
39
+
40
+ test "cas_server_url looks up CAS server from config in environment" do
41
+ expected = "https://127.0.0.1"
42
+ CASClient::Frameworks::Rails::Filter.expects(:config).returns({:cas_base_url=>expected})
43
+
44
+ assert_equal expected, Cas::Utils.cas_server_url
45
+ end
46
+
47
+ test "get login ticket" do
48
+ expected_host = "https://random.com"
49
+ Cas::Utils.expects(:cas_server_url).with.returns(expected_host)
50
+
51
+ Net::HTTP.any_instance.stubs(:start).returns(mock(:body=>"Ticket 100"))
52
+ uri = stub(:path=>"#{expected_host}/loginTicket", :host=>"", :port=>80)
53
+ URI.expects(:parse).with("#{expected_host}/loginTicket").returns(uri)
54
+
55
+ ticket = Cas::Utils.fetch_lt_from_cas
56
+ assert_equal "Ticket 100", ticket
57
+ end
58
+
59
+ # Verification test of CasClient API behavior.
60
+ test "[CASClient] Verify expected behavior of CASClient#logout_url" do
61
+ destination_url = "localhost"
62
+
63
+ client = CASClient::Client.new({:cas_base_url=>"/", :logout_url=>"/"})
64
+
65
+ logout_url = client.logout_url(destination_url, destination_url)
66
+ assert_equal "/?destination=localhost&url=localhost", logout_url, "Verifies that logout_url generates a correct URL."
67
+ assert_equal String, logout_url.class
68
+ end
69
+
70
+ test "Cas::Utils#logout redirects and attaches gateway=true to logout_url" do
71
+ destination_url = "localhost"
72
+ logout_url = "/?destination=localhost&url=localhost"
73
+
74
+ CASClient::Frameworks::Rails::Filter.expects(:client).returns(CASClient::Client.new({:cas_base_url=>""}))
75
+ CASClient::Client.any_instance.expects(:logout_url).with(destination_url, destination_url).returns(logout_url)
76
+
77
+ controller = stub()
78
+ controller.expects(:redirect_to).with("#{logout_url}&gateway=true")
79
+ Cas::Utils.expects(:reset_session_and_get_referrer).returns(destination_url)
80
+
81
+ Cas::Utils.logout(controller, "/")
82
+ end
83
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+
4
+ class LoginPortletHelperTest < ActionView::TestCase
5
+
6
+ test "Fetching login ticket" do
7
+ ticket = Cas::Utils.expects(:fetch_lt_from_cas).with().returns("ABC")
8
+ assert_equal hidden_field_tag( :lt, "ABC"), login_ticket_tag
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bcms_cas
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - BrowserMedia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-05 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: github@browsermedia.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - app/models/cas_user.rb
26
+ - app/portlets/helpers/login_portlet_helper.rb
27
+ - db/migrate/20091002162550_add_cas_user_group.rb
28
+ - lib/bcms_cas.rb
29
+ - lib/bcms_cas/routes.rb
30
+ - lib/cas/authentication.rb
31
+ - lib/cas/utils.rb
32
+ - rails/init.rb
33
+ - README.markdown
34
+ has_rdoc: true
35
+ homepage: http://browsercms.org
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --charset=UTF-8
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ requirements: []
56
+
57
+ rubyforge_project: browsercms
58
+ rubygems_version: 1.3.4
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: A CAS Module for BrowserCMS
62
+ test_files:
63
+ - test/performance/browsing_test.rb
64
+ - test/test_helper.rb
65
+ - test/unit/cas/cas_authentication_test.rb
66
+ - test/unit/cas_user_test.rb
67
+ - test/unit/cas_utils_test.rb
68
+ - test/unit/helpers/login_portlet_helper_test.rb