authlogic 0.10.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of authlogic might be problematic. Click here for more details.
- data/CHANGELOG.rdoc +11 -0
- data/Manifest +18 -81
- data/README.rdoc +53 -17
- data/Rakefile +1 -1
- data/authlogic.gemspec +7 -6
- data/lib/authlogic.rb +5 -0
- data/lib/authlogic/active_record/acts_as_authentic.rb +90 -58
- data/lib/authlogic/active_record/authenticates_many.rb +37 -0
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +5 -7
- data/lib/authlogic/controller_adapters/merb_adapter.rb +55 -0
- data/lib/authlogic/controller_adapters/rails_adapter.rb +21 -15
- data/lib/authlogic/session/base.rb +64 -116
- data/lib/authlogic/session/callbacks.rb +29 -13
- data/lib/authlogic/session/config.rb +5 -1
- data/lib/authlogic/session/scopes.rb +101 -0
- data/lib/authlogic/version.rb +3 -3
- data/test/active_record_acts_as_authentic_test.rb +213 -0
- data/test/active_record_authenticates_many_test.rb +28 -0
- data/{test_app/test → test}/fixtures/companies.yml +0 -2
- data/test/fixtures/employees.yml +17 -0
- data/{test_app/test → test}/fixtures/projects.yml +1 -2
- data/{test_app/test → test}/fixtures/users.yml +3 -5
- data/test/test_helper.rb +142 -0
- data/test/user_session_active_record_trickery_test.rb +12 -0
- data/test/user_session_base_test.rb +316 -0
- data/test/user_session_config_test.rb +144 -0
- data/test/user_session_scopes_test.rb +19 -0
- data/test_libs/aes128_crypto_provider.rb +17 -0
- data/test_libs/mock_controller.rb +19 -0
- data/test_libs/mock_cookie_jar.rb +6 -0
- data/test_libs/mock_request.rb +5 -0
- data/test_libs/ordered_hash.rb +9 -0
- metadata +32 -87
- data/test_app/README +0 -256
- data/test_app/Rakefile +0 -10
- data/test_app/app/controllers/application.rb +0 -72
- data/test_app/app/controllers/companies_controller.rb +0 -2
- data/test_app/app/controllers/user_sessions_controller.rb +0 -25
- data/test_app/app/controllers/users_controller.rb +0 -61
- data/test_app/app/helpers/application_helper.rb +0 -3
- data/test_app/app/helpers/companies_helper.rb +0 -2
- data/test_app/app/helpers/user_sessions_helper.rb +0 -2
- data/test_app/app/helpers/users_helper.rb +0 -2
- data/test_app/app/models/company.rb +0 -4
- data/test_app/app/models/project.rb +0 -3
- data/test_app/app/models/user.rb +0 -5
- data/test_app/app/models/user_session.rb +0 -3
- data/test_app/app/views/layouts/application.html.erb +0 -27
- data/test_app/app/views/user_sessions/new.html.erb +0 -15
- data/test_app/app/views/users/_form.erb +0 -15
- data/test_app/app/views/users/edit.html.erb +0 -8
- data/test_app/app/views/users/new.html.erb +0 -8
- data/test_app/app/views/users/show.html.erb +0 -29
- data/test_app/config/boot.rb +0 -109
- data/test_app/config/database.yml +0 -19
- data/test_app/config/environment.rb +0 -69
- data/test_app/config/environments/development.rb +0 -17
- data/test_app/config/environments/production.rb +0 -22
- data/test_app/config/environments/test.rb +0 -22
- data/test_app/config/initializers/inflections.rb +0 -10
- data/test_app/config/initializers/mime_types.rb +0 -5
- data/test_app/config/initializers/new_rails_defaults.rb +0 -17
- data/test_app/config/routes.rb +0 -11
- data/test_app/db/development.sqlite3 +0 -0
- data/test_app/db/migrate/20081023040052_create_users.rb +0 -20
- data/test_app/db/migrate/20081103003828_create_companies.rb +0 -14
- data/test_app/db/migrate/20081103003834_create_projects.rb +0 -18
- data/test_app/db/schema.rb +0 -46
- data/test_app/db/test.sqlite3 +0 -0
- data/test_app/doc/README_FOR_APP +0 -2
- data/test_app/public/404.html +0 -30
- data/test_app/public/422.html +0 -30
- data/test_app/public/500.html +0 -30
- data/test_app/public/dispatch.cgi +0 -10
- data/test_app/public/dispatch.fcgi +0 -24
- data/test_app/public/dispatch.rb +0 -10
- data/test_app/public/favicon.ico +0 -0
- data/test_app/public/images/rails.png +0 -0
- data/test_app/public/javascripts/application.js +0 -2
- data/test_app/public/javascripts/controls.js +0 -963
- data/test_app/public/javascripts/dragdrop.js +0 -972
- data/test_app/public/javascripts/effects.js +0 -1120
- data/test_app/public/javascripts/prototype.js +0 -4225
- data/test_app/public/robots.txt +0 -5
- data/test_app/public/stylesheets/scaffold.css +0 -62
- data/test_app/script/about +0 -4
- data/test_app/script/console +0 -3
- data/test_app/script/dbconsole +0 -3
- data/test_app/script/destroy +0 -3
- data/test_app/script/generate +0 -3
- data/test_app/script/performance/benchmarker +0 -3
- data/test_app/script/performance/profiler +0 -3
- data/test_app/script/performance/request +0 -3
- data/test_app/script/plugin +0 -3
- data/test_app/script/process/inspector +0 -3
- data/test_app/script/process/reaper +0 -3
- data/test_app/script/process/spawner +0 -3
- data/test_app/script/runner +0 -3
- data/test_app/script/server +0 -3
- data/test_app/test/functional/companies_controller_test.rb +0 -8
- data/test_app/test/functional/user_sessions_controller_test.rb +0 -36
- data/test_app/test/functional/users_controller_test.rb +0 -8
- data/test_app/test/integration/company_user_session_stories_test.rb +0 -46
- data/test_app/test/integration/user_sesion_stories_test.rb +0 -105
- data/test_app/test/integration/user_session_config_test.rb +0 -24
- data/test_app/test/integration/user_session_test.rb +0 -161
- data/test_app/test/test_helper.rb +0 -81
- data/test_app/test/unit/account_test.rb +0 -8
- data/test_app/test/unit/company_test.rb +0 -8
- data/test_app/test/unit/project_test.rb +0 -8
- data/test_app/test/unit/user_test.rb +0 -80
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 1.0.0 released 2008-11-05
|
2
|
+
|
3
|
+
* Checked for blank login counts, if a default wasnt set in the migrations.
|
4
|
+
* Added check for database table in acts_as_authentic to avoid errors in initial setup.
|
5
|
+
* Completely rewrote tests to be more conventional and thorough tests, removed test_app.
|
6
|
+
* Modified how validations work so that a validate method was added as well as callbacks for that method.
|
7
|
+
* Extracted scope support into its own module to help organize code better.
|
8
|
+
* Added in salt for encryption, just like hashes and removed :crypto_provider_type option for acts_as_authentic.
|
9
|
+
* Added merb adapters.
|
10
|
+
* Improved documentation throughout.
|
11
|
+
|
1
12
|
== 0.10.4 released 2008-10-31
|
2
13
|
|
3
14
|
* Changed configuration to use inheritable attributes
|
data/Manifest
CHANGED
@@ -4,12 +4,14 @@ lib/authlogic/active_record/acts_as_authentic.rb
|
|
4
4
|
lib/authlogic/active_record/authenticates_many.rb
|
5
5
|
lib/authlogic/active_record/scoped_session.rb
|
6
6
|
lib/authlogic/controller_adapters/abstract_adapter.rb
|
7
|
+
lib/authlogic/controller_adapters/merb_adapter.rb
|
7
8
|
lib/authlogic/controller_adapters/rails_adapter.rb
|
8
9
|
lib/authlogic/session/active_record_trickery.rb
|
9
10
|
lib/authlogic/session/base.rb
|
10
11
|
lib/authlogic/session/callbacks.rb
|
11
12
|
lib/authlogic/session/config.rb
|
12
13
|
lib/authlogic/session/errors.rb
|
14
|
+
lib/authlogic/session/scopes.rb
|
13
15
|
lib/authlogic/sha512_crypto_provider.rb
|
14
16
|
lib/authlogic/version.rb
|
15
17
|
lib/authlogic.rb
|
@@ -17,84 +19,19 @@ Manifest
|
|
17
19
|
MIT-LICENSE
|
18
20
|
Rakefile
|
19
21
|
README.rdoc
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
test_app/app/views/users/new.html.erb
|
37
|
-
test_app/app/views/users/show.html.erb
|
38
|
-
test_app/config/boot.rb
|
39
|
-
test_app/config/database.yml
|
40
|
-
test_app/config/environment.rb
|
41
|
-
test_app/config/environments/development.rb
|
42
|
-
test_app/config/environments/production.rb
|
43
|
-
test_app/config/environments/test.rb
|
44
|
-
test_app/config/initializers/inflections.rb
|
45
|
-
test_app/config/initializers/mime_types.rb
|
46
|
-
test_app/config/initializers/new_rails_defaults.rb
|
47
|
-
test_app/config/routes.rb
|
48
|
-
test_app/db/development.sqlite3
|
49
|
-
test_app/db/migrate/20081023040052_create_users.rb
|
50
|
-
test_app/db/migrate/20081103003828_create_companies.rb
|
51
|
-
test_app/db/migrate/20081103003834_create_projects.rb
|
52
|
-
test_app/db/schema.rb
|
53
|
-
test_app/db/test.sqlite3
|
54
|
-
test_app/doc/README_FOR_APP
|
55
|
-
test_app/public/404.html
|
56
|
-
test_app/public/422.html
|
57
|
-
test_app/public/500.html
|
58
|
-
test_app/public/dispatch.cgi
|
59
|
-
test_app/public/dispatch.fcgi
|
60
|
-
test_app/public/dispatch.rb
|
61
|
-
test_app/public/favicon.ico
|
62
|
-
test_app/public/images/rails.png
|
63
|
-
test_app/public/javascripts/application.js
|
64
|
-
test_app/public/javascripts/controls.js
|
65
|
-
test_app/public/javascripts/dragdrop.js
|
66
|
-
test_app/public/javascripts/effects.js
|
67
|
-
test_app/public/javascripts/prototype.js
|
68
|
-
test_app/public/robots.txt
|
69
|
-
test_app/public/stylesheets/scaffold.css
|
70
|
-
test_app/Rakefile
|
71
|
-
test_app/README
|
72
|
-
test_app/script/about
|
73
|
-
test_app/script/console
|
74
|
-
test_app/script/dbconsole
|
75
|
-
test_app/script/destroy
|
76
|
-
test_app/script/generate
|
77
|
-
test_app/script/performance/benchmarker
|
78
|
-
test_app/script/performance/profiler
|
79
|
-
test_app/script/performance/request
|
80
|
-
test_app/script/plugin
|
81
|
-
test_app/script/process/inspector
|
82
|
-
test_app/script/process/reaper
|
83
|
-
test_app/script/process/spawner
|
84
|
-
test_app/script/runner
|
85
|
-
test_app/script/server
|
86
|
-
test_app/test/fixtures/companies.yml
|
87
|
-
test_app/test/fixtures/projects.yml
|
88
|
-
test_app/test/fixtures/users.yml
|
89
|
-
test_app/test/functional/companies_controller_test.rb
|
90
|
-
test_app/test/functional/user_sessions_controller_test.rb
|
91
|
-
test_app/test/functional/users_controller_test.rb
|
92
|
-
test_app/test/integration/company_user_session_stories_test.rb
|
93
|
-
test_app/test/integration/user_sesion_stories_test.rb
|
94
|
-
test_app/test/integration/user_session_config_test.rb
|
95
|
-
test_app/test/integration/user_session_test.rb
|
96
|
-
test_app/test/test_helper.rb
|
97
|
-
test_app/test/unit/account_test.rb
|
98
|
-
test_app/test/unit/company_test.rb
|
99
|
-
test_app/test/unit/project_test.rb
|
100
|
-
test_app/test/unit/user_test.rb
|
22
|
+
test/active_record_acts_as_authentic_test.rb
|
23
|
+
test/active_record_authenticates_many_test.rb
|
24
|
+
test/fixtures/companies.yml
|
25
|
+
test/fixtures/employees.yml
|
26
|
+
test/fixtures/projects.yml
|
27
|
+
test/fixtures/users.yml
|
28
|
+
test/test_helper.rb
|
29
|
+
test/user_session_active_record_trickery_test.rb
|
30
|
+
test/user_session_base_test.rb
|
31
|
+
test/user_session_config_test.rb
|
32
|
+
test/user_session_scopes_test.rb
|
33
|
+
test_libs/aes128_crypto_provider.rb
|
34
|
+
test_libs/mock_controller.rb
|
35
|
+
test_libs/mock_cookie_jar.rb
|
36
|
+
test_libs/mock_request.rb
|
37
|
+
test_libs/ordered_hash.rb
|
data/README.rdoc
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
= Authlogic
|
2
2
|
|
3
|
-
Authlogic is
|
3
|
+
Authlogic is a framework agnostic object based authentication solution that handles all of the non sense for you. It's as easy as ActiveRecord is with a database. Put simply, its the Chuck Norris of authentication solutions for rails, merb, etc.
|
4
4
|
|
5
|
-
The last thing we need is another authentication solution
|
5
|
+
The last thing we need is another authentication solution, right? That's what I thought until I tried out some of the current solutions in both rails and merb. None of them felt right. They were either too complicated, bloated, littered my application with tons of code, or were just confusing. This is not the simple / elegant ruby we all fell in love with. We need a "ruby like" authentication solution. Authlogic is my attempt to satisfy that need...
|
6
6
|
|
7
|
-
|
7
|
+
Let's take a rails application, wouldn't it be nice to keep your app up to date with the latest and greatest security techniques with a simple update of a plugin?
|
8
8
|
|
9
|
-
What if you could have authentication up and running in minutes without having to run a generator? All because it's simple, like everything else
|
9
|
+
What if you could have authentication up and running in minutes without having to run a generator? All because it's simple, like everything else.
|
10
10
|
|
11
11
|
What if creating a user session could be as simple as...
|
12
12
|
|
@@ -35,8 +35,8 @@ What if your user sessions controller could look just like your other controller
|
|
35
35
|
|
36
36
|
Look familiar? If you didn't know any better, you would think UserSession was an ActiveRecord model. I think that's pretty cool, because it fits nicely into the RESTful development pattern, a style we all know and love. What about the view...
|
37
37
|
|
38
|
-
<%= error_messages_for "user_session" %>
|
39
38
|
<% form_for @user_session do |f| %>
|
39
|
+
<%= f.error_messages %>
|
40
40
|
<%= f.label :login %><br />
|
41
41
|
<%= f.text_field :login %><br />
|
42
42
|
<br />
|
@@ -63,8 +63,8 @@ Authlogic makes this a reality. This is just the tip of the ice berg. Keep readi
|
|
63
63
|
== Helpful links
|
64
64
|
|
65
65
|
* <b>Documentation:</b> http://authlogic.rubyforge.org
|
66
|
-
* <b>Authlogic setup tutorial:</b>
|
67
|
-
* <b>Live example of the setup tutorial above (with source):</b>
|
66
|
+
* <b>Authlogic setup tutorial:</b> http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup
|
67
|
+
* <b>Live example of the setup tutorial above (with source):</b> http://authlogic_example.binarylogic.com
|
68
68
|
* <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/18752-authlogic
|
69
69
|
|
70
70
|
== Install and use
|
@@ -79,7 +79,39 @@ Or as a plugin
|
|
79
79
|
|
80
80
|
script/plugin install git://github.com/binarylogic/authlogic.git
|
81
81
|
|
82
|
-
|
82
|
+
=== Create your session
|
83
|
+
|
84
|
+
Lets assume you are setting up a session for your User model.
|
85
|
+
|
86
|
+
Create your user_session.rb file:
|
87
|
+
|
88
|
+
# app/models/user_session.rb
|
89
|
+
class UserSession < Authgasm::Session::Base
|
90
|
+
# configuration here, just like ActiveRecord, or in an initializer
|
91
|
+
# See Authgasm::Session::Config::ClassMethods for more details
|
92
|
+
end
|
93
|
+
|
94
|
+
=== Ensure proper database fields
|
95
|
+
|
96
|
+
The user model needs to have the following columns. The names of these columns can be changed with configuration. Better yet, Authgasm tries to guess these names by checking for the existence of common names. See Authgasm::Session::Config::ClassMethods for more details, but chances are you won't have to specify any configuration for your field names, even if they aren't the same names as below.
|
97
|
+
|
98
|
+
t.string :login, :null => false
|
99
|
+
t.string :crypted_password, :null => false
|
100
|
+
t.string :password_salt, :null => false # not needed if you are encrypting your pw instead of using a hash algorithm
|
101
|
+
t.string :remember_token, :null => false
|
102
|
+
t.integer :login_count # This is optional, it is a "magic" column, just like "created_at". See below for a list of all magic columns.
|
103
|
+
|
104
|
+
=== Set up your model
|
105
|
+
|
106
|
+
Make sure you have a model that you will be authenticating with. For this example let's say you have a User model:
|
107
|
+
|
108
|
+
class User < ActiveRecord::Base
|
109
|
+
acts_as_authentic # for options see documentation: Authgasm::ActsAsAuthentic::ClassMethods
|
110
|
+
end
|
111
|
+
|
112
|
+
The options for acts_as_authentic are based on the UserSession configuration. So if you specified configuration for your UserSession model you should not have to specify any options for acts_as_authentic, unless you want them to be different.
|
113
|
+
|
114
|
+
Done! Now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this readme or check out the tutorial (see above in "helpful links") for a more detailed walk through.
|
83
115
|
|
84
116
|
== Magic Columns
|
85
117
|
|
@@ -104,7 +136,7 @@ Authlogic tries to check the state of the record before creating the session. If
|
|
104
136
|
|
105
137
|
What's neat about this is that these are checked upon any type of login. When logging in explicitly, by cookie, session, or basic http auth. So if you mark a user inactive in the middle of their session they wont be logged back in next time they refresh the page. Giving you complete control.
|
106
138
|
|
107
|
-
Need Authlogic to check your own "state"? No problem, check out the hooks section below. Add in a before_validation
|
139
|
+
Need Authlogic to check your own "state"? No problem, check out the hooks section below. Add in a before_validation to do your own checking. The sky is the limit.
|
108
140
|
|
109
141
|
== Hooks / Callbacks
|
110
142
|
|
@@ -172,7 +204,7 @@ This scopes your login field validation, so that users are allowed to have the s
|
|
172
204
|
|
173
205
|
=== Scoping your session
|
174
206
|
|
175
|
-
When
|
207
|
+
When the session tries to validate it searches for a record. You want to scope that search. No problem...
|
176
208
|
|
177
209
|
The goal of Authlogic was to not try and introduce anything new. As a result I came up with:
|
178
210
|
|
@@ -189,9 +221,9 @@ This works just like ActiveRecord, so it should come natural. Here is how you ge
|
|
189
221
|
|
190
222
|
=== Scoping cookies
|
191
223
|
|
192
|
-
What's neat about cookies is that if you use sub domains they automatically scope their self. Meaning if you create a cookie in whatever.yourdomain.com it will not exist in another.yourdomain.com. So if you
|
224
|
+
What's neat about cookies is that if you use sub domains they automatically scope their self. Meaning if you create a cookie in whatever.yourdomain.com it will not exist in another.yourdomain.com. So if you are using subdomains to scope your users, you don't have to do anything.
|
193
225
|
|
194
|
-
But what if you don't want to separate your cookies by subdomains? You can accomplish this by doing:
|
226
|
+
But what if you *don't* want to separate your cookies by subdomains? You can accomplish this by doing:
|
195
227
|
|
196
228
|
ActionController::Base.session_options[:session_domain] = ‘.mydomain.com’
|
197
229
|
|
@@ -205,7 +237,7 @@ Now let's look at this from the other angle. What if you are *NOT* using subdoma
|
|
205
237
|
|
206
238
|
Done, Authlogic will give each cookie a unique name depending on the account.
|
207
239
|
|
208
|
-
With the above information you should be able to scope your sessions any way you want. Just mix and match the tools above to accomplish
|
240
|
+
With the above information you should be able to scope your sessions any way you want. Just mix and match the tools above to accomplish this. Also check out the documentation on Authlogic::ActiveRecord::AuthenticatesMany.
|
209
241
|
|
210
242
|
== Errors
|
211
243
|
|
@@ -250,13 +282,17 @@ Obviously there is a little more to it than this, but hopefully this clarifies a
|
|
250
282
|
|
251
283
|
When things come together like this I think its a sign that you are doing something right. Put that in your pipe and smoke it!
|
252
284
|
|
253
|
-
==
|
285
|
+
== Framework agnostic (Rails, Merb, etc.)
|
286
|
+
|
287
|
+
I designed Authlogic to be framework agnostic, meaning it doesn't care what framework you use it in. Right out of the box it supports rails and merb. I have not had the opportunity to use other frameworks, but the only thing stopping Authlogic from being used in other frameworks is a simple adapter. Check out controller_adapters/rails_adapter, or controller_adapters/merb_adapter.
|
288
|
+
|
289
|
+
Since pretty much all of the frameworks in ruby follow the Rack conventions, the code should be very similar across adapters. You're saying "but Ben, why not just hook into Rack and avoid the need for controller adapters all together?". It's not that simple, because rails doesn't inherit from the Rack::Request class, plus there are small differences between how rack is implemented in each framework. Authlogic has to hook into your controller with a before_filter anyways, so it can "activate" itself. Why not just use the controller object?
|
254
290
|
|
255
|
-
|
291
|
+
The point in all of this rambling is that implementing Authlogic is as simple as creating an adapter. I created both the rails and merb adapters in under 10 minutes. If you have an adapter you created and would like to add please let me know and I will add it into the source.
|
256
292
|
|
257
293
|
== How it works
|
258
294
|
|
259
|
-
Interested in how all of this all works? Basically a before_filter is automatically set in your controller which lets Authlogic know about the current controller object. This "activates" Authlogic and allows Authlogic to set sessions, cookies, login via basic http auth, etc. If you are using
|
295
|
+
Interested in how all of this all works? Basically a before_filter is automatically set in your controller which lets Authlogic know about the current controller object. This "activates" Authlogic and allows Authlogic to set sessions, cookies, login via basic http auth, etc. If you are using your framework in a multiple thread environment, don't worry. I kept that in mind and made this thread safe.
|
260
296
|
|
261
297
|
From there it is pretty simple. When you try to create a new session the record is authenticated and then all of the session / cookie magic is done for you. The sky is the limit.
|
262
298
|
|
@@ -268,7 +304,7 @@ I don't necessarily think the current solutions are "wrong", nor am I saying Aut
|
|
268
304
|
|
269
305
|
=== Generators are messy
|
270
306
|
|
271
|
-
Generators have their place, and it is not to add authentication to
|
307
|
+
Generators have their place, and it is not to add authentication to an app. It doesn't make sense. Generators are meant to be a starting point for repetitive tasks that have no sustainable pattern. Take controllers, the set up is the same thing over and over, but they eventually evolve to a point where there is no clear cut pattern. Trying to extract a pattern out into a library would be extremely hard, messy, and overly complicated. As a result, generators make sense here.
|
272
308
|
|
273
309
|
Authentication is a one time set up process for your app. It's the same thing over and over and the pattern never really changes. The only time it changes is to conform with newer / stricter security techniques. This is exactly why generators should not be an authentication solution. Generators add code to your application, once code crosses that line, you are responsible for maintaining it. You get to make sure it stays up with the latest and greatest security techniques. And when the plugin you used releases some major update, you can't just re-run the generator, you get to sift through the code to see what changed. You don't really have a choice either, because you can't ignore security updates.
|
274
310
|
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Echoe.new 'authlogic' do |p|
|
|
8
8
|
p.author = "Ben Johnson of Binary Logic"
|
9
9
|
p.email = 'bjohnson@binarylogic.com'
|
10
10
|
p.project = 'authlogic'
|
11
|
-
p.summary = "
|
11
|
+
p.summary = "Framework agnostic object based authentication solution that handles all of the non sense for you. It's as easy as ActiveRecord is with a database."
|
12
12
|
p.url = "http://github.com/binarylogic/authlogic"
|
13
13
|
p.dependencies = %w(activesupport activerecord)
|
14
14
|
p.include_rakefile = true
|
data/authlogic.gemspec
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{authlogic}
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "1.0.0"
|
4
4
|
|
5
5
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
6
6
|
s.authors = ["Ben Johnson of Binary Logic"]
|
7
|
-
s.date = %q{2008-11-
|
8
|
-
s.description = %q{
|
7
|
+
s.date = %q{2008-11-05}
|
8
|
+
s.description = %q{Framework agnostic object based authentication solution that handles all of the non sense for you. It's as easy as ActiveRecord is with a database.}
|
9
9
|
s.email = %q{bjohnson@binarylogic.com}
|
10
|
-
s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/authlogic/active_record/acts_as_authentic.rb", "lib/authlogic/active_record/authenticates_many.rb", "lib/authlogic/active_record/scoped_session.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/sha512_crypto_provider.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "README.rdoc"]
|
11
|
-
s.files = ["CHANGELOG.rdoc", "init.rb", "lib/authlogic/active_record/acts_as_authentic.rb", "lib/authlogic/active_record/authenticates_many.rb", "lib/authlogic/active_record/scoped_session.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/sha512_crypto_provider.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "
|
10
|
+
s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/authlogic/active_record/acts_as_authentic.rb", "lib/authlogic/active_record/authenticates_many.rb", "lib/authlogic/active_record/scoped_session.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/sha512_crypto_provider.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "README.rdoc"]
|
11
|
+
s.files = ["CHANGELOG.rdoc", "init.rb", "lib/authlogic/active_record/acts_as_authentic.rb", "lib/authlogic/active_record/authenticates_many.rb", "lib/authlogic/active_record/scoped_session.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/sha512_crypto_provider.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "test/active_record_acts_as_authentic_test.rb", "test/active_record_authenticates_many_test.rb", "test/fixtures/companies.yml", "test/fixtures/employees.yml", "test/fixtures/projects.yml", "test/fixtures/users.yml", "test/test_helper.rb", "test/user_session_active_record_trickery_test.rb", "test/user_session_base_test.rb", "test/user_session_config_test.rb", "test/user_session_scopes_test.rb", "test_libs/aes128_crypto_provider.rb", "test_libs/mock_controller.rb", "test_libs/mock_cookie_jar.rb", "test_libs/mock_request.rb", "test_libs/ordered_hash.rb", "authlogic.gemspec"]
|
12
12
|
s.has_rdoc = true
|
13
13
|
s.homepage = %q{http://github.com/binarylogic/authlogic}
|
14
14
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Authlogic", "--main", "README.rdoc"]
|
15
15
|
s.require_paths = ["lib"]
|
16
16
|
s.rubyforge_project = %q{authlogic}
|
17
17
|
s.rubygems_version = %q{1.2.0}
|
18
|
-
s.summary = %q{
|
18
|
+
s.summary = %q{Framework agnostic object based authentication solution that handles all of the non sense for you. It's as easy as ActiveRecord is with a database.}
|
19
|
+
s.test_files = ["test/active_record_acts_as_authentic_test.rb", "test/active_record_authenticates_many_test.rb", "test/test_helper.rb", "test/user_session_active_record_trickery_test.rb", "test/user_session_base_test.rb", "test/user_session_config_test.rb", "test/user_session_scopes_test.rb"]
|
19
20
|
|
20
21
|
if s.respond_to? :specification_version then
|
21
22
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/lib/authlogic.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
require "active_support"
|
2
|
+
|
1
3
|
require File.dirname(__FILE__) + "/authlogic/version"
|
2
4
|
|
3
5
|
require File.dirname(__FILE__) + "/authlogic/controller_adapters/abstract_adapter"
|
4
6
|
require File.dirname(__FILE__) + "/authlogic/controller_adapters/rails_adapter" if defined?(Rails)
|
7
|
+
require File.dirname(__FILE__) + "/authlogic/controller_adapters/merb_adapter" if defined?(Merb)
|
5
8
|
|
6
9
|
require File.dirname(__FILE__) + "/authlogic/sha512_crypto_provider"
|
7
10
|
|
@@ -13,6 +16,7 @@ require File.dirname(__FILE__) + "/authlogic/session/active_record_trickery"
|
|
13
16
|
require File.dirname(__FILE__) + "/authlogic/session/callbacks"
|
14
17
|
require File.dirname(__FILE__) + "/authlogic/session/config"
|
15
18
|
require File.dirname(__FILE__) + "/authlogic/session/errors"
|
19
|
+
require File.dirname(__FILE__) + "/authlogic/session/scopes"
|
16
20
|
require File.dirname(__FILE__) + "/authlogic/session/base"
|
17
21
|
|
18
22
|
module Authlogic
|
@@ -20,6 +24,7 @@ module Authlogic
|
|
20
24
|
class Base
|
21
25
|
include ActiveRecordTrickery
|
22
26
|
include Callbacks
|
27
|
+
include Scopes
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
@@ -1,15 +1,9 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module ActiveRecord # :nodoc:
|
3
3
|
# = Acts As Authentic
|
4
|
-
# Provides
|
4
|
+
# Provides the acts_as_authentic method to include in your models to help with authentication. See method below.
|
5
5
|
module ActsAsAuthentic
|
6
|
-
|
7
|
-
#
|
8
|
-
# <b>Please keep in mind</b> that based on your configuration the method names could change. For example, if you pass the option:
|
9
|
-
#
|
10
|
-
# :password_field => :pass
|
11
|
-
#
|
12
|
-
# The method will not be password=, it will be pass=. Same with valid_password?, it will be valid_pass?, etc.
|
6
|
+
# Call this method in your model to add in basic authentication madness that your authlogic session expects.
|
13
7
|
#
|
14
8
|
# === Methods
|
15
9
|
# For example purposes lets assume you have a User model.
|
@@ -32,21 +26,71 @@ module Authlogic
|
|
32
26
|
# user.forget! Changes their remember token, making their cookie and session invalid. A way to log the user out withouth changing their password.
|
33
27
|
#
|
34
28
|
# === Options
|
35
|
-
#
|
36
|
-
# * <tt>
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# * <tt>
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# * <tt>
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# * <tt>
|
29
|
+
#
|
30
|
+
# * <tt>session_class:</tt> default: "#{name}Session",
|
31
|
+
# This is the related session class. A lot of the configuration will be based off of the configuration values of this class.
|
32
|
+
#
|
33
|
+
# * <tt>crypto_provider:</tt> default: Authlogic::Sha512CryptoProvider,
|
34
|
+
# This is the class that provides your encryption. By default Authlogic provides its own crypto provider that uses Sha512 encrypton.
|
35
|
+
#
|
36
|
+
# * <tt>login_field:</tt> default: options[:session_class].login_field,
|
37
|
+
# The name of the field used for logging in, this is guess based on what columns are in your db. Only specify if you aren't using:
|
38
|
+
# login, username, or email
|
39
|
+
#
|
40
|
+
# * <tt>login_field_type:</tt> default: options[:login_field] == :email ? :email : :login,
|
41
|
+
# Tells authlogic how to validation the field, what regex to use, etc. If the field name is email it will automatically use email,
|
42
|
+
# otherwise it uses login.
|
43
|
+
#
|
44
|
+
# * <tt>login_field_regex:</tt> default: if email then typical email regex, otherwise typical login regex.
|
45
|
+
# This is used in validates_format_of for the login_field.
|
46
|
+
#
|
47
|
+
# * <tt>login_field_regex_message:</tt> the message to use when the validates_format_of for the login field fails.
|
48
|
+
#
|
49
|
+
# * <tt>password_field:</tt> default: options[:session_class].password_field,
|
50
|
+
# This is the name of the field to set the password, *NOT* the field the encrypted password is stored.
|
51
|
+
#
|
52
|
+
# * <tt>crypted_password_field:</tt> default: depends on which columns are present,
|
53
|
+
# The name of the database field where your encrypted password is stored. If the name of the field is different from any of the following
|
54
|
+
# you need to specify it with this option: crypted_password, encrypted_password, password_hash, pw_hash
|
55
|
+
#
|
56
|
+
# * <tt>password_salt_field:</tt> default: depends on which columns are present,
|
57
|
+
# This is the name of the field in your database that stores your password salt. If the name of the field is different from any of the
|
58
|
+
# following then you need to specify it with this option: password_salt, pw_salt, salt
|
59
|
+
#
|
60
|
+
# * <tt>remember_token_field:</tt> default: options[:session_class].remember_token_field,
|
61
|
+
# This is the name of the field your remember_token is stored. The remember token is a unique token that is stored in the users cookie and
|
62
|
+
# session. This way you have complete control of when session expire and you don't have to change passwords to expire sessions. This also
|
63
|
+
# ensures that stale sessions can not be persisted. By stale, I mean sessions that are logged in using an outdated password. If the name
|
64
|
+
# of the field is anything other than the following you need to specify it with this option: remember_token, remember_key, cookie_token,
|
65
|
+
# cookie_key
|
66
|
+
#
|
67
|
+
# * <tt>scope:</tt> default: nil,
|
68
|
+
# This scopes validations. If all of your users belong to an account you might want to scope everything to the account. Just pass :account_id
|
69
|
+
#
|
70
|
+
# * <tt>logged_in_timeout:</tt> default: 10.minutes,
|
71
|
+
# This is really just a nifty feature to tell if a user is logged in or not. It's based on activity. So if the user in inactive longer than
|
72
|
+
# the value you pass here they are assumed "logged out".
|
73
|
+
#
|
74
|
+
# * <tt>session_ids:</tt> default: [nil],
|
75
|
+
# The sessions that we want to automatically reset when a user is created or updated so you don't have to worry about this. Set to [] to disable.
|
76
|
+
# Should be an array of ids. See the Authlogic::Session documentation for information on ids. The order is important.
|
77
|
+
# The first id should be your main session, the session they need to log into first. This is generally nil. When you don't specify an id
|
78
|
+
# in your session you are really just inexplicitly saying you want to use the id of nil.
|
47
79
|
def acts_as_authentic(options = {})
|
80
|
+
# If we don't have a database, skip all of this, solves initial setup errors
|
81
|
+
begin
|
82
|
+
column_names
|
83
|
+
rescue Exception
|
84
|
+
return
|
85
|
+
end
|
86
|
+
|
48
87
|
# Setup default options
|
49
|
-
|
88
|
+
begin
|
89
|
+
options[:session_class] ||= "#{name}Session".constantize
|
90
|
+
rescue NameError
|
91
|
+
raise NameError.new("You must create a #{name}Session class before a model can act_as_authentic. If that is not the name of the class pass the class constant via the :session_class option.")
|
92
|
+
end
|
93
|
+
|
50
94
|
options[:crypto_provider] ||= Sha512CryptoProvider
|
51
95
|
options[:crypto_provider_type] ||= options[:crypto_provider].respond_to?(:decrypt) ? :encryption : :hash
|
52
96
|
options[:login_field] ||= options[:session_class].login_field
|
@@ -74,11 +118,14 @@ module Authlogic
|
|
74
118
|
email_name_regex = '[\w\.%\+\-]+'
|
75
119
|
domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
|
76
120
|
domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
|
77
|
-
|
78
|
-
|
121
|
+
options[:login_field_regex] ||= /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
|
122
|
+
options[:login_field_regex_message] ||= "should look like an email address."
|
123
|
+
validates_format_of options[:login_field], :with => options[:login_field_regex], :message => options[:login_field_regex_message]
|
79
124
|
else
|
80
125
|
validates_length_of options[:login_field], :within => 2..100
|
81
|
-
|
126
|
+
options[:login_field_regex] ||= /\A\w[\w\.\-_@ ]+\z/
|
127
|
+
options[:login_field_regex_message] ||= "use only letters, numbers, spaces, and .-_@ please."
|
128
|
+
validates_format_of options[:login_field], :with => options[:login_field_regex], :message => options[:login_field_regex_message]
|
82
129
|
end
|
83
130
|
|
84
131
|
validates_uniqueness_of options[:login_field], :scope => options[:scope]
|
@@ -88,7 +135,7 @@ module Authlogic
|
|
88
135
|
|
89
136
|
if column_names.include?("last_request_at")
|
90
137
|
named_scope :logged_in, lambda { {:conditions => ["last_request_at > ?", options[:logged_in_timeout].ago]} }
|
91
|
-
named_scope :logged_out, lambda { {:conditions => ["last_request_at <= ?", options[:logged_in_timeout].ago]} }
|
138
|
+
named_scope :logged_out, lambda { {:conditions => ["last_request_at is NULL or last_request_at <= ?", options[:logged_in_timeout].ago]} }
|
92
139
|
end
|
93
140
|
|
94
141
|
before_save :get_session_information, :if => :update_sessions?
|
@@ -101,7 +148,8 @@ module Authlogic
|
|
101
148
|
# Class methods
|
102
149
|
class_eval <<-"end_eval", __FILE__, __LINE__
|
103
150
|
def self.unique_token
|
104
|
-
|
151
|
+
# Force using the Sha512 because all that we are doing is creating a unique token, a hash is perfect for this
|
152
|
+
Authlogic::Sha512CryptoProvider.encrypt(Time.now.to_s + (1..10).collect{ rand.to_s }.join)
|
105
153
|
end
|
106
154
|
|
107
155
|
def self.crypto_provider
|
@@ -129,39 +177,23 @@ module Authlogic
|
|
129
177
|
end_eval
|
130
178
|
end
|
131
179
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
self.#{options[:crypted_password_field]} = crypto_provider.encrypt(@#{options[:password_field]} + #{options[:password_salt_field]})
|
142
|
-
end
|
143
|
-
|
144
|
-
def valid_#{options[:password_field]}?(attempted_password)
|
145
|
-
return false if attempted_password.blank?
|
146
|
-
attempted_password == #{options[:crypted_password_field]} || #{options[:crypted_password_field]} == crypto_provider.encrypt(attempted_password + #{options[:password_salt_field]})
|
147
|
-
end
|
148
|
-
end_eval
|
149
|
-
when :encryption
|
150
|
-
class_eval <<-"end_eval", __FILE__, __LINE__
|
151
|
-
def #{options[:password_field]}=(pass)
|
152
|
-
return if pass.blank?
|
153
|
-
self.tried_to_set_#{options[:password_field]} = true
|
154
|
-
@#{options[:password_field]} = pass
|
155
|
-
self.#{options[:remember_token_field]} = self.class.unique_token
|
156
|
-
self.#{options[:crypted_password_field]} = crypto_provider.encrypt(@#{options[:password_field]})
|
157
|
-
end
|
180
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
181
|
+
def #{options[:password_field]}=(pass)
|
182
|
+
return if pass.blank?
|
183
|
+
self.tried_to_set_#{options[:password_field]} = true
|
184
|
+
@#{options[:password_field]} = pass
|
185
|
+
self.#{options[:remember_token_field]} = self.class.unique_token
|
186
|
+
self.#{options[:password_salt_field]} = self.class.unique_token
|
187
|
+
self.#{options[:crypted_password_field]} = crypto_provider.encrypt(@#{options[:password_field]} + #{options[:password_salt_field]})
|
188
|
+
end
|
158
189
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
190
|
+
def valid_#{options[:password_field]}?(attempted_password)
|
191
|
+
return false if attempted_password.blank? || #{options[:crypted_password_field]}.blank? || #{options[:password_salt_field]}.blank?
|
192
|
+
attempted_password == #{options[:crypted_password_field]} ||
|
193
|
+
(crypto_provider.respond_to?(:decrypt) && crypto_provider.decrypt(#{options[:crypted_password_field]}) == attempted_password + #{options[:password_salt_field]}) ||
|
194
|
+
(!crypto_provider.respond_to?(:decrypt) && crypto_provider.encrypt(attempted_password + #{options[:password_salt_field]}) == #{options[:crypted_password_field]})
|
195
|
+
end
|
196
|
+
end_eval
|
165
197
|
|
166
198
|
class_eval <<-"end_eval", __FILE__, __LINE__
|
167
199
|
def #{options[:password_field]}; end
|