adva_user 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README +114 -0
  6. data/README.md +29 -0
  7. data/Rakefile +2 -0
  8. data/adva_user.gemspec +17 -0
  9. data/app/controllers/admin/base_account_controller.rb +13 -0
  10. data/app/controllers/admin/users_controller.rb +95 -0
  11. data/app/controllers/password_controller.rb +36 -0
  12. data/app/controllers/session_controller.rb +30 -0
  13. data/app/helpers/users_helper.rb +27 -0
  14. data/app/models/account.rb +7 -0
  15. data/app/models/membership.rb +16 -0
  16. data/app/models/password_mailer.rb +43 -0
  17. data/app/models/user.rb +106 -0
  18. data/app/views/admin/users/_form.html.erb +29 -0
  19. data/app/views/admin/users/_sidebar.html.erb +8 -0
  20. data/app/views/admin/users/edit.html.erb +7 -0
  21. data/app/views/admin/users/index.html.erb +13 -0
  22. data/app/views/admin/users/new.html.erb +5 -0
  23. data/app/views/admin/users/show.html.erb +27 -0
  24. data/app/views/layouts/login.html.erb +24 -0
  25. data/app/views/password/edit.html.erb +14 -0
  26. data/app/views/password/new.html.erb +13 -0
  27. data/app/views/password_mailer/reset_password_email.html.erb +3 -0
  28. data/app/views/password_mailer/updated_password_email.html.erb +1 -0
  29. data/app/views/session/new.html.erb +17 -0
  30. data/config/initializers/menus.rb +25 -0
  31. data/config/routes.rb +14 -0
  32. data/db/migrate/20080402000001_create_users_table.rb +33 -0
  33. data/db/migrate/20080402000005_create_memberships_table.rb +13 -0
  34. data/db/migrate/20090625124502_create_accounts.rb +13 -0
  35. data/db/migrate/20090625133231_add_account_to_user.rb +10 -0
  36. data/lib/action_controller/authenticate_anonymous.rb +70 -0
  37. data/lib/action_controller/authenticate_user.rb +201 -0
  38. data/lib/active_record/belongs_to_author.rb +37 -0
  39. data/lib/adva_user.rb +28 -0
  40. data/lib/adva_user/version.rb +3 -0
  41. data/lib/login/helper_integration.rb +11 -0
  42. data/lib/login/mail_config.rb +39 -0
  43. data/test/contexts.rb +42 -0
  44. data/test/fixtures.rb +18 -0
  45. data/test/functional/admin/users_controller_test.rb +176 -0
  46. data/test/functional/password_controller_test.rb +96 -0
  47. data/test/functional/session_controller_test.rb +1 -0
  48. data/test/functional/user_controller_test.rb +95 -0
  49. data/test/integration/anonymous_login_test.rb +39 -0
  50. data/test/integration/edit_user_test.rb +44 -0
  51. data/test/integration/memberships_test.rb +52 -0
  52. data/test/integration/user_deletion_test.rb +27 -0
  53. data/test/integration/user_login_test.rb +53 -0
  54. data/test/integration/user_login_with_remember_me_test.rb +20 -0
  55. data/test/integration/user_registration_test.rb +64 -0
  56. data/test/test_helper.rb +1 -0
  57. data/test/unit/cells/user_cell_test.rb +13 -0
  58. data/test/unit/helpers/users_helper_test.rb +52 -0
  59. data/test/unit/models/account_test.rb +21 -0
  60. data/test/unit/models/anonymous_test.rb +54 -0
  61. data/test/unit/models/password_mailer_test.rb +26 -0
  62. data/test/unit/models/user_mailer_test.rb +16 -0
  63. data/test/unit/models/user_test.rb +173 -0
  64. data/vendor/gems/authentication/.gitignore +17 -0
  65. data/vendor/gems/authentication/Gemfile +4 -0
  66. data/vendor/gems/authentication/LICENSE +22 -0
  67. data/vendor/gems/authentication/MIT-LICENSE +38 -0
  68. data/vendor/gems/authentication/README +39 -0
  69. data/vendor/gems/authentication/README.md +29 -0
  70. data/vendor/gems/authentication/RUNNING_UNIT_TESTS +13 -0
  71. data/vendor/gems/authentication/Rakefile +61 -0
  72. data/vendor/gems/authentication/authentication.gemspec +17 -0
  73. data/vendor/gems/authentication/lib/authentication.rb +270 -0
  74. data/vendor/gems/authentication/lib/authentication/active_record_extensions.rb +11 -0
  75. data/vendor/gems/authentication/lib/authentication/bogus.rb +13 -0
  76. data/vendor/gems/authentication/lib/authentication/hash_helper.rb +26 -0
  77. data/vendor/gems/authentication/lib/authentication/ldap.rb +49 -0
  78. data/vendor/gems/authentication/lib/authentication/remember_me.rb +52 -0
  79. data/vendor/gems/authentication/lib/authentication/salted_hash.rb +53 -0
  80. data/vendor/gems/authentication/lib/authentication/single_token.rb +53 -0
  81. data/vendor/gems/authentication/lib/authentication/version.rb +3 -0
  82. data/vendor/gems/authentication/lib/radius/dictionary +207 -0
  83. data/vendor/gems/authentication/test_backup/abstract_unit.rb +30 -0
  84. data/vendor/gems/authentication/test_backup/active_record_extension_test.rb +17 -0
  85. data/vendor/gems/authentication/test_backup/authentication_test.rb +231 -0
  86. data/vendor/gems/authentication/test_backup/database.yml +12 -0
  87. data/vendor/gems/authentication/test_backup/fixtures/user.rb +3 -0
  88. data/vendor/gems/authentication/test_backup/fixtures/users.yml +3 -0
  89. data/vendor/gems/authentication/test_backup/options_test.rb +100 -0
  90. data/vendor/gems/authentication/test_backup/remember_me_test.rb +41 -0
  91. data/vendor/gems/authentication/test_backup/salted_hash_test.rb +38 -0
  92. data/vendor/gems/authentication/test_backup/schema.rb +10 -0
  93. data/vendor/gems/authentication/test_backup/single_token_test.rb +44 -0
  94. data/vendor/gems/authentication/test_backup/test_helper.rb +8 -0
  95. metadata +157 -0
@@ -0,0 +1,70 @@
1
+ # Auto-registers and re-authenticates anonymous users based on a single token
2
+ # that's stored in the session. This is for anonymous posting of blog comments,
3
+ # editing wikipages etc. and allows to do such things as:
4
+ #
5
+ # * store user information in the user table (which keeps the model and db
6
+ # structure clean) and
7
+ # * allow users to (e.g.) edit their comment based on this anonymous login.
8
+
9
+ module ActionController
10
+ module AuthenticateAnonymous
11
+ def self.included(base)
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ module ClassMethods
16
+ def authenticates_anonymous_user
17
+ return if authenticates_anonymous_user?
18
+ include InstanceMethods
19
+ alias_method_chain :current_user, :anonymous
20
+ alias_method_chain :authenticated?, :anonymous
21
+ end
22
+
23
+ def authenticates_anonymous_user?
24
+ included_modules.include? InstanceMethods
25
+ end
26
+ end
27
+
28
+ module InstanceMethods
29
+ def current_user_with_anonymous
30
+ @current_user ||= (current_user_without_anonymous || login_or_register_anonymous)
31
+ end
32
+
33
+ def authenticated_with_anonymous?
34
+ !!current_user and !current_user.anonymous?
35
+ end
36
+
37
+ def login_or_register_anonymous
38
+ anonymous = try_login_anonymous || User.anonymous
39
+ anonymous = register_or_update_anonymous anonymous if params[:user]
40
+ login_anonymous! anonymous if anonymous
41
+ anonymous
42
+ end
43
+
44
+ def try_login_anonymous
45
+ # try to authenticate if token is present
46
+ validate_token User, session[:anonymous_token] if session[:anonymous_token]
47
+ end
48
+
49
+ def register_or_update_anonymous(anonymous)
50
+ # if :name and :email params are passed either register a new Anonymous or update the existing one
51
+ anonymous.update_attributes params[:user].merge(request_info)
52
+ anonymous
53
+ end
54
+
55
+ def login_anonymous!(anonymous)
56
+ # set a new session token and expiration
57
+ token = anonymous.assign_token('anonymous', 3.hour.from_now)
58
+ anonymous.save
59
+ session[:anonymous_token] = "#{anonymous.id};#{token}"
60
+ cookies[:aid] = anonymous.id.to_s unless anonymous.new_record?
61
+ end
62
+
63
+ def request_info
64
+ { :ip => request.env["REMOTE_ADDR"],
65
+ :agent => request.env["HTTP_USER_AGENT"],
66
+ :referer => request.env["HTTP_REFERER"] }
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,201 @@
1
+ module ActionController
2
+
3
+ # Module automatically mixed into the all controllers making the
4
+ # application of authentication easy. See
5
+ # Login::ControllerIntegration::ClassMethods for how to apply
6
+ # authentication.
7
+ module AuthenticateUser
8
+ def self.included(target)
9
+ target.extend(ClassMethods)
10
+ target.send(:include, InstanceMethods)
11
+ target.helper_method(:logged_in?, :authenticated?)
12
+ end
13
+
14
+ # Methods available as macro-style methods on any controller
15
+ module ClassMethods
16
+
17
+ # Sets up the controller so that authentication is required. If
18
+ # the user is not authenticated then they will be redirected to
19
+ # the login screen.
20
+ #
21
+ # The page requested will be saved so that once the login has
22
+ # occured they will be sent back to the page they first
23
+ # requested. If no page was requested (they went to the login
24
+ # page directly) then they will be directed to profiles/home
25
+ # after login which is a placeholder for the app to override.
26
+ #
27
+ # Options given are passed directly to the before_filter method
28
+ # so feel free to provide :only and :except options.
29
+ def authentication_required
30
+ before_filter :require_authentication
31
+ end
32
+
33
+ # Will remove authentication from certain actions. Options given
34
+ # are passed directly to skip_before_filter so feel free to use
35
+ # :only and :except options.
36
+ #
37
+ # This method is useful in cases where you have locked down the
38
+ # entire application by putting authentication_required in your
39
+ # ApplicationController but then want to open an action back up
40
+ # in a specific controller.
41
+ def no_authentication_required
42
+ skip_before_filter :require_authentication
43
+ end
44
+ end
45
+
46
+ # Methods callable from within actions
47
+ module InstanceMethods
48
+ def authenticate_user(credentials)
49
+ User.authenticate(credentials).tap do |user|
50
+ if user
51
+ # prevent session hijacking - unnecessary according to http://dev.rubyonrails.org/ticket/10108
52
+ # reset_session_except :return_location
53
+ session[:uid] = user.id
54
+ set_user_cookie!(user)
55
+ end
56
+ end
57
+ end
58
+
59
+ # Will retrieve the current_user. Will not force a login but
60
+ # simply load the current user if a person is logged in. If
61
+ # you need the user object loaded with extra options (such as
62
+ # eager loading) then create a private method called
63
+ # "user_find_options" on your controller that returns a hash
64
+ # of the find options you want.
65
+ #
66
+ # This method will also inform the models of the current user
67
+ # if the current user is logged in and the "User" class responds
68
+ # to the class method current_user=. This is a nice way to
69
+ # communciate the current user down to the model level for
70
+ # model-level security. This means you will want to call this
71
+ # method at least once before using the model-level security.
72
+ # Usually you will call it in a before filter. This method is
73
+ # called automatically when authentication_required is applied to
74
+ # an action.
75
+ def current_user
76
+ @current_user ||= begin
77
+ # Check for session[:uid] here? That would mean that for token auth the
78
+ # user always needs to be logged out (e.g. in UserController#create).
79
+ # Looks a bit more robust this way:
80
+ try_login
81
+ if session && session[:uid]
82
+ user = find_current_user
83
+ set_user_cookie!(user)
84
+ user
85
+ end
86
+ end
87
+ end
88
+
89
+ def authenticated?
90
+ !!current_user
91
+ end
92
+ alias :logged_in? :authenticated?
93
+
94
+ # killed this because it's just the wrong way to do it
95
+ #
96
+ # # Will store the current params so that we can return here on
97
+ # # successful login. If you want to redirect to the login yourself
98
+ # # (perhaps you are applying your own security instead of just
99
+ # # determining if the user is logged in) then you will want to
100
+ # # call this before issuing your redirect to the login screen.
101
+ # def store_return_location
102
+ # session[:return_location] = params
103
+ # end
104
+
105
+ private
106
+
107
+ # Will actually test to see if the user is authorized
108
+ def require_authentication
109
+ # No matter what the app does a user can always login, forgot
110
+ # password and register. The controllers provided by this
111
+ # plugin alreaddy have these controllers/actions on an
112
+ # exception list but this prevents a mistake an overridden
113
+ # controller from preventing the normal login behavior.
114
+ %w(session password user).each do |c|
115
+ %w(new create).each do |a|
116
+ return if (controller_name == c) && (action_name == a)
117
+ end
118
+ end
119
+
120
+ # If we cannot get the current user store the requested page
121
+ # and send them to the login page.
122
+ if current_user.nil? or current_user.anonymous?
123
+ redirect_to login_url(:return_to => request.url) and false
124
+ end
125
+ end
126
+
127
+ def logout
128
+ reset_session
129
+ forget_me!
130
+ end
131
+
132
+ def forget_me!
133
+ cookies[:remember_me] = nil
134
+ cookies[:uid] = nil
135
+ cookies[:uname] = nil
136
+ end
137
+
138
+ def remember_me!
139
+ token = current_user.assign_token!('remember me')
140
+ cookies[:remember_me] = { :value => "#{current_user.id};#{token}", :expires => 10.years.from_now }
141
+ end
142
+
143
+ def set_user_cookie!(user = current_user)
144
+ if user
145
+ cookies[:uid] = user.id.to_s
146
+ cookies[:uname] = user.name
147
+ end
148
+ end
149
+
150
+ # There are a few ways that a user can login without going through
151
+ # a login screen. These methods all rely on authenticating with
152
+ # the information given in the request. If any of these methods
153
+ # are successful then session[:uid] will be set with the current
154
+ # user id and current_user will return the current user
155
+ def try_login
156
+ if user = http_auth_login || validation_login || remember_me_login
157
+ session[:uid] = user.id
158
+ end
159
+ end
160
+
161
+ # Will attempt to authenticate with HTTP Auth. HTTP Auth will not
162
+ # be required. We are just checking if it is provided mainly for
163
+ # RESTful requests.
164
+ def http_auth_login
165
+ # FIXME: Implement
166
+ end
167
+
168
+ # Will use the URL param :token to see if we can do a token
169
+ # authentication.
170
+ def validation_login
171
+ validate_token User, params[:token]
172
+ end
173
+
174
+ # Will check for a :remember_me cookie for a token that will
175
+ # authenticate the user.
176
+ def remember_me_login
177
+ validate_token User, cookies[:remember_me]
178
+ end
179
+
180
+ # The tokens are stored in various places as id;token. This method
181
+ # will split that out and validate it. If everything is successful
182
+ # then the user object is returned. Otherwise nil is returned.
183
+ # The full token should be passed in.
184
+ def validate_token(klass, token, options = {})
185
+ return nil if token.blank?
186
+ return nil unless token =~ /\;/
187
+
188
+ uid, token = token.split ';'
189
+ if object = klass.find_by_id(uid)
190
+ return object if object.authenticate(token)
191
+ end
192
+ nil
193
+ end
194
+
195
+ def find_current_user
196
+ User.find_by_id(session[:uid])
197
+ end
198
+
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,37 @@
1
+ module ActiveRecord
2
+ module BelongsToAuthor
3
+ def self.included(base)
4
+ base.extend ActMacro
5
+ end
6
+
7
+ module ActMacro
8
+ def belongs_to_user(*args)
9
+ options = args.extract_options!
10
+ args = (args.empty? ? [:user] : args)
11
+ belongs_to_cacheable *args.dup << options # FIXME should not be polymorphic!
12
+
13
+ args.each do |name|
14
+ class_eval <<-code, __FILE__, __LINE__
15
+ def #{name}_ip
16
+ #{name}.ip if #{name} && #{name}.respond_to?(:ip)
17
+ end
18
+
19
+ def #{name}_agent
20
+ #{name}.agent if #{name} && #{name}.respond_to?(:agent)
21
+ end
22
+
23
+ def #{name}_referer
24
+ #{name}.referer if #{name} && #{name}.respond_to?(:referer)
25
+ end
26
+ code
27
+ end
28
+ end
29
+
30
+ def belongs_to_author(*args)
31
+ options = args.extract_options!
32
+ args = (args.empty? ? [:author] : args) << options
33
+ belongs_to_user *args
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
1
+ # require "adva_user/version"
2
+
3
+ # load vendored gems
4
+ Dir["#{File.expand_path("#{File.dirname(__FILE__)}/../vendor/gems")}/**/lib"].each do |vendored_gem_path|
5
+ $: << vendored_gem_path
6
+ end
7
+ require "authentication"
8
+
9
+ require "rails"
10
+
11
+ require "action_controller/authenticate_user"
12
+ require "action_controller/authenticate_anonymous"
13
+ require "active_record/belongs_to_author"
14
+ require "login/helper_integration"
15
+
16
+ module AdvaUser
17
+ class Engine < Rails::Engine
18
+ initializer "adva_user.init" do
19
+ ActionController::Base.send :include, ActionController::AuthenticateUser
20
+ ActionController::Base.send :include, ActionController::AuthenticateAnonymous
21
+ ActiveRecord::Base.send :include, ActiveRecord::BelongsToAuthor
22
+ ActionView::Base.send :include, Login::HelperIntegration
23
+
24
+ Event.observers << 'UserMailer'
25
+ Event.observers << 'PasswordMailer'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module AdvaUser
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,11 @@
1
+ module Login
2
+ # Automatically mixed into all views for utility functions.
3
+ module HelperIntegration
4
+
5
+ # Returns the current user at the view level. Everything said
6
+ # about the current_user method in the
7
+ # Login::ControllerIntegration::InstanceMethods module
8
+ # applies to this method as well.
9
+ def current_user; controller.current_user end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ module Login
2
+
3
+ # The purpose of this module is to provide an application some control
4
+ # over how the messages are sent without having to overwrite blocks
5
+ # of code. We do this through simple constants. The two constants
6
+ # currently are:
7
+ #
8
+ # SUBJECT_PREFIX::
9
+ # Text that is before every message subject. By default this is not
10
+ # used. You may want to put something like the website here.
11
+ # NOTIFICATIONS_FROM::
12
+ # Who the message appears to be coming from. By default this is
13
+ # postmaster@yourdomain.com
14
+ #
15
+ # If you want to access these same values in your own mailers just
16
+ # mix them into your mailers and the methods will be available.
17
+ module MailConfig
18
+ protected
19
+
20
+ # Will return subject prefix
21
+ def subject_prefix
22
+ return "[#{SUBJECT_PREFIX}] " if Object.const_defined?('SUBJECT_PREFIX')
23
+ ''
24
+ end
25
+
26
+ # Email message appear to come from. The constant takes priority
27
+ # but if no constant is defined then the email is extracted from
28
+ # the given param which can be any link that you want the email
29
+ # to appear to come from.
30
+ def system_email(extract_from)
31
+ return NOTIFICATIONS_FROM if Object.const_defined?('NOTIFICATIONS_FROM')
32
+ if host = URI.parse(extract_from).host
33
+ host = host.split '.'
34
+ host.shift if host.first =~ /www/i
35
+ "postmaster@#{host * '.'}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ class Test::Unit::TestCase
2
+ def login(user)
3
+ @user = user
4
+ stub(@controller).current_user.returns(user)
5
+ end
6
+
7
+ share :no_user do
8
+ before do
9
+ User.delete_all
10
+ end
11
+ end
12
+
13
+ share :a_user do
14
+ before do
15
+ @user = User.first
16
+ end
17
+ end
18
+
19
+ def valid_user_params
20
+ { :first_name => 'first name',
21
+ :last_name => 'last name',
22
+ :email => 'email@email.org',
23
+ :password => 'password',
24
+ :homepage => 'http://homepage.org' }
25
+ end
26
+
27
+ share :valid_user_params do
28
+ before { @params = { :user => valid_user_params } }
29
+ end
30
+
31
+ share :invalid_user_params do
32
+ before { @params = { :user => valid_user_params.update(:first_name => '') } }
33
+ end
34
+
35
+ share :invalid_user_params do
36
+ before { @params = { :user => valid_user_params.update(:email => '') } }
37
+ end
38
+
39
+ share :invalid_user_params do
40
+ before { @params = { :user => valid_user_params.update(:password => '') } }
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ user1 = User.create! :first_name => 'user1',
2
+ :email => 'user1@example.com',
3
+ :password => 'a password',
4
+ :verified_at => Time.now
5
+ user2 = User.create! :first_name => 'user2',
6
+ :email => 'user2@example.com',
7
+ :password => 'a password',
8
+ :verified_at => Time.now
9
+ user3 = User.create! :first_name => 'user3',
10
+ :email => 'user3@example.com',
11
+ :password => 'a password',
12
+ :verified_at => Time.now
13
+ user4 = User.create! :first_name => 'user4',
14
+ :email => 'user4@example.com',
15
+ :password => 'a password',
16
+ :verified_at => Time.now
17
+
18
+ account = Account.create! :name => 'an account', :users => [ user1, user2, user3 ]