ioquatix-account_engine 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 (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