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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in authentication.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Micah Geisel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,38 @@
1
+ Maintainers
2
+ -----------
3
+ Copyright (c) 2007-2008 CorData <cordata.org>
4
+ Copyright (c) 2007-2008 Eric Anderson <eric@pixelwareinc.com>
5
+
6
+ Contributors
7
+ ------------
8
+ Copyright (c) 2008 Bart Duchesne <bduc@dyndaco.com>
9
+ All of LDAP, Radius
10
+ Most of Bogus and environment-based configuration support
11
+
12
+ 3rd Party Code
13
+ --------------
14
+ Radius Authentication Module:
15
+ Copyright (C) 2002 Rafael R. Sevilla <dido@imperium.ph>
16
+ Licensed under LGPL
17
+
18
+ Everything not 3rd Party Code is licensed under the following
19
+ MIT-LICENSE:
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining
22
+ a copy of this software and associated documentation files (the
23
+ "Software"), to deal in the Software without restriction, including
24
+ without limitation the rights to use, copy, modify, merge, publish,
25
+ distribute, sublicense, and/or sell copies of the Software, and to
26
+ permit persons to whom the Software is furnished to do so, subject to
27
+ the following conditions:
28
+
29
+ The above copyright notice and this permission notice shall be
30
+ included in all copies or substantial portions of the Software.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ = authentication plugin
2
+
3
+ This plugin provide the infrastructure for implementing a pluggable
4
+ authentication system. This plugin only provides support for the
5
+ lower-level model functionality to carry out various authentication
6
+ actions. Higher level functions that the user interacts with
7
+ (login pages, forgot my password, etc.) should be implemented by the
8
+ application or a plugin like the login plugin which is designed for
9
+ this purpose.
10
+
11
+ See the #Authentication module for overview info
12
+
13
+ = Installation
14
+
15
+ == Standard Method
16
+
17
+ ruby ./script/plugin install http://authentication.rubyforge.org/svn/trunk
18
+ mv vendor/plugins/trunk vendor/plugins/authentication
19
+
20
+ == Piston Method
21
+
22
+ piston import http://authentication.rubyforge.org/svn/trunk vendor/plugins/authentication
23
+
24
+ = NOTICE
25
+
26
+ Since this plugin does not yet contain many modules that it hopes to
27
+ one day (POP3, etc.) the internal API is not set in stone. I wanted to
28
+ leave a place for plugging in other authentication systems but do not
29
+ yet actually have any need for any besides a salted hash and basic
30
+ tokens. This means as the others are added the internals will probably
31
+ change to account for the variety.
32
+
33
+ = NOTICE
34
+
35
+ Since nobody uses all aspects of this program different people are
36
+ maintaining different parts. If you have any questions about a specific
37
+ authentication module contact correct person:
38
+
39
+ Bart Duchesne <bduc@dyndaco.com> - LDAP and Radius auth modules
@@ -0,0 +1,29 @@
1
+ # Authentication
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'authentication'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install authentication
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ == Creating the test database
2
+
3
+ The test databases will be created from the info specified in
4
+ test/database.yml. Either change that file to match your database or
5
+ change your database to match that file.
6
+
7
+ == Running with Rake
8
+
9
+ The easiest way to run the unit tests is through Rake. By default
10
+ sqlite will be the database run. Just change your env variable DB to be
11
+ the database adaptor (specified in database.yml) that you want to use.
12
+ The database and permissions must already be setup but the tables will
13
+ be created for you from schema.rb.
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ PKG_NAME = 'authentication'
5
+ PKG_VERSION = 0.02
6
+
7
+ require 'rake/testtask'
8
+ require 'rake/rdoctask'
9
+ require 'rake/packagetask'
10
+
11
+ desc 'Default: run unit tests.'
12
+ task :default => :test
13
+
14
+ desc "Test the #{PKG_NAME} plugin."
15
+ Rake::TestTask.new(:test) do |t|
16
+ t.libs << 'lib'
17
+ t.pattern = 'test/**/*_test.rb'
18
+ t.verbose = true
19
+ end
20
+
21
+ desc "Generate documentation for the #{PKG_NAME} plugin"
22
+ Rake::RDocTask.new(:rdoc) do |rdoc|
23
+ rdoc.rdoc_dir = 'html'
24
+ rdoc.title = PKG_NAME
25
+ rdoc.options << '--line-numbers' << '--inline-source'
26
+ rdoc.rdoc_files.include('README')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
29
+
30
+ Rake::PackageTask.new(PKG_NAME, PKG_VERSION) do |pkg|
31
+ pkg.need_tar_gz = true
32
+ pkg.package_files.include('{lib,test}/**/*')
33
+ pkg.package_files.include('README')
34
+ pkg.package_files.include('MIT-LICENSE')
35
+ pkg.package_files.include('Rakefile')
36
+ end
37
+
38
+ desc 'Tag release'
39
+ task :tag do
40
+ svn_root = "svn+ssh://rubyforge.org/var/svn/#{PKG_NAME}"
41
+ sh %(svn cp #{svn_root}/trunk #{svn_root}/tags/rel-#{PKG_VERSION} -m "Tag #{PKG_NAME} release #{PKG_VERSION}")
42
+ end
43
+
44
+ desc 'Push a release to rubyforge'
45
+ task :release => [:package, :tag, :rdoc] do
46
+
47
+ sh %{scp -rq html/* rubyforge.org:/var/www/gforge-projects/#{PKG_NAME}}
48
+
49
+ require 'rubyforge'
50
+
51
+ rubyforge = RubyForge.new
52
+ rubyforge.login
53
+
54
+ package = [PKG_NAME, PKG_VERSION] * '-'
55
+ rubyforge.add_release(PKG_NAME, PKG_NAME, PKG_VERSION, "pkg/#{package}.tar.gz")
56
+ rubyforge.post_news(PKG_NAME, "#{PKG_NAME} #{PKG_VERSION} Released", <<BODY)
57
+ A new version of #{PKG_NAME} has been released. Please see
58
+ http://#{PKG_NAME}.rubyforge.org for full information. See the SCM
59
+ log messages for what has changed.
60
+ BODY
61
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/authentication/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Micah Geisel"]
6
+ gem.email = ["micah@botandrose.com"]
7
+ gem.description = %q{TODO: Write a gem description}
8
+ gem.summary = %q{TODO: Write a gem summary}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "authentication"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Authentication::VERSION
17
+ end
@@ -0,0 +1,270 @@
1
+ require "authentication/version"
2
+ require 'authentication/salted_hash'
3
+ require 'authentication/remember_me'
4
+ require 'authentication/single_token'
5
+
6
+ # This module provides the infrastructure for implementing a pluggable
7
+ # authentication system.
8
+ #
9
+ # This plugin was created in similar spirit to the Authen::Simple CPAN
10
+ # module in Perl. The internal design is different but the goal is the
11
+ # same. A chain of authentication systems can be registered. When a user
12
+ # attempts to authenticate it will cycle through this chain until it can
13
+ # authenticate successfully.
14
+ #
15
+ # This allows you to have multiple authentication attempts (perhaps a
16
+ # ActiveDirectory auth, followed by a POP3 auth, followed by an auth on
17
+ # the local database). This also allows the authentication mechanism to
18
+ # be switched out with mimimal affects on the code.
19
+ #
20
+ # The goal is eventually to include with this plugin a variety of
21
+ # authentication methods with sane defaults. Depending on the
22
+ # environment the authentication method can be easily changed and
23
+ # chained. Right now we only support authenticating with the local
24
+ # database.
25
+ #
26
+ # See Authentication::Macros for usage info
27
+ module Authentication
28
+
29
+ mattr_accessor :default_scheme
30
+ self.default_scheme = {
31
+ :authenticate_with => 'Authentication::SaltedHash',
32
+ :token_with => [
33
+ 'Authentication::RememberMe',
34
+ 'Authentication::SingleToken'
35
+ ]
36
+ }
37
+
38
+ module Macros
39
+
40
+ # Should be called on whatever ActiveRecord::Base subclass is
41
+ # being authenticated (i.e. User, Profile, etc.). The common
42
+ # case should look something like:
43
+ #
44
+ # class User < ActiveRecord::Base
45
+ # acts_as_authenticated_user
46
+ # end
47
+ #
48
+ # Most of the time you will simply call this method with no
49
+ # arguments. In this case sane defaults will cause the
50
+ # application to authenticate with the local database. These
51
+ # sane defaults will attempt to provide you with the following:
52
+ #
53
+ # * A salted hash password authentication
54
+ # * A single token authentication ideal for URL tokens
55
+ # * A remember me authentication ideal for cookie remember me
56
+ # functionality
57
+ #
58
+ # Those methods will only be provided if the model being
59
+ # authenticated provides the proper fields. See the documentation
60
+ # on those various authentication modules for what is required
61
+ # to make a module work.
62
+ #
63
+ # If you are interested in using other modules then you need to know
64
+ # the following:
65
+ #
66
+ # There are two types of authentication modules.
67
+ # The password auth type has the traditional user/password
68
+ # requirement to authenticate. A user can also typically change
69
+ # their password (although this is not required). An example
70
+ # of this module is the Authentication::SaltedHash module.
71
+ #
72
+ # The other type of module is a token module. A token module
73
+ # typically consist of a user and some sort of token that is
74
+ # not usually user entered. For example a single-signon system
75
+ # may use a token to avoid having to prompt the user. Examples
76
+ # of token modules are the Authentication::SingleToken module
77
+ # and the Authentication::RememberMe module. A token module may
78
+ # authenticate many different tokens for the same user. This allows
79
+ # a token module to assign different valid tokens to different
80
+ # systems so that a token can be revoked if desired. Token
81
+ # authentications often also have a time expiration that a token
82
+ # is valid for. After that time has expired the token no longer
83
+ # works.
84
+ #
85
+ # If you desire to change the modules used this macro method
86
+ # accepts two options in the option hash. The option
87
+ # :authenticate_with is how you specify one or more password auth
88
+ # modules. The option :token_with is how you specify one or more
89
+ # token modules to authenticate with.
90
+ #
91
+ # Both options can accept values in following formats:
92
+ #
93
+ # single module::
94
+ # In this case a single module name is provided to authenticate
95
+ # against. For example:
96
+ # acts_as_authenticated_user :authenticate_with => 'Authentication::POP3'
97
+ # chain of modules::
98
+ # In this case a list of modules will be used to authenticate
99
+ # against. If any of them are a success then the user
100
+ # authenticates. Otherwise the user will not successfully login.
101
+ # For example:
102
+ # acts_as_authenticated_user :authenticate_with =>
103
+ # ['Authentication::ActiveDirectory', 'Authentication::POP3']
104
+ # module with arguments::
105
+ # In this case a single module is being used but it has arguments
106
+ # which are passed to the module when instantated. For example:
107
+ # acts_as_authenticated_user :authenticate_with =>
108
+ # {'Authentication::POP3' => ['pop3.example.org', 110]}
109
+ # In this case the code will call
110
+ # Authentication::POP3.new('pop3.example.org', 110) when
111
+ # instantionating the object. More than likely the authentication
112
+ # module will just have one argument which is an option hash. In
113
+ # this case you might initialize that module like the following:
114
+ # acts_as_authenticated_user :authenticate_with =>
115
+ # {'Authentication::POP3' =>
116
+ # {:server => 'pop3.example.org', :port => 110}}
117
+ # chain of modules with arguments::
118
+ # You can also chain modules and use arguments. In this case you
119
+ # just pass the method an array of hashes. For example:
120
+ # acts_as_authenticated_user :authenticate_with =>
121
+ # [
122
+ # {'Authentication::POP3' =>
123
+ # {:server => 'pop3.example.com', :port => 5000}},
124
+ # {'Autnentication::ActiveDirectory' =>
125
+ # {:server => 'ad.example.com'}}
126
+ # ]
127
+ #
128
+ # If you wish to provide a different scheme depending on the
129
+ # environment (i.e. production vs. development) then you can
130
+ # assign your argument to the Module method "default_scheme"
131
+ # on the Authentication module in the proper environment file.
132
+ # For example:
133
+ #
134
+ # Authentication.default_scheme = {
135
+ # :authenticate_with => 'Authentication::POP3',
136
+ # :token_with => []
137
+ # }
138
+ #
139
+ # This would authenticate with POP3 and not provide any token
140
+ # mechanism.
141
+ def acts_as_authenticated_user(options={})
142
+ options.reverse_merge! Authentication.default_scheme
143
+
144
+ # Process arguments and store in instantiated auth modules
145
+ {
146
+ :authenticate_with => :authentication_modules,
147
+ :token_with => :token_modules,
148
+ }.each do |option, mod_type|
149
+ mods = [options[option]].flatten.compact
150
+ mods = mods.inject([]) do |memo, mod|
151
+ if mod.is_a? Hash
152
+ mod.each do |m, args|
153
+ args = [args] unless args.is_a? Array
154
+ memo << m.constantize.new(*args)
155
+ end
156
+ else
157
+ memo << mod.constantize.new
158
+ end
159
+ memo
160
+ end
161
+ class_attribute mod_type
162
+ private
163
+ self.send "#{mod_type.to_s}=".to_sym, mods
164
+ end
165
+
166
+ include Authentication::InstanceMethods
167
+ if method_defined?(:password=) # TODO rather have these in the client class?
168
+ before_validation :assign_password
169
+ # after_save :reset_password
170
+ end
171
+ end
172
+ end
173
+
174
+ # Methods that are mixed into the authenticated object as instance
175
+ # methods.
176
+ module InstanceMethods
177
+ # If the given password will authenticate the object using
178
+ # the chain of authentication modules configured then true is
179
+ # returned. Otherwise false is returned. Both token modules
180
+ # and password auth modules are checked.
181
+ def authenticate(password)
182
+ mods = [
183
+ self.class.token_modules,
184
+ self.class.authentication_modules
185
+ ].flatten.compact
186
+ mods.each {|mod| return true if mod.authenticate self, password}
187
+ false
188
+ end
189
+
190
+ # Will create a new token that can be used to login without a
191
+ # password (or basically you can consider this just a really
192
+ # complex password). If this token is passed into the authenticate
193
+ # method then true should be returned. This method takes the
194
+ # following three arguments:
195
+ #
196
+ # name:: Depending on the token modules used will determine if this
197
+ # argument has any meaning. Sometimes a token module will only
198
+ # respond to one name. Other times it will respond to any name.
199
+ # The reason for this parameter is to allow a token module to
200
+ # have multiple tokens it accepts so that it can then later revoke
201
+ # only some tokens if needed. For example a site trying to provide
202
+ # single-signon service may give out a token for each foreign system
203
+ # that interacts with it. Then later when that token is used the
204
+ # token module can note what system it authenticated for and if at
205
+ # some point it stops trusting the foreign system it can revoke
206
+ # that token without revoking the other tokens it has assigned.
207
+ #
208
+ # An expiration date can also be given although not all token
209
+ # modules will do anythign with this expiration date.
210
+ #
211
+ # NOTE: If the token generated is attached to the model (default
212
+ # behavior) then the token may not actually valid until the model
213
+ # has been saved. To be sure always call save after getting a new
214
+ # token if you want to be sure to keep that token.
215
+ def assign_token(name, expire=3.days.from_now)
216
+ self.class.token_modules.each do |mod|
217
+ token = mod.assign_token self, name, expire if mod.respond_to? :assign_token
218
+ return token if token
219
+ end
220
+ nil
221
+ end
222
+
223
+ def assign_token!(*args)
224
+ assign_token(*args).tap do |token|
225
+ save!
226
+ end
227
+ end
228
+
229
+ # Will assign a new password that will by crypted on when the
230
+ # model is saved. If multiple password auth modules are configured
231
+ # then each one will be given a copy of this new password. This
232
+ # could be a useful method of syncing your passwords across
233
+ # different systems. Not all password auth modules support the
234
+ # ability to change passwords.
235
+ attr_writer :password
236
+
237
+ # For confirmation validation
238
+ # previously this was private, which seems to cause validates_presence_of :password
239
+ # to fail, therefor made it public
240
+ attr_reader :password
241
+
242
+ private
243
+
244
+ # before_validation callback let authentication modules set password.
245
+ # If a module does not allow setting a password it should just not implement
246
+ # the assign_password function.
247
+ #
248
+ # NOTE: If password is blank nothing is done. This is to prevent
249
+ # the common case of empty passwords on a form from blanking out a
250
+ # password. The side effect is that you cannot specifically have a
251
+ # blank password.
252
+ def assign_password
253
+ return true if password.blank?
254
+ self.class.authentication_modules.each do |mod|
255
+ mod.assign_password self, password if mod.respond_to? :assign_password
256
+ end
257
+ true
258
+ end
259
+
260
+ # Callback after save to ensure cleartext password is deleted
261
+ def reset_password
262
+ self.password = nil
263
+ self.password_confirmation = nil if respond_to? :password_confirmation
264
+ end
265
+ end
266
+ end
267
+
268
+ require 'authentication/active_record_extensions'
269
+ ActiveRecord::Base.extend Authentication::Macros
270
+