devise_bushido_authenticatable 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -20
  5. data/Gemfile.lock +151 -74
  6. data/README.md +4 -2
  7. data/Rakefile +1 -46
  8. data/app/controllers/devise/cas_sessions_controller.rb +59 -10
  9. data/app/views/devise/cas_sessions/unregistered.html.erb +150 -2
  10. data/app/views/devise/cas_sessions/unregistered.html.erb.old +2 -0
  11. data/devise_bushido_authenticatable.gemspec +28 -95
  12. data/lib/devise_bushido_authenticatable/version.rb +3 -0
  13. data/lib/devise_cas_authenticatable.rb +45 -3
  14. data/lib/devise_cas_authenticatable/missing_session_helpers.rb +9 -0
  15. data/lib/devise_cas_authenticatable/model.rb +5 -6
  16. data/lib/devise_cas_authenticatable/routes.rb +5 -3
  17. data/lib/devise_cas_authenticatable/single_sign_out.rb +22 -0
  18. data/lib/devise_cas_authenticatable/single_sign_out/session_store/active_record.rb +12 -0
  19. data/lib/devise_cas_authenticatable/single_sign_out/session_store/redis.rb +27 -0
  20. data/lib/devise_cas_authenticatable/single_sign_out/strategies.rb +58 -0
  21. data/lib/devise_cas_authenticatable/single_sign_out/strategies/base.rb +11 -0
  22. data/lib/devise_cas_authenticatable/single_sign_out/strategies/rails_cache.rb +31 -0
  23. data/lib/devise_cas_authenticatable/strategy.rb +15 -11
  24. data/spec/devise_cas_authenticatable/model_spec.rb +39 -0
  25. data/spec/routes_spec.rb +25 -7
  26. data/spec/scenario/app/models/user.rb +2 -2
  27. data/spec/scenario/config/environments/development.rb +0 -1
  28. data/spec/scenario/config/initializers/castronaut.rb +1 -0
  29. data/spec/scenario/config/initializers/session_store.rb +2 -2
  30. data/spec/scenario/db/migrate/20100401102949_create_tables.rb +3 -2
  31. data/spec/scenario/db/migrate/20111002012903_add_sessions_table.rb +16 -0
  32. data/spec/scenario/db/schema.rb +25 -0
  33. data/spec/spec_helper.rb +3 -2
  34. data/spec/strategy_spec.rb +20 -29
  35. metadata +118 -27
  36. data/VERSION +0 -1
  37. data/devise_cas_authenticatable.gemspec +0 -118
@@ -0,0 +1,12 @@
1
+ ActiveRecord::SessionStore.class_eval do
2
+
3
+ include DeviseCasAuthenticatable::SingleSignOut::SetSession
4
+ alias_method_chain :set_session, :storage
5
+
6
+ #def destroy_session(env, session_id, options)
7
+ # if session = Session::find_by_session_id(sid)
8
+ # session.destroy
9
+ # end
10
+ #end
11
+
12
+ end
@@ -0,0 +1,27 @@
1
+ require "action_controller/session/redis_session_store"
2
+
3
+ module DeviseCasAuthenticatable
4
+ module SingleSignOut
5
+ module RedisSessionStore
6
+
7
+ include DeviseCasAuthenticatable::SingleSignOut::SetSession
8
+
9
+ def destroy_session(sid)
10
+ @pool.del(sid)
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+
17
+ if ::Redis::Store.rails3?
18
+ ActionDispatch::Session::RedisSessionStore.class_eval do
19
+ include DeviseCasAuthenticatable::SingleSignOut::RedisSessionStore
20
+ alias_method_chain :set_session, :storage
21
+ end
22
+ else
23
+ ActionController::Session::RedisSessionStore.class_eval do
24
+ include DeviseCasAuthenticatable::SingleSignOut::RedisSessionStore
25
+ alias_method_chain :set_session, :storage
26
+ end
27
+ end
@@ -0,0 +1,58 @@
1
+ module DeviseCasAuthenticatable
2
+ module SingleSignOut
3
+ module Strategies
4
+ class << self
5
+
6
+ # Add a strategy and store it in a hash.
7
+ def add(label, strategy, &block)
8
+ strategy ||= Class.new(DeviseCasAuthenticatable::SingleSignOut::Strategies::Base)
9
+ strategy.class_eval(&block) if block_given?
10
+
11
+ check_method(label, strategy, :store_session_id_for_index)
12
+ check_method(label, strategy, :find_session_id_by_index)
13
+ check_method(label, strategy, :delete_session_index)
14
+
15
+ unless strategy.ancestors.include?(DeviseCasAuthenticatable::SingleSignOut::Strategies::Base)
16
+ raise "#{label.inspect} is not a #{base}"
17
+ end
18
+
19
+ _strategies[label] = strategy.new()
20
+ end
21
+
22
+ # Update a previously given strategy.
23
+ def update(label, &block)
24
+ strategy = _strategies[label]
25
+ raise "Unknown strategy #{label.inspect}" unless strategy
26
+ add(label, strategy, &block)
27
+ end
28
+
29
+ # Provides access to strategies by label
30
+ def [](label)
31
+ _strategies[label]
32
+ end
33
+
34
+ def current_strategy
35
+ self[::Devise.cas_single_sign_out_mapping_strategy]
36
+ end
37
+
38
+ # Clears all declared.
39
+ def clear!
40
+ _strategies.clear
41
+ end
42
+
43
+ private
44
+
45
+ def _strategies
46
+ @strategies ||= {}
47
+ end
48
+
49
+ def check_method(label, strategy, method)
50
+ unless strategy.method_defined?(method)
51
+ raise NoMethodError, "#{method.to_s} is not declared in the #{label.inspect} strategy"
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ module DeviseCasAuthenticatable
2
+ module SingleSignOut
3
+ module Strategies
4
+ class Base
5
+ def logger
6
+ @logger ||= Rails.logger
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module DeviseCasAuthenticatable
2
+ module SingleSignOut
3
+ module Strategies
4
+ class RailsCache < Base
5
+ def store_session_id_for_index(session_index, session_id)
6
+ logger.debug("Storing #{session_id} for index #{session_index}")
7
+ Rails.cache.write(cache_key(session_index), session_id)
8
+ end
9
+
10
+ def find_session_id_by_index(session_index)
11
+ sid = Rails.cache.read(cache_key(session_index))
12
+ logger.debug("Found session id #{sid.inspect} for index #{session_index.inspect}")
13
+ sid
14
+ end
15
+
16
+ def delete_session_index(session_index)
17
+ logger.info("Deleting index #{session_index}")
18
+ Rails.cache.delete(cache_key(session_index))
19
+ end
20
+
21
+ private
22
+
23
+ def cache_key(session_index)
24
+ "devise_cas_authenticatable:#{session_index}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ ::DeviseCasAuthenticatable::SingleSignOut::Strategies.add( :rails_cache, DeviseCasAuthenticatable::SingleSignOut::Strategies::RailsCache )
@@ -1,4 +1,6 @@
1
1
  require 'devise/strategies/base'
2
+ require 'net/http'
3
+ require 'uri'
2
4
 
3
5
  module Devise
4
6
  module Strategies
@@ -15,18 +17,20 @@ module Devise
15
17
  # or attempt to redirect to the CAS server's login URL.
16
18
  def authenticate!
17
19
  ticket = read_ticket(params)
18
- if ticket
19
- if resource = mapping.to.authenticate_with_cas_ticket(ticket)
20
- success!(resource)
21
- elsif ticket.is_valid?
22
- logger.debug "="*30
23
- logger.debug ticket.response.user[:ido_id]
24
- logger.debug "="*30
25
- redirect!(::Devise.cas_unregistered_url(request.url, mapping), :ido_id => ticket.response.user)
26
- #fail!("The user #{ticket.response.user} is not registered with this site. Please use a different account.")
27
- else
28
- fail!(:invalid)
20
+ fail!(:invalid) if not ticket
21
+
22
+ if resource = mapping.to.authenticate_with_cas_ticket(ticket)
23
+ # Store the ticket in the session for later usage
24
+ if ::Devise.cas_enable_single_sign_out
25
+ session['cas_last_valid_ticket'] = ticket.ticket
26
+ session['cas_last_valid_ticket_store'] = true
29
27
  end
28
+
29
+ success!(resource)
30
+ elsif ticket.is_valid?
31
+ ido_id = ticket.respond_to?(:user) ? ticket.user : ticket.response.user
32
+ redirect!(::Devise.cas_unregistered_url(request.url, mapping), :ido_id => ido_id)
33
+ #fail!("The user #{ticket.response.user} is not registered with this site. Please use a different account.")
30
34
  else
31
35
  fail!(:invalid)
32
36
  end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ describe Devise::Models::BushidoAuthenticatable do
4
+
5
+ class ExampleAuth
6
+ include Devise::Models::BushidoAuthenticatable
7
+ end
8
+
9
+ describe "authenticate_with_cas_ticket" do
10
+
11
+ before :each do
12
+ @ticket = Object.new
13
+ @user = Object.new
14
+
15
+ @ticket.should_receive(:user).and_return(@user)
16
+ @ticket.should_receive(:has_been_validated?).and_return(true)
17
+ @ticket.should_receive(:is_valid?).and_return(true)
18
+ ::Devise.cas_create_user = true
19
+
20
+ ExampleAuth.should_receive(:find_for_authentication).and_return(@user)
21
+ @user.should_receive(:save)
22
+ end
23
+
24
+ it "should call the bushido_extra_attributes method if it's defined on the devise resource" do
25
+ @ticket.should_receive(:extra_attributes)
26
+ @user.should_receive(:bushido_extra_attributes)
27
+ ExampleAuth.authenticate_with_cas_ticket(@ticket)
28
+ end
29
+
30
+ it "should *not* call the bushido_extra_attributes method if it's *not* defined on the devise resource" do
31
+
32
+ @user.should_receive(:respond_to?).and_return(false)
33
+ @user.should_not_receive(:bushido_extra_attributes)
34
+
35
+ ExampleAuth.authenticate_with_cas_ticket(@ticket)
36
+ end
37
+
38
+ end
39
+ end
@@ -1,13 +1,31 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Devise::CasSessionsController do
4
- include RSpec::Rails::ControllerExampleGroup
3
+ describe "routing" do
4
+ include RSpec::Rails::RoutingExampleGroup
5
+
6
+ it "routes to #service" do
7
+ get("/users/service").should route_to("devise/cas_sessions#service")
8
+ end
9
+
10
+ it "routes to #new" do
11
+ get("/users/sign_in").should route_to("devise/cas_sessions#new")
12
+ end
13
+
14
+ it "routes to #create" do
15
+ post("/users/sign_in").should route_to("devise/cas_sessions#create")
16
+ end
17
+
18
+ it "routes to #destroy" do
19
+ get("/users/sign_out").should route_to("devise/cas_sessions#destroy")
20
+ end
5
21
 
6
- it { should route(:get, "/users/service").to(:action => "service") }
7
- it { should route(:get, "/users/sign_in").to(:action => "new") }
8
- it { should route(:post, "/users/sign_in").to(:action => "create") }
9
- it { should route(:get, "/users/sign_out").to(:action => "destroy") }
10
- it { should route(:get, "/users/unregistered").to(:action => "unregistered") }
22
+ it "routes to #unregistered" do
23
+ get("/users/unregistered").should route_to("devise/cas_sessions#unregistered")
24
+ end
25
+ end
26
+
27
+ describe Devise::CasSessionsController do
28
+ include RSpec::Rails::ControllerExampleGroup
11
29
 
12
30
  it "should have the right route names" do
13
31
  controller.should respond_to("user_service_path", "new_user_session_path", "user_session_path", "destroy_user_session_path")
@@ -1,3 +1,3 @@
1
1
  class User < ActiveRecord::Base
2
- devise :cas_authenticatable, :rememberable
3
- end
2
+ devise :bushido_authenticatable, :rememberable
3
+ end
@@ -11,7 +11,6 @@ Scenario::Application.configure do
11
11
 
12
12
  # Show full error reports and disable caching
13
13
  config.consider_all_requests_local = true
14
- config.action_view.debug_rjs = true
15
14
  config.action_controller.perform_caching = false
16
15
 
17
16
  # Don't care if the mailer can't send
@@ -0,0 +1 @@
1
+ Castronaut.config.connect_activerecord
@@ -1,8 +1,8 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
- Scenario::Application.config.session_store :cookie_store, :key => '_scenario_session'
3
+ # Scenario::Application.config.session_store :cookie_store, :key => '_scenario_session'
4
4
 
5
5
  # Use the database for sessions instead of the cookie-based default,
6
6
  # which shouldn't be used to store highly confidential information
7
7
  # (create the session table with "rake db:sessions:create")
8
- # Scenario::Application.config.session_store :active_record_store
8
+ Scenario::Application.config.session_store :active_record_store
@@ -1,7 +1,8 @@
1
1
  class CreateTables < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :users do |t|
4
- t.cas_authenticatable
4
+ t.bushido_authenticatable
5
+ t.string :username
5
6
  t.rememberable
6
7
  t.string :email
7
8
  t.timestamps
@@ -11,4 +12,4 @@ class CreateTables < ActiveRecord::Migration
11
12
  def self.down
12
13
  drop_table :users
13
14
  end
14
- end
15
+ end
@@ -0,0 +1,16 @@
1
+ class AddSessionsTable < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :sessions do |t|
4
+ t.string :session_id, :null => false
5
+ t.text :data
6
+ t.timestamps
7
+ end
8
+
9
+ add_index :sessions, :session_id
10
+ add_index :sessions, :updated_at
11
+ end
12
+
13
+ def self.down
14
+ drop_table :sessions
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your
6
+ # database schema. If you need to create the application database on another
7
+ # system, you should be using db:schema:load, not running all the migrations
8
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
10
+ #
11
+ # It's strongly recommended to check this file into your version control system.
12
+
13
+ ActiveRecord::Schema.define(:version => 20111002012903) do
14
+
15
+ create_table "sessions", :force => true do |t|
16
+ t.string "session_id", :null => false
17
+ t.text "data"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
23
+ add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
24
+
25
+ end
@@ -2,6 +2,7 @@ ENV["RAILS_ENV"] = "test"
2
2
  $:.unshift File.dirname(__FILE__)
3
3
  $:.unshift File.expand_path('../../lib', __FILE__)
4
4
 
5
+ require "devise_bushido_authenticatable"
5
6
  require "scenario/config/environment"
6
7
  require "rails/test_help"
7
8
  require 'rspec/rails'
@@ -9,7 +10,7 @@ require 'sham_rack'
9
10
  require 'capybara/rspec'
10
11
 
11
12
  RSpec.configure do |config|
12
- config.mock_with :mocha
13
+ config.mock_with :rspec
13
14
  end
14
15
 
15
16
  ShamRack.at('www.example.com') do |env|
@@ -19,4 +20,4 @@ ShamRack.at('www.example.com') do |env|
19
20
  Castronaut::Application.call(request.env)
20
21
  end
21
22
 
22
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
23
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -17,12 +17,14 @@ describe Devise::Strategies::CasAuthenticatable, :type => "acceptance" do
17
17
  visit destroy_user_session_url
18
18
  end
19
19
 
20
- def cas_login_url
20
+ def cas_login_url(redirect_path=nil)
21
21
  @cas_login_url ||= begin
22
- uri = URI.parse(Devise.cas_base_url + "/login")
23
- uri.query = Rack::Utils.build_nested_query(:service => user_service_url)
24
- uri.to_s
25
- end
22
+ redirect_path = "/" if not redirect_path
23
+ uri = URI.parse(Devise.cas_base_url + "/login")
24
+ uri.query = "service=#{CGI.escape(user_service_url)}&redirect=#{redirect_path}"
25
+ puts "URI CHECK #{uri.to_s}"
26
+ uri.to_s
27
+ end
26
28
  end
27
29
 
28
30
  def cas_logout_url
@@ -31,7 +33,6 @@ describe Devise::Strategies::CasAuthenticatable, :type => "acceptance" do
31
33
 
32
34
  def sign_into_cas(username, password)
33
35
  visit root_url
34
- current_url.should == cas_login_url
35
36
  fill_in "Username", :with => username
36
37
  fill_in "Password", :with => password
37
38
  click_on "Login"
@@ -51,7 +52,7 @@ describe Devise::Strategies::CasAuthenticatable, :type => "acceptance" do
51
52
 
52
53
  it 'should redirect to CAS server' do
53
54
  response.should be_redirect
54
- response.should redirect_to(cas_login_url)
55
+ response.should redirect_to(cas_login_url("/"))
55
56
  end
56
57
  end
57
58
 
@@ -66,31 +67,21 @@ describe Devise::Strategies::CasAuthenticatable, :type => "acceptance" do
66
67
  end
67
68
 
68
69
  it "should register new CAS users if set up to do so" do
69
- User.count.should == 1
70
- TestAdapter.register_valid_user("newuser", "newpassword")
71
- Devise.cas_create_user = true
72
- sign_into_cas "newuser", "newpassword"
70
+ expect {
71
+ TestAdapter.register_valid_user("newuser", "newpassword")
72
+ Devise.cas_create_user = true
73
+ sign_into_cas "newuser", "newpassword"
73
74
 
74
- current_url.should == root_url
75
- User.count.should == 2
76
- User.find_by_username("newuser").should_not be_nil
75
+ }.to change(User, :count).by(1)
77
76
  end
78
77
 
79
78
  it "should fail CAS login if user is unregistered and cas_create_user is false" do
80
- User.count.should == 1
81
- TestAdapter.register_valid_user("newuser", "newpassword")
82
- Devise.cas_create_user = false
83
- sign_into_cas "newuser", "newpassword"
84
-
85
- current_url.should_not == root_url
86
- User.count.should == 1
87
- User.find_by_username("newuser").should be_nil
79
+ expect {
80
+ TestAdapter.register_valid_user("newuser", "newpassword")
81
+ Devise.cas_create_user = false
82
+ sign_into_cas "newuser", "newpassword"
88
83
 
89
- click_on "sign in using a different account"
90
- current_url.should == cas_login_url
91
- fill_in "Username", :with => "joeuser"
92
- fill_in "Password", :with => "joepassword"
93
- click_on "Login"
94
- current_url.should == root_url
84
+ current_url.should_not == root_url
85
+ }.to change(User, :count).by(0)
95
86
  end
96
- end
87
+ end