devise-multi-radius-authenticatable 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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +21 -0
- data/README.md +85 -0
- data/Rakefile +16 -0
- data/devise-multi-radius-authenticatable.gemspec +32 -0
- data/lib/devise-radius-authenticatable.rb +8 -0
- data/lib/devise/models/radius_authenticatable.rb +187 -0
- data/lib/devise/radius_authenticatable.rb +45 -0
- data/lib/devise/radius_authenticatable/test_helpers.rb +126 -0
- data/lib/devise/radius_authenticatable/version.rb +5 -0
- data/lib/devise/strategies/radius_authenticatable.rb +30 -0
- data/lib/generators/devise_radius_authenticatable/install_generator.rb +93 -0
- data/spec/devise/models/radius_authenticatable_spec.rb +170 -0
- data/spec/factories/admins.rb +10 -0
- data/spec/fixtures/devise.rb +238 -0
- data/spec/generators/install_generator_spec.rb +66 -0
- data/spec/integration/radius_authenticatable_spec.rb +115 -0
- data/spec/rails_app/.gitignore +15 -0
- data/spec/rails_app/Gemfile +4 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +13 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_app/app/controllers/admins_controller.rb +83 -0
- data/spec/rails_app/app/controllers/application_controller.rb +11 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.gitkeep +0 -0
- data/spec/rails_app/app/models/.gitkeep +0 -0
- data/spec/rails_app/app/models/admin.rb +11 -0
- data/spec/rails_app/app/views/admins/_form.html.erb +17 -0
- data/spec/rails_app/app/views/admins/edit.html.erb +6 -0
- data/spec/rails_app/app/views/admins/index.html.erb +21 -0
- data/spec/rails_app/app/views/admins/new.html.erb +5 -0
- data/spec/rails_app/app/views/admins/show.html.erb +5 -0
- data/spec/rails_app/app/views/devise/confirmations/new.html.erb +12 -0
- data/spec/rails_app/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/spec/rails_app/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/spec/rails_app/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/spec/rails_app/app/views/devise/passwords/edit.html.erb +16 -0
- data/spec/rails_app/app/views/devise/passwords/new.html.erb +12 -0
- data/spec/rails_app/app/views/devise/registrations/edit.html.erb +29 -0
- data/spec/rails_app/app/views/devise/registrations/new.html.erb +18 -0
- data/spec/rails_app/app/views/devise/sessions/new.html.erb +17 -0
- data/spec/rails_app/app/views/devise/shared/_links.erb +25 -0
- data/spec/rails_app/app/views/devise/unlocks/new.html.erb +12 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +25 -0
- data/spec/rails_app/bin/bundle +3 -0
- data/spec/rails_app/bin/rails +4 -0
- data/spec/rails_app/bin/rake +4 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +23 -0
- data/spec/rails_app/config/boot.rb +4 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +29 -0
- data/spec/rails_app/config/environments/production.rb +80 -0
- data/spec/rails_app/config/environments/test.rb +36 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/devise.rb +308 -0
- data/spec/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/rails_app/config/initializers/inflections.rb +16 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +12 -0
- data/spec/rails_app/config/initializers/session_store.rb +3 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/devise.en.yml +59 -0
- data/spec/rails_app/config/locales/en.yml +23 -0
- data/spec/rails_app/config/routes.rb +63 -0
- data/spec/rails_app/db/migrate/20120627042556_devise_create_admins.rb +48 -0
- data/spec/rails_app/db/schema.rb +37 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/lib/assets/.gitkeep +0 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +25 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/devise_helpers.rb +18 -0
- data/spec/support/generator_helpers.rb +16 -0
- metadata +359 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'generators/devise_radius_authenticatable/install_generator'
|
3
|
+
|
4
|
+
describe DeviseRadiusAuthenticatable::InstallGenerator do
|
5
|
+
destination File.expand_path("../../../tmp", __FILE__)
|
6
|
+
|
7
|
+
before do
|
8
|
+
prepare_devise
|
9
|
+
end
|
10
|
+
|
11
|
+
it "requires the radius server IP to be specified" do
|
12
|
+
expect { run_generator }.
|
13
|
+
to raise_error(Thor::RequiredArgumentMissingError,
|
14
|
+
/required arguments 'server'/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "requires the radius server shared secret to be specified" do
|
18
|
+
expect { run_generator ['1.1.1.1'] }.
|
19
|
+
to raise_error(Thor::RequiredArgumentMissingError,
|
20
|
+
/required arguments 'secret'/)
|
21
|
+
end
|
22
|
+
|
23
|
+
context "with required arguments" do
|
24
|
+
|
25
|
+
subject { file('config/initializers/devise.rb') }
|
26
|
+
|
27
|
+
context "with default options" do
|
28
|
+
before do
|
29
|
+
run_generator ['1.1.1.1', 'secret']
|
30
|
+
end
|
31
|
+
|
32
|
+
it { should exist }
|
33
|
+
it { should contain('==> Configuration for radius_authenticatable') }
|
34
|
+
it { should contain("config.radius_server = '1.1.1.1'") }
|
35
|
+
it { should contain("config.radius_server_port = 1812") }
|
36
|
+
it { should contain("config.radius_server_secret = 'secret'") }
|
37
|
+
it { should contain("config.radius_server_timeout = 60") }
|
38
|
+
it { should contain("config.radius_server_retries = 0") }
|
39
|
+
it { should contain("config.radius_uid_field = :uid") }
|
40
|
+
it { should contain("config.radius_uid_generator =") }
|
41
|
+
it { should contain("config.radius_dictionary_path =") }
|
42
|
+
it { should contain("config.handle_radius_timeout_as_failure = false") }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "with custom options" do
|
46
|
+
before do
|
47
|
+
run_generator ['1.1.1.2', 'password', '--port=1813',
|
48
|
+
'--timeout=120', '--retries=3', '--uid_field=email',
|
49
|
+
'--dictionary_path=/tmp/dictionaries',
|
50
|
+
'--handle_timeout_as_failure=true']
|
51
|
+
end
|
52
|
+
|
53
|
+
it { should exist }
|
54
|
+
it { should contain('==> Configuration for radius_authenticatable') }
|
55
|
+
it { should contain("config.radius_server = '1.1.1.2'") }
|
56
|
+
it { should contain("config.radius_server_port = 1813") }
|
57
|
+
it { should contain("config.radius_server_secret = 'password'") }
|
58
|
+
it { should contain("config.radius_server_timeout = 120") }
|
59
|
+
it { should contain("config.radius_server_retries = 3") }
|
60
|
+
it { should contain("config.radius_uid_field = :email") }
|
61
|
+
it { should contain("config.radius_uid_generator =") }
|
62
|
+
it { should contain("config.radius_dictionary_path = '/tmp/dictionaries'") }
|
63
|
+
it { should contain("config.handle_radius_timeout_as_failure = true") }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "login" do
|
4
|
+
before do
|
5
|
+
@admin = FactoryGirl.create(:admin, :password => 'password')
|
6
|
+
create_radius_user('testuser', 'password')
|
7
|
+
visit new_admin_session_path
|
8
|
+
end
|
9
|
+
|
10
|
+
it "is successful for a database user with HTTP Basic Authentication" do
|
11
|
+
page.driver.browser.basic_authorize(@admin.email, 'password')
|
12
|
+
visit root_path
|
13
|
+
|
14
|
+
current_path.should == root_path
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is successful for a database user with params authentication" do
|
18
|
+
fill_in "Login", :with => @admin.email
|
19
|
+
fill_in "Password", :with => 'password'
|
20
|
+
click_button "Sign in"
|
21
|
+
|
22
|
+
current_path.should == root_path
|
23
|
+
page.should have_content("Signed in successfully")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "is successful for a radius user with HTTP Basic Authentication" do
|
27
|
+
page.driver.browser.basic_authorize('testuser', 'password')
|
28
|
+
visit root_path
|
29
|
+
|
30
|
+
current_path.should == root_path
|
31
|
+
end
|
32
|
+
|
33
|
+
it "is successful for a radius user with params authentication" do
|
34
|
+
fill_in "Login", :with => 'testuser'
|
35
|
+
fill_in "Password", :with => 'password'
|
36
|
+
click_button "Sign in"
|
37
|
+
|
38
|
+
current_path.should == root_path
|
39
|
+
page.should have_content("Signed in successfully")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "fails for wrong database password" do
|
43
|
+
fill_in "Login", :with => @admin.email
|
44
|
+
fill_in "Password", :with => 'password2'
|
45
|
+
click_button "Sign in"
|
46
|
+
|
47
|
+
current_path.should == new_admin_session_path
|
48
|
+
page.should have_content("Invalid email or password")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "fails for wrong radius password" do
|
52
|
+
fill_in "Login", :with => 'testuser'
|
53
|
+
fill_in "Password", :with => 'password2'
|
54
|
+
click_button "Sign in"
|
55
|
+
|
56
|
+
current_path.should == new_admin_session_path
|
57
|
+
page.should have_content("Invalid email or password")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "invokes the after_radius_authentication callback" do
|
61
|
+
fill_in "Login", :with => 'testuser'
|
62
|
+
fill_in "Password", :with => 'password'
|
63
|
+
click_button "Sign in"
|
64
|
+
|
65
|
+
uid = Admin.radius_uid_generator.call('testuser', Admin.radius_server)
|
66
|
+
Admin.where(Admin.radius_uid_field => uid).count.should == 1
|
67
|
+
end
|
68
|
+
|
69
|
+
it "successfully logs in a user with case insensitive username" do
|
70
|
+
swap(Devise, :case_insensitive_keys => [Admin.authentication_keys.first]) do
|
71
|
+
fill_in "Login", :with => 'TESTUSER'
|
72
|
+
fill_in "Password", :with => 'password'
|
73
|
+
click_button "Sign in"
|
74
|
+
|
75
|
+
current_path.should == root_path
|
76
|
+
page.should have_content("Signed in successfully")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "fails to log in a user with case sensitive username" do
|
81
|
+
swap(Devise, :case_insensitive_keys => []) do
|
82
|
+
fill_in "Login", :with => 'TESTUSER'
|
83
|
+
fill_in "Password", :with => 'password'
|
84
|
+
click_button "Sign in"
|
85
|
+
|
86
|
+
current_path.should == new_admin_session_path
|
87
|
+
page.should have_content("Invalid email or password")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when radius authentication is the first strategy" do
|
92
|
+
before do
|
93
|
+
@admin2 = FactoryGirl.create(:admin, :password => 'password')
|
94
|
+
create_radius_user(@admin2.email, 'password2')
|
95
|
+
|
96
|
+
@orig_order = Devise.warden_config.default_strategies(:scope => :admin)
|
97
|
+
Devise.warden_config.default_strategies(:radius_authenticatable,
|
98
|
+
:database_authenticatable,
|
99
|
+
{:scope => :admin})
|
100
|
+
end
|
101
|
+
|
102
|
+
after do
|
103
|
+
Devise.warden_config.default_strategies(@orig_order, {:scope => :admin})
|
104
|
+
end
|
105
|
+
|
106
|
+
it "proceeds with the next strategy if radius authentication fails" do
|
107
|
+
fill_in "Login", :with => @admin2.email
|
108
|
+
fill_in "Password", :with => 'password'
|
109
|
+
click_button "Sign in"
|
110
|
+
|
111
|
+
current_path.should == root_path
|
112
|
+
page.should have_content("Signed in successfully")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile ~/.gitignore_global
|
6
|
+
|
7
|
+
# Ignore bundler config
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore the default SQLite database.
|
11
|
+
/db/*.sqlite3
|
12
|
+
|
13
|
+
# Ignore all logfiles and tempfiles.
|
14
|
+
/log/*.log
|
15
|
+
/tmp
|
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
RailsApp::Application.load_tasks
|
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class AdminsController < ApplicationController
|
2
|
+
# GET /admins
|
3
|
+
# GET /admins.json
|
4
|
+
def index
|
5
|
+
@admins = Admin.all
|
6
|
+
|
7
|
+
respond_to do |format|
|
8
|
+
format.html # index.html.erb
|
9
|
+
format.json { render json: @admins }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /admins/1
|
14
|
+
# GET /admins/1.json
|
15
|
+
def show
|
16
|
+
@admin = Admin.find(params[:id])
|
17
|
+
|
18
|
+
respond_to do |format|
|
19
|
+
format.html # show.html.erb
|
20
|
+
format.json { render json: @admin }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# GET /admins/new
|
25
|
+
# GET /admins/new.json
|
26
|
+
def new
|
27
|
+
@admin = Admin.new
|
28
|
+
|
29
|
+
respond_to do |format|
|
30
|
+
format.html # new.html.erb
|
31
|
+
format.json { render json: @admin }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# GET /admins/1/edit
|
36
|
+
def edit
|
37
|
+
@admin = Admin.find(params[:id])
|
38
|
+
end
|
39
|
+
|
40
|
+
# POST /admins
|
41
|
+
# POST /admins.json
|
42
|
+
def create
|
43
|
+
@admin = Admin.new(params[:admin])
|
44
|
+
|
45
|
+
respond_to do |format|
|
46
|
+
if @admin.save
|
47
|
+
format.html { redirect_to @admin, notice: 'Admin was successfully created.' }
|
48
|
+
format.json { render json: @admin, status: :created, location: @admin }
|
49
|
+
else
|
50
|
+
format.html { render action: "new" }
|
51
|
+
format.json { render json: @admin.errors, status: :unprocessable_entity }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# PUT /admins/1
|
57
|
+
# PUT /admins/1.json
|
58
|
+
def update
|
59
|
+
@admin = Admin.find(params[:id])
|
60
|
+
|
61
|
+
respond_to do |format|
|
62
|
+
if @admin.update_attributes(params[:admin])
|
63
|
+
format.html { redirect_to @admin, notice: 'Admin was successfully updated.' }
|
64
|
+
format.json { head :no_content }
|
65
|
+
else
|
66
|
+
format.html { render action: "edit" }
|
67
|
+
format.json { render json: @admin.errors, status: :unprocessable_entity }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# DELETE /admins/1
|
73
|
+
# DELETE /admins/1.json
|
74
|
+
def destroy
|
75
|
+
@admin = Admin.find(params[:id])
|
76
|
+
@admin.destroy
|
77
|
+
|
78
|
+
respond_to do |format|
|
79
|
+
format.html { redirect_to admins_url }
|
80
|
+
format.json { head :no_content }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Admin < ActiveRecord::Base
|
2
|
+
devise :database_authenticatable, :radius_authenticatable
|
3
|
+
|
4
|
+
attr_accessor :login
|
5
|
+
|
6
|
+
def self.find_for_database_authentication(conditions)
|
7
|
+
login = conditions.delete(:login)
|
8
|
+
conditions[:email] = login
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= form_for(@admin) do |f| %>
|
2
|
+
<% if @admin.errors.any? %>
|
3
|
+
<div id="error_explanation">
|
4
|
+
<h2><%= pluralize(@admin.errors.count, "error") %> prohibited this admin from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<% @admin.errors.full_messages.each do |msg| %>
|
8
|
+
<li><%= msg %></li>
|
9
|
+
<% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div class="actions">
|
15
|
+
<%= f.submit %>
|
16
|
+
</div>
|
17
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h1>Listing admins</h1>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<tr>
|
5
|
+
<th></th>
|
6
|
+
<th></th>
|
7
|
+
<th></th>
|
8
|
+
</tr>
|
9
|
+
|
10
|
+
<% @admins.each do |admin| %>
|
11
|
+
<tr>
|
12
|
+
<td><%= link_to 'Show', admin %></td>
|
13
|
+
<td><%= link_to 'Edit', edit_admin_path(admin) %></td>
|
14
|
+
<td><%= link_to 'Destroy', admin, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
15
|
+
</tr>
|
16
|
+
<% end %>
|
17
|
+
</table>
|
18
|
+
|
19
|
+
<br />
|
20
|
+
|
21
|
+
<%= link_to 'New Admin', new_admin_path %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h2>Resend confirmation instructions</h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<div><%= f.label :email %><br />
|
7
|
+
<%= f.email_field :email, autofocus: true %></div>
|
8
|
+
|
9
|
+
<div><%= f.submit "Resend confirmation instructions" %></div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<%= render "devise/shared/links" %>
|