ioquatix-account_engine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/README +0 -0
  2. data/lib/account_engine/configuration.rb +101 -0
  3. data/lib/account_engine/controller.rb +246 -0
  4. data/lib/account_engine/helper.rb +104 -0
  5. data/lib/account_engine/password.rb +432 -0
  6. data/lib/account_engine/support.rb +12 -0
  7. data/lib/account_engine/user_account/class_methods.rb +63 -0
  8. data/lib/account_engine/user_account.rb +184 -0
  9. data/lib/account_engine.rb +63 -0
  10. data/rails/app/controllers/account_controller.rb +162 -0
  11. data/rails/app/controllers/permissions_controller.rb +90 -0
  12. data/rails/app/controllers/roles_controller.rb +133 -0
  13. data/rails/app/controllers/users_controller.rb +144 -0
  14. data/rails/app/helpers/account_helper.rb +3 -0
  15. data/rails/app/helpers/permissions_helper.rb +3 -0
  16. data/rails/app/helpers/roles_helper.rb +3 -0
  17. data/rails/app/helpers/users_helper.rb +3 -0
  18. data/rails/app/models/permission.rb +129 -0
  19. data/rails/app/models/role.rb +60 -0
  20. data/rails/app/models/user.rb +5 -0
  21. data/rails/app/models/user_notify.rb +75 -0
  22. data/rails/app/views/account/_form.rhtml +8 -0
  23. data/rails/app/views/account/change_password.rhtml +17 -0
  24. data/rails/app/views/account/edit.rhtml +5 -0
  25. data/rails/app/views/account/forgot_password.rhtml +12 -0
  26. data/rails/app/views/account/home.rhtml +3 -0
  27. data/rails/app/views/account/login.rhtml +27 -0
  28. data/rails/app/views/account/logout.rhtml +8 -0
  29. data/rails/app/views/account/signup.rhtml +28 -0
  30. data/rails/app/views/permissions/_form.rhtml +14 -0
  31. data/rails/app/views/permissions/_list.rhtml +38 -0
  32. data/rails/app/views/permissions/edit.rhtml +5 -0
  33. data/rails/app/views/permissions/index.rhtml +3 -0
  34. data/rails/app/views/permissions/new.rhtml +5 -0
  35. data/rails/app/views/roles/_form.rhtml +8 -0
  36. data/rails/app/views/roles/_permissions.rhtml +25 -0
  37. data/rails/app/views/roles/edit.rhtml +5 -0
  38. data/rails/app/views/roles/index.rhtml +34 -0
  39. data/rails/app/views/roles/new.rhtml +5 -0
  40. data/rails/app/views/roles/show.rhtml +20 -0
  41. data/rails/app/views/user_notify/change_password.rhtml +10 -0
  42. data/rails/app/views/user_notify/delete.rhtml +5 -0
  43. data/rails/app/views/user_notify/forgot_password.rhtml +11 -0
  44. data/rails/app/views/user_notify/pending_delete.rhtml +9 -0
  45. data/rails/app/views/user_notify/signup.rhtml +12 -0
  46. data/rails/app/views/users/_form.rhtml +12 -0
  47. data/rails/app/views/users/edit.rhtml +5 -0
  48. data/rails/app/views/users/index.rhtml +38 -0
  49. data/rails/app/views/users/new.rhtml +5 -0
  50. data/rails/app/views/users/roles.rhtml +42 -0
  51. data/rails/app/views/users/show.rhtml +36 -0
  52. data/rails/assets/images/default/omnipotent.png +0 -0
  53. data/rails/assets/images/default/system.png +0 -0
  54. data/rails/assets/images/permissions/create.png +0 -0
  55. data/rails/assets/images/permissions/sync.png +0 -0
  56. data/rails/assets/images/roles/add_permission.png +0 -0
  57. data/rails/assets/images/roles/create.png +0 -0
  58. data/rails/assets/images/roles/edit.png +0 -0
  59. data/rails/assets/images/roles/remove_permission.png +0 -0
  60. data/rails/assets/images/roles/user.png +0 -0
  61. data/rails/assets/images/table_background.png +0 -0
  62. data/rails/assets/images/users/create.png +0 -0
  63. data/rails/assets/images/users/destroy.png +0 -0
  64. data/rails/assets/images/users/edit.png +0 -0
  65. data/rails/assets/images/users/show.png +0 -0
  66. data/rails/assets/javascripts/account_engine.js +166 -0
  67. data/rails/assets/stylesheets/account_engine.css +7 -0
  68. data/rails/assets/stylesheets/check_password.css +10 -0
  69. data/rails/assets/stylesheets/simple.css +168 -0
  70. data/rails/db/migrate/001_initial_schema.rb +49 -0
  71. data/rails/init.rb +21 -0
  72. data/rails/routes.rb +5 -0
  73. data/rails/tasks/account_engine.rake +123 -0
  74. metadata +165 -0
data/README ADDED
File without changes
@@ -0,0 +1,101 @@
1
+ # Configuration
2
+ module AccountEngine
3
+ # These are the default constants, used if nothing else is specified
4
+ mattr_accessor :email_charset, :site_email, :admin_email, :app_url, :app_name
5
+ mattr_accessor :generate_password, :validate_email, :salt, :security_token_life_hours
6
+ mattr_accessor :confirm_account, :use_email_notification
7
+ mattr_reader :registration
8
+
9
+ def self.registration=(r)
10
+ if [:open, :closed].include? r
11
+ @@registration = r
12
+ end
13
+ end
14
+
15
+ mattr_accessor :guest_role_name, :user_role_name
16
+ mattr_accessor :admin_role_name, :admin_login, :admin_password, :admin_email
17
+
18
+ mattr_accessor :login_page, :logout_page, :stealth
19
+
20
+ mattr_accessor :users_table, :roles_table, :permissions_table
21
+
22
+ # The names of the new Role and Permission tables
23
+ if ActiveRecord::Base.pluralize_table_names
24
+ @@users_table = "users"
25
+ @@roles_table = "roles"
26
+ @@permissions_table = "permissions"
27
+ else
28
+ @@users_table = "user"
29
+ @@roles_table = "role"
30
+ @@permissions_table = "permission"
31
+ end
32
+
33
+ # Join tables for users <-> roles, and roles <-> permissions
34
+ def self.users_roles_table
35
+ "#{AccountEngine.users_table}_#{AccountEngine.roles_table}"
36
+ end
37
+
38
+ def self.permissions_roles_table
39
+ "#{AccountEngine.permissions_table}_#{AccountEngine.roles_table}"
40
+ end
41
+
42
+ def self.allow_registration?
43
+ return (@@registration == :open ? true : false)
44
+ end
45
+
46
+ #Generate random passwords
47
+ @@generate_password = true
48
+
49
+ # Source address for user emails
50
+ @@site_email = 'root@localhost'
51
+
52
+ # Destination email for system errors
53
+ @@admin_email = 'root@localhost'
54
+
55
+ # Sent in emails to users
56
+ @@app_url = 'http://localhost:3000/'
57
+
58
+ # Sent in emails to users
59
+ @@app_name = 'My Application'
60
+
61
+ # Whether the model will enforce email validation
62
+ @@validate_email = true
63
+
64
+ # Email charset
65
+ @@email_charset = 'utf-8'
66
+
67
+ # Security token lifetime in hours
68
+ @@security_token_life_hours = 48
69
+
70
+ # Registrations are open to the public
71
+ @@registration = :closed
72
+
73
+ # controls whether or not email is used
74
+ @@use_email_notification = true
75
+
76
+ # Controls whether accounts must be confirmed after signing up
77
+ # ONLY if this and use_email_notification are both true
78
+ @@confirm_account = false
79
+
80
+ # The names of the Guest and User roles
81
+ # The Guest role is automatically assigned to any visitor who is not logged in
82
+ @@guest_role_name = "Guest"
83
+ # The User role is given to every user
84
+ @@user_role_name = "User"
85
+
86
+ # The details for the Admin user and role
87
+ @@admin_role_name = "Administrator"
88
+ @@admin_login = "admin"
89
+ @@admin_password = "test123"
90
+ @@admin_email = "root@localhost"
91
+
92
+ # The controller/action
93
+ @@login_page = {:controller => 'account', :action => 'login'}
94
+
95
+ @@logout_page = {:controller => 'account', :action => 'logout'}
96
+
97
+ # If this is set to true, authorization failure messages won't volunteer
98
+ # any extra information, and missing actions will not be flagged as such.
99
+ @@stealth = false
100
+ end
101
+
@@ -0,0 +1,246 @@
1
+
2
+ require 'account_engine/support'
3
+
4
+ module AccountEngine
5
+ module Controller
6
+ # methods to be added to the ApplicationController
7
+
8
+ include AccountEngine::Support
9
+
10
+ module ClassMethods
11
+
12
+ # Returns an array containing all subclasses of ApplicationController
13
+ def all_controllers
14
+ #ObjectSpace.subclasses_of(ApplicationController)
15
+ subclasses_of(ApplicationController)
16
+ end
17
+ end
18
+
19
+ # Returns an array of all action names for this controller
20
+ # (Actually returns the result of ApplicationController#action_methods, which is private)
21
+ def action_method_names
22
+ action_methods
23
+ end
24
+
25
+ def self.included(base)
26
+ base.extend(ClassMethods)
27
+
28
+ base.class_eval do
29
+ # We don't want these actions to be exposed to the Permission
30
+ # system synchronisation, so we hide them for all controllers.
31
+ hide_action :require_without_load_path_reloading, :process_test
32
+ hide_action :action_method_names, :wsdl, :deepcopy
33
+ hide_action :readable?, :writable?, :r?, :w?, :authorize_action
34
+ hide_action :store_location, :redirect_back_or_default
35
+
36
+ # methods from the AccountEngine module itself
37
+ hide_action :link_if_authorized, :authorized?, :user_name_if_logged_in
38
+ hide_action :user?, :current_user, :logged_in?
39
+ end
40
+ end
41
+
42
+ protected
43
+ # Use this method to log a user in to the system
44
+ def authenticate_user
45
+ # If we are already logged in, return true
46
+ return true if current_user
47
+
48
+ login = params[:login]
49
+ password = params[:password]
50
+ id = params[:user_id]
51
+ key = params[:key]
52
+ user = nil
53
+
54
+ if login and password
55
+ user = User.authenticate(login, password)
56
+ end
57
+
58
+ if id and key and user.nil?
59
+ user = User.authenticate_by_token(id, key)
60
+ end
61
+
62
+ if user
63
+ user.update_attribute(:logged_in_at, Time.now)
64
+ session[:user] = user
65
+ return true
66
+ end
67
+
68
+ return false
69
+ end
70
+
71
+ # overwrite this if you want to restrict access to only a few actions
72
+ # or if you want to check if the user has the correct rights
73
+ # example:
74
+ #
75
+ # # only allow nonbobs
76
+ # def authorized?(user)
77
+ # user.login != "bob"
78
+ # end
79
+ def authorize?(user)
80
+ true
81
+ end
82
+
83
+ # overwrite this method if you only want to protect certain actions of the controller
84
+ # example:
85
+ #
86
+ # # don't protect the login and the about method
87
+ # def protect?(action)
88
+ # if ['action', 'about'].include?(action)
89
+ # return false
90
+ # else
91
+ # return true
92
+ # end
93
+ # end
94
+ def protect?(action)
95
+ true
96
+ end
97
+
98
+ # login_required filter. add
99
+ #
100
+ # before_filter :login_required
101
+ #
102
+ # if the controller should be under any rights management.
103
+ # for finer access control you can overwrite
104
+ #
105
+ # def authorize?(user)
106
+ #
107
+ def login_required
108
+ if not protect?(action_name)
109
+ return true
110
+ end
111
+
112
+ if user? and authorize?(current_user)
113
+ return true
114
+ end
115
+
116
+ if authorize_action
117
+ return true
118
+ end
119
+
120
+ if user?
121
+ # If we are logged in and were denied, we will need to actually back out of the operation
122
+ redirect_to request.env['HTTP_REFERER'] || session['prev_uri'] || "/"
123
+ return false
124
+ end
125
+
126
+ # store current location so that we can
127
+ # come back after the user logged in
128
+ store_location
129
+
130
+ # call overwriteable reaction to unauthorized access
131
+ access_denied
132
+ end
133
+
134
+ # overwrite if you want to have special behavior in case the user is not authorized
135
+ # to access the current operation.
136
+ # the default action is to redirect to the login screen
137
+ # example use :
138
+ # a popup window might just close itself for instance
139
+ def access_denied
140
+ logger.info "Access denied! Action: #{action_name} User: #{current_user}"
141
+ redirect_to AccountEngine.login_page
142
+ return false
143
+ end
144
+
145
+ # store current uri in the session.
146
+ # we can return to this location by calling return_location
147
+ def store_location
148
+ session['return-to'] = request.request_uri
149
+ end
150
+
151
+ # move to the last store_location call or to the passed default one
152
+ def redirect_to_stored_or_default(default=nil)
153
+ if session['return-to'].nil?
154
+ redirect_to default
155
+ else
156
+ redirect_to session['return-to']
157
+ session['return-to'] = nil
158
+ end
159
+ end
160
+
161
+ def redirect_back_or_default(default=nil)
162
+ if request.env["HTTP_REFERER"].nil?
163
+ redirect_to default
164
+ else
165
+ redirect_to(request.env["HTTP_REFERER"]) # same as redirect_to :back
166
+ end
167
+ end
168
+
169
+
170
+ # This method will return true if:
171
+ #
172
+ # * The Guest Role is authorized to perform the current action
173
+ # * The currently logged in user is omnipotent
174
+ # * The currently logged in user has permission to perform the current
175
+ # action.
176
+ #
177
+ # In all other cases, it will return false. This method is a replacement
178
+ # for the +login_required+ method provided by the AccountEngine. If the Guest
179
+ # role does not have permission for the current action, the user will be
180
+ # redirected to the login page (and redirected back to this action upon
181
+ # successful authentication). Users can also authenticate directly via
182
+ # a security token (see AccountEngine for details).
183
+ def authorize_action
184
+ required_permission = "%s/%s" % [ params["controller"], params["action"] ]
185
+ logger.debug "required_perm is #{required_permission}"
186
+
187
+ controller = params["controller"]
188
+ action = params["action"]
189
+
190
+ # EVERYONE should be able to get to the root. This might never come up, but
191
+ # better to be safe than sorry. This condition could just as easily be
192
+ # appended to the Guest check below, but it's clearer up here.
193
+ if (controller == nil && action == nil)
194
+ return true
195
+ end
196
+
197
+ # if the controller wasn't nil, but the action was, then we want to
198
+ # set the action to "index" so we can check authentication properly
199
+ action ||= "index"
200
+
201
+ # If someone is or can be logged in...
202
+ # calling 'user?' from the AccountEngine will ensure that a User is
203
+ # loaded into the session if possible. It could either be there already
204
+ # or via a user_id and security key
205
+ if user?
206
+ # ... then if that logged user is NOT authorised...
207
+
208
+ unless current_user.authorized?(controller, action)
209
+ # YOU... SHALL... NOT... PASS!
210
+
211
+ flash[:message] = "Permission warning: You are not authorized for the action '#{required_permission}'."
212
+
213
+ # Here we are distinguishing between unauthorized actions and actions which do
214
+ # not exist. It *might* be better to employ a 'steath' technique and simple
215
+ # claim that all nonsense actions are unauthorized too... but that can make it
216
+ # difficult to debug.
217
+ if !AccountEngine.stealth
218
+ if Permission.find_by_controller_and_action(controller, action)
219
+
220
+ # This is a real action, but the user is not allowed to perform it.
221
+ allowed_roles = Permission.find_by_controller_and_action(controller, action).roles.collect {|r| r.name}.join(', ')
222
+ your_roles = current_user.roles.collect {|r| r.name}.join(', ')
223
+ flash[:message] << " Allowed Roles: #{allowed_roles}. User '#{current_user.login}' has only the following: #{your_roles}."
224
+
225
+ else # This wasn't even a real action.
226
+ end
227
+ end
228
+
229
+ return false
230
+ end
231
+ else
232
+
233
+ # noone is or can be logged in...
234
+ unless User.guest_user_authorized?(controller, action)
235
+ flash[:message] = "You need to log in."
236
+ return false
237
+ end
238
+ end
239
+
240
+ # If we get here, the user is either a guest and this action is permitted
241
+ # for guest users, or the user is logged in and the action is permitted by
242
+ # one or more of their associated roles. Let them pass..
243
+ return true
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,104 @@
1
+
2
+ require 'account_engine/support'
3
+
4
+ module AccountEngine
5
+ module Helper
6
+ include AccountEngine::Support
7
+
8
+ def link_to_user(user = current_user)
9
+ link_to user.fullname, :controller => 'account', :action => 'show'
10
+ end
11
+
12
+ #--
13
+ # The methods to be included in both ApplicationController and ApplicationHelper
14
+ #++
15
+
16
+ # Returns an HTML link if the user has authorisation to perform the
17
+ # supplied action. All other options and parameters are identical to
18
+ # those for ActionView::link_to
19
+ # e.g.
20
+ # link_if_authorized("Home", {:controller => "home", :action => "index"})
21
+ #
22
+ # If either of the :controller or :action options are ommitted, the
23
+ # current controller or action will be used instead.
24
+ #
25
+ # This method can also take an additional block, which can override the actual
26
+ # user permissions (i.e. the user must have valid permissions AND this block
27
+ # must not return false or nil for the link to be generated).
28
+ #
29
+ # We also provide special elements with the html_options argument.
30
+ #
31
+ # === :wrap_in
32
+ # This can be used to wrap the link in a given tag. This is useful if some
33
+ # surrounding markup to the link should also be ommitted if the user is not
34
+ # authorised for that link. E.g.
35
+ # <ul>
36
+ # <%= link_if_authorised("Delete", {:action => "delete"}, :wrap_in => "li") %>
37
+ # ...
38
+ # </ul>
39
+ #
40
+ # In this case, if the user is not authorised for this link, the <li></li>
41
+ # element will not be generated. Please note that this is fairly simplistic
42
+ # and relies on Rails' own #content_tag method. For more sophisticated
43
+ # control of markup based on authorisation, use the #authorised?() method
44
+ # directly.
45
+ #
46
+ # === :show_text
47
+ # if this flag is set to true, the text given for the link will be shown
48
+ # (although not as a link) even if the use is NOT authorised for the given
49
+ # action.
50
+ def link_if_authorized(name, options = {}, html_options = {}, *params, &block)
51
+ result = html_options.delete(:show_text) ? name : ""
52
+
53
+ # we need to strip leading slashes when checking authorisation, but not when
54
+ # actually generating the link.
55
+ auth_options = options.dup
56
+ if auth_options[:controller]
57
+ auth_options[:controller] = auth_options[:controller].gsub(/^\//, '')
58
+ end
59
+
60
+ (block.nil? || (yield block)) && authorized?(auth_options) {
61
+ #result = link_to_with_current_styling(name, options, html_options, *params)
62
+ result = link_to(name, options, html_options, *params)
63
+
64
+ # TODO: won't this pass other things like html_options[:id], which is EVIL since two
65
+ # things shouldn't share the same ID.
66
+ wrap_tag = html_options.delete(:wrap_in)
67
+ result = content_tag(wrap_tag, result, html_options) if wrap_tag != nil
68
+ }
69
+ result
70
+ end
71
+
72
+ # Returns true, and also executes an optional code block if the current user
73
+ # is authorised for the supplied controller and action. If no action is
74
+ # supplied, "index" is used by default. Returns false if the user is not
75
+ # authorised.
76
+ # e.g.
77
+ # <% authorized?("person", "destroy") { %>
78
+ # <p>You have the power to destroy users! Well done.</p>
79
+ # <% } %>
80
+ def authorized?(options, &block) # default the action to "index"
81
+ controller = options[:controller]
82
+ action = options[:action]
83
+
84
+ # use the current controller/action if none is given in options
85
+ controller ||= @controller.controller_name
86
+ action ||= @controller.action_name
87
+
88
+ if current_user.nil?
89
+ RAILS_DEFAULT_LOGGER.debug "checking guest authorisation for #{controller}/#{action}"
90
+ if User.guest_user_authorized?(controller, action)
91
+ yield block if block != nil
92
+ return true
93
+ end
94
+ else
95
+ RAILS_DEFAULT_LOGGER.debug "checking user:#{session[:user].id} authorisation for #{controller}/#{action}"
96
+ if current_user.authorized?(controller, action)
97
+ yield block if block != nil
98
+ return true
99
+ end
100
+ end
101
+ return false
102
+ end
103
+ end
104
+ end