innetra-easy_authentication 0.1.0

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 (51) hide show
  1. data/Rakefile +14 -0
  2. data/easy_authentication.gemspec +32 -0
  3. data/generators/easy_authentication/easy_authentication_generator.rb +163 -0
  4. data/generators/easy_authentication/templates/controllers/roles_controller.rb +79 -0
  5. data/generators/easy_authentication/templates/controllers/sessions_controller.rb +44 -0
  6. data/generators/easy_authentication/templates/controllers/user_password_controller.rb +82 -0
  7. data/generators/easy_authentication/templates/controllers/user_roles_controller.rb +34 -0
  8. data/generators/easy_authentication/templates/controllers/users_controller.rb +72 -0
  9. data/generators/easy_authentication/templates/helpers/form_helper.rb +5 -0
  10. data/generators/easy_authentication/templates/helpers/shadowbox_helper.rb +23 -0
  11. data/generators/easy_authentication/templates/layouts/easy_authentication.erb +40 -0
  12. data/generators/easy_authentication/templates/layouts/easy_authentication_login.erb +22 -0
  13. data/generators/easy_authentication/templates/locales/en.easy_authentication.yml +84 -0
  14. data/generators/easy_authentication/templates/locales/es-MX.easy_authentication.yml +100 -0
  15. data/generators/easy_authentication/templates/migrations/easy_authentication.rb +54 -0
  16. data/generators/easy_authentication/templates/models/right.rb +2 -0
  17. data/generators/easy_authentication/templates/models/role.rb +12 -0
  18. data/generators/easy_authentication/templates/models/user.rb +3 -0
  19. data/generators/easy_authentication/templates/models/user_mailer.rb +0 -0
  20. data/generators/easy_authentication/templates/site_keys.rb +2 -0
  21. data/generators/easy_authentication/templates/stylesheets/default.css +249 -0
  22. data/generators/easy_authentication/templates/stylesheets/login.css +111 -0
  23. data/generators/easy_authentication/templates/stylesheets/roles.css +26 -0
  24. data/generators/easy_authentication/templates/stylesheets/users.css +21 -0
  25. data/generators/easy_authentication/templates/views/roles/_form.html.erb +37 -0
  26. data/generators/easy_authentication/templates/views/roles/edit.html.erb +19 -0
  27. data/generators/easy_authentication/templates/views/roles/index.html.erb +21 -0
  28. data/generators/easy_authentication/templates/views/roles/new.html.erb +19 -0
  29. data/generators/easy_authentication/templates/views/roles/show.html.erb +30 -0
  30. data/generators/easy_authentication/templates/views/sessions/new.html.erb +25 -0
  31. data/generators/easy_authentication/templates/views/user_password/edit.html.erb +35 -0
  32. data/generators/easy_authentication/templates/views/user_password/forgot_password.html.erb +16 -0
  33. data/generators/easy_authentication/templates/views/user_password/reset_password.html.erb +22 -0
  34. data/generators/easy_authentication/templates/views/user_roles/edit.html.erb +27 -0
  35. data/generators/easy_authentication/templates/views/users/_form.html.erb +47 -0
  36. data/generators/easy_authentication/templates/views/users/_user.html.erb +4 -0
  37. data/generators/easy_authentication/templates/views/users/edit.html.erb +14 -0
  38. data/generators/easy_authentication/templates/views/users/index.html.erb +21 -0
  39. data/generators/easy_authentication/templates/views/users/new.html.erb +14 -0
  40. data/generators/easy_authentication/templates/views/users/show.html.erb +53 -0
  41. data/init.rb +5 -0
  42. data/lib/controller_methods.rb +14 -0
  43. data/lib/cookie_authentication.rb +63 -0
  44. data/lib/helper_methods.rb +198 -0
  45. data/lib/password_authentication.rb +64 -0
  46. data/lib/user_methods.rb +109 -0
  47. data/tasks/rights.rake +35 -0
  48. data/tasks/sysadmin.rake +27 -0
  49. data/test/easy_authentication_test.rb +8 -0
  50. data/test/test_helper.rb +3 -0
  51. metadata +113 -0
@@ -0,0 +1,4 @@
1
+ <div class="user_actions">
2
+ <%%= link_to t("users.actions.change_password_link"), edit_user_password_url(current_user) %>&nbsp;|
3
+ <%%= link_to t("users.actions.logout_link"), logout_url %>
4
+ </div>
@@ -0,0 +1,14 @@
1
+ <%% content_for :header do -%>
2
+ <%%= stylesheet_link_tag "easy_authentication/users", :media => :all %>
3
+ <%% end -%>
4
+
5
+ <h1>
6
+ <div class="title_actions">
7
+ <%%= link_to t("users.edit.cancel"), @user %>
8
+ </div>
9
+ <%%= t("users.edit.title", :full_name => @user.full_name, :login => @user.login) %>
10
+ </h1>
11
+
12
+ <%% form_for @user do |form| %>
13
+ <%%= render :partial => form %>
14
+ <%% end %>
@@ -0,0 +1,21 @@
1
+ <%% content_for :header do -%>
2
+ <%%= stylesheet_link_tag "easy_authentication/users", :media => :all %>
3
+ <%% end -%>
4
+
5
+ <%% content_for :sidebar do -%>
6
+ <%% shadowbox "users_actions", :class => "sidebar_section" do %>
7
+ <%%= link_to t("users.index.new_link"), new_user_url %>
8
+ <%% end %>
9
+ <%% end -%>
10
+
11
+ <h1><%%= t "users.index.title" %></h1>
12
+
13
+ <ul>
14
+ <%% for user in @users -%>
15
+ <%% content_tag_for(:li, user) do %>
16
+ <%%= link_to user.full_name, user, :class => "full_name important" %>
17
+ (<%%= user.login %>)<br />
18
+ <%%= auto_link user.email %>
19
+ <%% end %>
20
+ <%% end -%>
21
+ </ul>
@@ -0,0 +1,14 @@
1
+ <%% content_for :header do -%>
2
+ <%%= stylesheet_link_tag "easy_authentication/users", :media => :all %>
3
+ <%% end -%>
4
+
5
+ <h1>
6
+ <div class="title_actions">
7
+ <%%= link_to t("users.new.cancel"), users_url %>
8
+ </div>
9
+ <%%= t "users.new.title" %>
10
+ </h1>
11
+
12
+ <%% form_for @user do |form| %>
13
+ <%%= render :partial => form %>
14
+ <%% end %>
@@ -0,0 +1,53 @@
1
+ <%% content_for :header do -%>
2
+ <%%= stylesheet_link_tag "easy_authentication/users", :media => :all %>
3
+ <%% end -%>
4
+
5
+ <%% content_for :sidebar do -%>
6
+ <%% shadowbox "user_details", :class => "sidebar_section" do %>
7
+ <h1>
8
+ <div class="title_actions">
9
+ <%%= link_to t("users.show.user_details.edit_link"), edit_user_url(@user) %>
10
+ </div>
11
+ <%%= t("users.show.user_details.title") %>
12
+ </h1>
13
+ <table>
14
+ <tr>
15
+ <td class="label"><%%= t("users.show.user_details.login") %></td>
16
+ <td><%%= @user.login %></td>
17
+ </tr>
18
+ <tr>
19
+ <td class="label"><%%= t("users.show.user_details.email") %></td>
20
+ <td><%%= auto_link @user.email %></td>
21
+ </tr>
22
+ </table>
23
+ <%% end %>
24
+
25
+ <%% shadowbox "roles_section", :class => "sidebar_section" do %>
26
+ <h1>
27
+ <div class="title_actions">
28
+ <%%= link_to t("users.show.roles_section.edit_link"), edit_user_role_url(@user) %>
29
+ </div>
30
+ <%%= t("users.show.roles_section.title") %>
31
+ </h1>
32
+ <%% unless @user.roles.blank? -%>
33
+ <ul>
34
+ <%% for role in @user.roles -%>
35
+ <%% content_tag_for(:li, role) do -%>
36
+ <%%= role.name %>
37
+ <%% end -%>
38
+ <%% end -%>
39
+ </ul>
40
+ <%% end -%>
41
+ <%% end %>
42
+
43
+ <%% shadowbox "password_section", :class => "sidebar_section" do %>
44
+ <%%= link_to t("users.show.password_section.edit_link"), edit_user_url(@user) %>
45
+ <%% end %>
46
+
47
+ <%% end -%>
48
+ <h1>
49
+ <div class="title_actions">
50
+ <%%= link_to t("users.show.back"), users_url %>
51
+ </div>
52
+ <%%= @user.full_name %>
53
+ </h1>
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/lib/cookie_authentication'
2
+ require File.dirname(__FILE__) + '/lib/password_authentication'
3
+ require File.dirname(__FILE__) + '/lib/user_methods'
4
+ require File.dirname(__FILE__) + '/lib/helper_methods'
5
+ require File.dirname(__FILE__) + '/lib/controller_methods'
@@ -0,0 +1,14 @@
1
+ module EasyAuthentication
2
+ module ControllerMethods
3
+ def self.included(recipient)
4
+ recipient.class_eval do
5
+ # Requires valid user credentials on all actions and controllers
6
+ before_filter :login_required
7
+ # Filter password from log
8
+ filter_parameter_logging :password
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ ActionController::Base.send :include, EasyAuthentication::ControllerMethods
@@ -0,0 +1,63 @@
1
+ module EasyAuthentication
2
+ module CookieAuthentication
3
+
4
+ # Mixin
5
+ def self.included(recipient)
6
+ recipient.extend(ClassMethods)
7
+ recipient.class_eval do
8
+ include InstanceMethods
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ def secure_digest(*args)
14
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
15
+ end
16
+
17
+ def make_token
18
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
19
+ end
20
+ end # ClassMethods
21
+
22
+ module InstanceMethods
23
+ def remember_token?
24
+ (!remember_token.blank?) &&
25
+ remember_token_expires_at && (Time.now.utc < remember_token_expires_at.utc)
26
+ end
27
+
28
+ def remember_me
29
+ remember_me_for 2.weeks
30
+ end
31
+
32
+ def remember_me_for(time)
33
+ remember_me_until time.from_now.utc
34
+ end
35
+
36
+ def remember_me_until(time)
37
+ self.remember_token_expires_at = time
38
+ self.remember_token = self.class.make_token
39
+ save(false)
40
+ end
41
+
42
+ # refresh token (keeping same expires_at) if it exists
43
+ def refresh_token
44
+ if remember_token?
45
+ self.remember_token = self.class.make_token
46
+ save(false)
47
+ end
48
+ end
49
+
50
+
51
+ # Deletes the server-side record of the authentication token. The
52
+ # client-side (browser cookie) and server-side (this remember_token) must
53
+ # always be deleted together.
54
+ def forget_me
55
+ self.remember_token_expires_at = nil
56
+ self.remember_token = nil
57
+ save(false)
58
+ end
59
+
60
+ end # InstanceMethods
61
+
62
+ end # CookieAuthentication
63
+ end # EasyAuthentication
@@ -0,0 +1,198 @@
1
+ module EasyAuthentication
2
+ module HelperMethods
3
+ protected
4
+ # Returns true or false if the user is logged in.
5
+ # Preloads @current_user with the user model if they're logged in.
6
+ def logged_in?
7
+ !!current_user
8
+ end
9
+
10
+ # Accesses the current user from the session.
11
+ # Future calls avoid the database because nil is not equal to false.
12
+ def current_user
13
+ @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_user == false
14
+ end
15
+
16
+ # Store the given user id in the session.
17
+ def current_user=(new_user)
18
+ session[:user_id] = new_user ? new_user.id : nil
19
+ @current_user = new_user || false
20
+ end
21
+
22
+ # Check if the user is authorized
23
+ #
24
+ # Override this method in your controllers if you want to restrict access
25
+ # to only a few actions or if you want to check if the user
26
+ # has the correct rights.
27
+ #
28
+ # Example:
29
+ #
30
+ # # only allow nonbobs
31
+ # def authorized?
32
+ # current_user.login != "bob"
33
+ # end
34
+ #
35
+ def authorized?
36
+ return false if !current_user
37
+ current_user.authorized?(controller_name, action_name)
38
+ end
39
+
40
+ # Filter method to enforce a login requirement.
41
+ #
42
+ # To require logins for all actions, use this in your controllers:
43
+ #
44
+ # before_filter :login_required
45
+ #
46
+ # To require logins for specific actions, use this in your controllers:
47
+ #
48
+ # before_filter :login_required, :only => [ :edit, :update ]
49
+ #
50
+ # To skip this in a subclassed controller:
51
+ #
52
+ # skip_before_filter :login_required
53
+ #
54
+ def login_required
55
+ (logged_in? && authorized?) || access_denied
56
+ end
57
+
58
+ # Redirect as appropriate when an access request fails.
59
+ #
60
+ # The default action is to redirect to the login screen.
61
+ #
62
+ # Override this method in your controllers if you want to have special
63
+ # behavior in case the user is not authorized
64
+ # to access the requested action. For example, a popup window might
65
+ # simply close itself.
66
+ def access_denied
67
+ respond_to do |format|
68
+ format.html do
69
+ store_location
70
+ if current_user.blank?
71
+ redirect_to login_url
72
+ else
73
+ flash[:error] = t("easy_authentication.access_denied")
74
+ redirect_to :back
75
+ end
76
+ end
77
+ # format.any doesn't work in rails version < http://dev.rubyonrails.org/changeset/8987
78
+ # Add any other API formats here. (Some browsers, notably IE6, send Accept: */* and trigger
79
+ # the 'format.any' block incorrectly. See http://bit.ly/ie6_borken or http://bit.ly/ie6_borken2
80
+ # for a workaround.)
81
+ format.any(:json, :xml) do
82
+ request_http_basic_authentication 'Web Password'
83
+ end
84
+ end
85
+ end
86
+
87
+ # Store the URI of the current request in the session.
88
+ #
89
+ # We can return to this location by calling #redirect_back_or_default.
90
+ def store_location
91
+ session[:return_to] = request.request_uri
92
+ end
93
+
94
+ # Redirect to the URI stored by the most recent store_location call or
95
+ # to the passed default. Set an appropriately modified
96
+ # after_filter :store_location, :only => [:index, :new, :show, :edit]
97
+ # for any controller you want to be bounce-backable.
98
+ def redirect_back_or_default(default)
99
+ redirect_to(session[:return_to] || default)
100
+ session[:return_to] = nil
101
+ end
102
+
103
+ # Inclusion hook to make #current_user and #logged_in?
104
+ # available as ActionView helper methods.
105
+ def self.included(base)
106
+ base.send :helper_method, :current_user, :logged_in?, :authorized? if base.respond_to? :helper_method
107
+ end
108
+
109
+ #
110
+ # Login
111
+ #
112
+
113
+ # Called from #current_user. First attempt to login by the user id stored in the session.
114
+ def login_from_session
115
+ self.current_user = User.find_by_id(session[:user_id]) if session[:user_id]
116
+ end
117
+
118
+ # Called from #current_user. Now, attempt to login by basic authentication information.
119
+ def login_from_basic_auth
120
+ authenticate_with_http_basic do |login, password|
121
+ self.current_user = User.authenticate(login, password)
122
+ end
123
+ end
124
+
125
+ #
126
+ # Logout
127
+ #
128
+
129
+ # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
130
+ # for the paranoid: we _should_ be storing user_token = hash(cookie_token, request IP)
131
+ def login_from_cookie
132
+ user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
133
+ if user && user.remember_token?
134
+ self.current_user = user
135
+ handle_remember_cookie! false # freshen cookie token (keeping date)
136
+ self.current_user
137
+ end
138
+ end
139
+
140
+ # This is ususally what you want; resetting the session willy-nilly wreaks
141
+ # havoc with forgery protection, and is only strictly necessary on login.
142
+ # However, **all session state variables should be unset here**.
143
+ def logout_keeping_session!
144
+ # Kill server-side auth cookie
145
+ @current_user.forget_me if @current_user.is_a? User
146
+ @current_user = false # not logged in, and don't do it for me
147
+ kill_remember_cookie! # Kill client-side auth cookie
148
+ session[:user_id] = nil # keeps the session but kill our variable
149
+ # explicitly kill any other session variables you set
150
+ end
151
+
152
+ # The session should only be reset at the tail end of a form POST --
153
+ # otherwise the request forgery protection fails. It's only really necessary
154
+ # when you cross quarantine (logged-out to logged-in).
155
+ def logout_killing_session!
156
+ logout_keeping_session!
157
+ reset_session
158
+ end
159
+
160
+ #
161
+ # Remember_me Tokens
162
+ #
163
+ # Cookies shouldn't be allowed to persist past their freshness date,
164
+ # and they should be changed at each login
165
+
166
+ # Cookies shouldn't be allowed to persist past their freshness date,
167
+ # and they should be changed at each login
168
+
169
+ def valid_remember_cookie?
170
+ return nil unless @current_user
171
+ (@current_user.remember_token?) &&
172
+ (cookies[:auth_token] == @current_user.remember_token)
173
+ end
174
+
175
+ # Refresh the cookie auth token if it exists, create it otherwise
176
+ def handle_remember_cookie!(new_cookie_flag)
177
+ return unless @current_user
178
+ case
179
+ when valid_remember_cookie? then @current_user.refresh_token # keeping same expiry date
180
+ when new_cookie_flag then @current_user.remember_me
181
+ else @current_user.forget_me
182
+ end
183
+ send_remember_cookie!
184
+ end
185
+
186
+ def kill_remember_cookie!
187
+ cookies.delete :auth_token
188
+ end
189
+
190
+ def send_remember_cookie!
191
+ cookies[:auth_token] = {
192
+ :value => @current_user.remember_token,
193
+ :expires => @current_user.remember_token_expires_at }
194
+ end
195
+ end # EasyAuthentication::UserHelper
196
+ end # EasyAuthentication
197
+
198
+ ActionController::Base.send :include, EasyAuthentication::HelperMethods
@@ -0,0 +1,64 @@
1
+ module EasyAuthentication
2
+ module PasswordAuthentication
3
+
4
+ # Mixin
5
+ def self.included(recipient)
6
+ recipient.extend(ClassMethods)
7
+ recipient.class_eval do
8
+
9
+ include InstanceMethods
10
+
11
+ # Virtual attribute for the unencrypted password
12
+ attr_accessor :password
13
+
14
+ validates_presence_of :password, :if => :password_required?
15
+ validates_presence_of :password_confirmation, :if => :password_required?
16
+ validates_confirmation_of :password, :if => :password_required?
17
+ validates_length_of :password, :minimum => 6, :if => :password_required?
18
+
19
+ before_save :encrypt_password
20
+
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ # This provides a modest increased defense against a dictionary attack if
26
+ # your db were ever compromised, but will invalidate existing passwords.
27
+ # See the README and the file config/initializers/site_keys.rb
28
+ #
29
+ # It may not be obvious, but if you set REST_AUTH_SITE_KEY to nil and
30
+ # REST_AUTH_DIGEST_STRETCHES to 1 you'll have backwards compatibility with
31
+ # older versions of restful-authentication.
32
+ def password_digest(password, salt)
33
+ digest = AUTH_SITE_KEY
34
+ AUTH_DIGEST_STRETCHES.times do
35
+ digest = secure_digest(digest, salt, password, AUTH_SITE_KEY)
36
+ end
37
+ digest
38
+ end
39
+ end # ClassMethods
40
+
41
+ module InstanceMethods
42
+ # Encrypts the password with the user salt
43
+ def encrypt(password)
44
+ self.class.password_digest(password, password_salt)
45
+ end
46
+
47
+ def authenticated?(password)
48
+ password_hash == encrypt(password)
49
+ end
50
+
51
+ # before filter
52
+ def encrypt_password
53
+ return if password.blank?
54
+ self.password_salt = self.class.make_token if new_record?
55
+ self.password_hash = encrypt(password)
56
+ end
57
+
58
+ def password_required?
59
+ password_hash.blank? || (!password.blank? || !current_password.blank?)
60
+ end
61
+ end # InstanceMethods
62
+
63
+ end # PasswordAuthentication
64
+ end # EasyAuthentication