theworkinggroup-wristband 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +130 -0
- data/Rakefile +39 -0
- data/generators/wristband/templates/app/controllers/sessions_controller.rb +50 -0
- data/generators/wristband/templates/app/controllers/users_controller.rb +47 -0
- data/generators/wristband/templates/app/models/user.rb +30 -0
- data/generators/wristband/templates/app/models/user_notifier.rb +54 -0
- data/generators/wristband/templates/app/views/sessions/new.html.haml +17 -0
- data/generators/wristband/templates/app/views/user_notifier/email_verification.text.html.rhtml +7 -0
- data/generators/wristband/templates/app/views/user_notifier/email_verification.text.plain.rhtml +9 -0
- data/generators/wristband/templates/app/views/user_notifier/forgot_password.text.html.rhtml +10 -0
- data/generators/wristband/templates/app/views/user_notifier/forgot_password.text.plain.rhtml +10 -0
- data/generators/wristband/templates/app/views/users/forgot_password.html.haml +10 -0
- data/generators/wristband/templates/app/views/users/index.html.haml +6 -0
- data/generators/wristband/templates/db/migrate/create_wristband_tables.rb +28 -0
- data/generators/wristband/wristband_generator.rb +69 -0
- data/init.rb +1 -0
- data/lib/wristband.rb +121 -0
- data/lib/wristband/application_extensions.rb +78 -0
- data/lib/wristband/authority_check.rb +160 -0
- data/lib/wristband/support.rb +28 -0
- data/lib/wristband/user_extensions.rb +89 -0
- data/test/database.yml +3 -0
- data/test/fixtures/crypted_password_users.yml +12 -0
- data/test/fixtures/plain_text_password_users.yml +4 -0
- data/test/fixtures/users.yml +23 -0
- data/test/schema.rb +34 -0
- data/test/test_helper.rb +40 -0
- data/test/unit/crypted_password_users_test.rb +81 -0
- data/test/unit/has_authorities_test.rb +49 -0
- data/test/unit/plain_text_password_user_test.rb +92 -0
- data/wristband.gemspec +32 -0
- metadata +97 -0
data/README.rdoc
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
= Wristband plugin
|
2
|
+
Author:: {The Working Group, Inc}[http://www.theworkinggroup.ca]
|
3
|
+
Version:: 1.0.0
|
4
|
+
|
5
|
+
The Wristband plug-in simplifies the user authentication process necessary in most web applications.
|
6
|
+
|
7
|
+
It handles:
|
8
|
+
|
9
|
+
* Login and logout
|
10
|
+
* Password storage with encryption
|
11
|
+
* Remember me functionality
|
12
|
+
* Authority definitions
|
13
|
+
|
14
|
+
|
15
|
+
== Usage
|
16
|
+
|
17
|
+
From a clean project
|
18
|
+
(assuming you just did <tt>rails myproject</tt> )
|
19
|
+
|
20
|
+
<b>1.</b> Install the plugin
|
21
|
+
cd vendor/plugins
|
22
|
+
svn export http://twg.unfuddle.com/svn/twg_twgplugins/wristband/trunk wristband
|
23
|
+
|
24
|
+
<b>2.</b> Run the wristband generator:
|
25
|
+
script/generate wristband
|
26
|
+
|
27
|
+
This will output something like:
|
28
|
+
|
29
|
+
exists app/models
|
30
|
+
create app/models/user.rb
|
31
|
+
create app/controllers/users_controller.rb
|
32
|
+
create app/views/users/index.html.haml
|
33
|
+
exists app/controllers
|
34
|
+
create app/controllers/sessions_controller.rb
|
35
|
+
create app/views/sessions/new.html.haml
|
36
|
+
exists db/migrate
|
37
|
+
exists db/migrate
|
38
|
+
create db/migrate/001_wristband.rb
|
39
|
+
route specific routes
|
40
|
+
route map.resources :sessions, :users
|
41
|
+
|
42
|
+
<b>3.</b> Run migrations
|
43
|
+
|
44
|
+
rake db:migrate
|
45
|
+
|
46
|
+
<b>4.</b> Restart your server
|
47
|
+
|
48
|
+
<b>5.</b> Add whatever validations you need in your User model
|
49
|
+
|
50
|
+
<b>6.</b> Read the documentation on each one of the generated files
|
51
|
+
|
52
|
+
|
53
|
+
== Configuration
|
54
|
+
|
55
|
+
|
56
|
+
=== User model
|
57
|
+
|
58
|
+
class User < ActiveRecord::Base
|
59
|
+
wristband [options]
|
60
|
+
end
|
61
|
+
|
62
|
+
==== Options:
|
63
|
+
|
64
|
+
[:login_with] Array of fields you want to authenticate the user with. Default: usename
|
65
|
+
|
66
|
+
wristband :login_with => [:username, :email]
|
67
|
+
|
68
|
+
|
69
|
+
[:before_authentication] Array of functions run after the user authentication takes place. Default: []
|
70
|
+
|
71
|
+
wristband :before_authentication => :do_something
|
72
|
+
|
73
|
+
|
74
|
+
[:after_authentication] Array of functions run before the user authentication takes place. Default: []
|
75
|
+
|
76
|
+
wristband :after_authentication => :do_something
|
77
|
+
|
78
|
+
|
79
|
+
[:plain_text_password] If true the password won't be encrypted. Default: false
|
80
|
+
|
81
|
+
wristband :plain_text_password => true
|
82
|
+
|
83
|
+
[:has_authorities] If true the password won't be encrypted. Default: false
|
84
|
+
|
85
|
+
wristband :plain_text_password => true
|
86
|
+
|
87
|
+
==== Remarks:
|
88
|
+
|
89
|
+
* While password_crypt is limited to 40 characters, the standard output of the hashing function used to encrypt it, there is no such limit on the length of the password as input by the user.
|
90
|
+
* There are no default restrictions on the content of the username. These should be added as required.
|
91
|
+
* A user's password is stored encrypted by default but support for plain- text passwords is also provided. Leaving 'password_salt' as blank or nil means the password is not encrypted. This makes the content of user
|
92
|
+
fixtures easy to read and understand.
|
93
|
+
* The 'remember_token' field is used for login authentication via persistent cookie. This value changes each time the user's password is reassigned.
|
94
|
+
|
95
|
+
|
96
|
+
== Functionality
|
97
|
+
|
98
|
+
=== 1. Remember me
|
99
|
+
If you want to automatically login a user when he comes back to your site, add <tt>before_filter :login_from_cookie</tt> to your AplicationController.
|
100
|
+
|
101
|
+
=== 2. Authority Definitions
|
102
|
+
|
103
|
+
Check the documentation on the link:files/lib/authority_check_rb.html file
|
104
|
+
|
105
|
+
==== Other Reading
|
106
|
+
|
107
|
+
"The Emerging Standards Bureau" on naming methods
|
108
|
+
http://giantrobots.thoughtbot.com/2008/4/10/the-emerging-standards-bureau
|
109
|
+
|
110
|
+
|
111
|
+
== Database configuration
|
112
|
+
|
113
|
+
The generator gives you a head start.
|
114
|
+
The basic columns are defined as such:
|
115
|
+
|
116
|
+
create_table :users do |t|
|
117
|
+
t.string :email
|
118
|
+
t.string :password_crypt, :limit => 40
|
119
|
+
t.string :password_salt, :limit => 40
|
120
|
+
t.string :remember_token
|
121
|
+
t.string :email_validation_key
|
122
|
+
t.string :role
|
123
|
+
t.datetime :created_at
|
124
|
+
t.datetime :updated_at
|
125
|
+
# Add your own stuff here ...
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
desc 'Default: run unit tests.'
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
desc 'Test the wristband plugin.'
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
desc 'Generate documentation for the wristband plugin.'
|
20
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
21
|
+
rdoc.rdoc_dir = 'rdoc'
|
22
|
+
rdoc.title = 'Wristband'
|
23
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
24
|
+
rdoc.rdoc_files.include('README')
|
25
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
Echoe.new('wristband', '1.0.0') do |p|
|
30
|
+
p.description = "Simplifies the process of authenticating and authorizing users."
|
31
|
+
p.url = "http://github.com/theworkinggroup/wristband"
|
32
|
+
p.author = "Jack Neto"
|
33
|
+
p.email = "jack@theworkinggroup.ca"
|
34
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
35
|
+
p.development_dependencies = []
|
36
|
+
end
|
37
|
+
|
38
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
39
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# This file was generated by the acts_as_authenticated_user plugin
|
3
|
+
# Edit as needed ...
|
4
|
+
#
|
5
|
+
# More details at http://www.theworkinggroup.ca/rails/plugins/wristband
|
6
|
+
# -----------------------------------------------
|
7
|
+
class SessionsController < ApplicationController
|
8
|
+
|
9
|
+
# login_required is defined by the wristband plugin
|
10
|
+
# if the user is not logged in it will call respond_not_logged_in
|
11
|
+
before_filter :login_required, :only => :destroy
|
12
|
+
|
13
|
+
# This one is just usefull to have
|
14
|
+
before_filter :redirect_if_logged_in, :only => [:new, :create]
|
15
|
+
|
16
|
+
def new
|
17
|
+
# ...
|
18
|
+
end
|
19
|
+
|
20
|
+
# Logs the user in
|
21
|
+
# Adjust as necessary
|
22
|
+
def create
|
23
|
+
if @user = authenticate_and_login(params[:user][:username], params[:user][:password], params[:user][:remember_me]=='1')
|
24
|
+
flash[:notice] = "Welcome, you are now logged in."
|
25
|
+
redirect_to users_path
|
26
|
+
else
|
27
|
+
flash[:notice] = 'Login failed.'
|
28
|
+
redirect_to login_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Logs out the user
|
33
|
+
# Adjust as necessary
|
34
|
+
def destroy
|
35
|
+
logout
|
36
|
+
redirect_to home_path
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def redirect_if_logged_in
|
41
|
+
redirect_to home_path if logged_in?
|
42
|
+
end
|
43
|
+
|
44
|
+
# This will be called by the login_required filter when the user is not logged in
|
45
|
+
# You can replace this with whatever you want.
|
46
|
+
# You can also move this to Application controller so it can be shared with other controllers.
|
47
|
+
def respond_not_logged_in
|
48
|
+
redirect_to login_path
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# This file was generated by the acts_as_authenticated_user plugin
|
3
|
+
# Edit as needed ...
|
4
|
+
#
|
5
|
+
# More details at http://www.theworkinggroup.ca/rails/plugins/wristband
|
6
|
+
# -----------------------------------------------
|
7
|
+
class UsersController < ApplicationController
|
8
|
+
|
9
|
+
# login_required is defined by the wristband plugin
|
10
|
+
# if the user is not logged in it will call respond_not_logged_in
|
11
|
+
before_filter :login_required
|
12
|
+
|
13
|
+
|
14
|
+
def verify_email
|
15
|
+
@user = User.verify_email!(params[:email_validation_key])
|
16
|
+
flash[:notice] = 'Your email address has been verified. You may now login to your account.'
|
17
|
+
redirect_to login_path
|
18
|
+
rescue UserVerificationError => error
|
19
|
+
flash[:error] = error.message
|
20
|
+
redirect_to login_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def forgot_password
|
24
|
+
if request.post?
|
25
|
+
if @user = User.find_by_username(params[:user][:username])
|
26
|
+
@user.password = Wristband::Support.random_string(6)
|
27
|
+
@user.save!
|
28
|
+
UserNotifier::deliver_forgot_password(@user)
|
29
|
+
flash[:notice] = 'A new password has been generated and emailed to the address you entered.'
|
30
|
+
redirect_to login_path and return
|
31
|
+
else
|
32
|
+
@user = User.new
|
33
|
+
@user.errors.add("email", "Cannot find that email address, did you mistype?")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
private
|
40
|
+
# This will be called by the login_required filter when the user is not logged in
|
41
|
+
# You can replace this with whatever you want.
|
42
|
+
# You can also move this to Application controller so it can be shared with other controllers.
|
43
|
+
def respond_not_logged_in
|
44
|
+
redirect_to login_path
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# This file was generated by the acts_as_authenticated_user plugin
|
3
|
+
# Edit as needed ...
|
4
|
+
#
|
5
|
+
# More details at http://www.theworkinggroup.ca/rails/plugins/wristband
|
6
|
+
# -----------------------------------------------
|
7
|
+
class User < ActiveRecord::Base
|
8
|
+
|
9
|
+
# Add your own stuff here...
|
10
|
+
# Possible options are:
|
11
|
+
#
|
12
|
+
# :login_with
|
13
|
+
# The fields a user will be validated againts.
|
14
|
+
# Defaults to :username
|
15
|
+
#
|
16
|
+
# :password_column
|
17
|
+
# Sets the name of your password column.
|
18
|
+
# If :plain_text_password => true it defaults to :password otherwise it defaults to :password_crypt
|
19
|
+
#
|
20
|
+
# :plain_text_password
|
21
|
+
# Defaults to false
|
22
|
+
#
|
23
|
+
# :before_authentication
|
24
|
+
# Stuff you may want to do before authentication
|
25
|
+
#
|
26
|
+
# :after_authentication
|
27
|
+
# Stuff you may want to do after authentication
|
28
|
+
#
|
29
|
+
wristband
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# This file was generated by the acts_as_authenticated_user plugin
|
3
|
+
# Edit as needed ...
|
4
|
+
#
|
5
|
+
# More details at http://www.theworkinggroup.ca/rails/plugins/wristband
|
6
|
+
# -----------------------------------------------
|
7
|
+
class UserNotifier < ActionMailer::Base
|
8
|
+
# Define on you config/environments folder:
|
9
|
+
# development:
|
10
|
+
# HOST_NAME = 'localhost:3000'
|
11
|
+
# SITE_URL = 'http://localhost:3000'
|
12
|
+
# FROM_EMAIL = 'your_email@your_domain.com'
|
13
|
+
# test:
|
14
|
+
# HOST_NAME = 'localhost:3000'
|
15
|
+
# SITE_URL = 'http://localhost:3000'
|
16
|
+
# FROM_EMAIL = 'your_email@your_domain.com'
|
17
|
+
# staging:
|
18
|
+
# HOST_NAME = 'staging.yourapp.com'
|
19
|
+
# SITE_URL = 'http://staging.yourapp.com'
|
20
|
+
# FROM_EMAIL = 'info@staging.yourapp.com'
|
21
|
+
# production:
|
22
|
+
# HOST_NAME = 'yourapp.com'
|
23
|
+
# SITE_URL = 'http://www.yourapp.com'
|
24
|
+
# FROM_EMAIL = 'info@yourapp.com'
|
25
|
+
|
26
|
+
default_url_options[:host] = HOST_NAME
|
27
|
+
|
28
|
+
def email_verification(user)
|
29
|
+
setup_email(user)
|
30
|
+
@subject += "Your account has been created. Please verify your email address"
|
31
|
+
end
|
32
|
+
|
33
|
+
def forgot_password(user)
|
34
|
+
setup_email(user)
|
35
|
+
@subject += "You have requested a new password"
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
protected
|
40
|
+
# Change YourApp to whatever you application is called
|
41
|
+
def setup_email(user)
|
42
|
+
@recipients = user.email
|
43
|
+
@body[:user] = user
|
44
|
+
@from = FROM_EMAIL
|
45
|
+
@subject = case ENV['RAILS_ENV']
|
46
|
+
when 'development': "[YourApp Development] "
|
47
|
+
when 'staging': "[YourApp Staging] "
|
48
|
+
else "[YourApp] "
|
49
|
+
end
|
50
|
+
@sent_on = Time.now
|
51
|
+
headers "Reply-to" => FROM_EMAIL
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
%h1 Login
|
2
|
+
|
3
|
+
= error_messages_for :user
|
4
|
+
- form_for :user, @user, :url => sessions_path, :builder => CustomForm do |f|
|
5
|
+
= f.text_field :username
|
6
|
+
= f.password_field :password
|
7
|
+
= f.check_box :remember_me, :label => 'Remember me when I come back'
|
8
|
+
= f.submit 'Log In'
|
9
|
+
|
10
|
+
|
11
|
+
%p
|
12
|
+
Did you forget your password?
|
13
|
+
= link_to 'Recover it here.', forgot_password_path
|
14
|
+
%p
|
15
|
+
If you don't have a login yet, click
|
16
|
+
= link_to 'here', register_path
|
17
|
+
to register.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<p>Hi,</p>
|
2
|
+
|
3
|
+
<p>A new password was requested for this email address.</p>
|
4
|
+
|
5
|
+
<p>Your new password is: <b><%= @user.password %></b> </p>
|
6
|
+
|
7
|
+
<p><%= link_to 'Click here to login', login_url %>.</p>
|
8
|
+
<p>Once you have logged in, you can edit your profile and change your password to something you can easily remember.</p>
|
9
|
+
|
10
|
+
<p>Thanks</p>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Hi,
|
2
|
+
|
3
|
+
A new password was requested for this email address.
|
4
|
+
|
5
|
+
Your new password is: <b><%= @user.password %></b>
|
6
|
+
|
7
|
+
To login go to: <%= login_url %>.
|
8
|
+
Once you have logged in, you can edit your profile and change your password to something you can easily remember.
|
9
|
+
|
10
|
+
Thanks
|
@@ -0,0 +1,10 @@
|
|
1
|
+
%h1 Password Recovery
|
2
|
+
|
3
|
+
%p
|
4
|
+
If you have forgotten your Password, please enter your email address below.
|
5
|
+
%br/
|
6
|
+
You will be sent an email with new login information.
|
7
|
+
|
8
|
+
- form_for :user, @user, :url => forgot_password_path do |f|
|
9
|
+
= f.text_field :email, :label => 'Your Email:'
|
10
|
+
= f.submit 'Recover Username/Password', link_to('Cancel', login_path)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# This file was generated by the wristband plugin
|
3
|
+
# Edit as needed ...
|
4
|
+
#
|
5
|
+
# More details at http://www.theworkinggroup.ca/rails/plugins/wristband
|
6
|
+
# -----------------------------------------------
|
7
|
+
class CreateWristbandTables < ActiveRecord::Migration
|
8
|
+
def self.up
|
9
|
+
create_table :users do |t|
|
10
|
+
# uncomment if you want a username in addition to an email
|
11
|
+
# t.string :username
|
12
|
+
t.string :email
|
13
|
+
t.string :password_crypt, :limit => 40
|
14
|
+
t.string :password_salt, :limit => 40
|
15
|
+
t.string :remember_token
|
16
|
+
t.string :email_validation_key
|
17
|
+
t.datetime :validated_at
|
18
|
+
t.string :role
|
19
|
+
t.datetime :created_at
|
20
|
+
t.datetime :updated_at
|
21
|
+
# Add your own stuff here ...
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.down
|
26
|
+
drop_table :users
|
27
|
+
end
|
28
|
+
end
|