devise_bushido_authenticatable 1.0.0 → 1.0.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.
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