rodauth 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +3 -0
- data/MIT-LICENSE +18 -0
- data/README.rdoc +484 -0
- data/Rakefile +91 -0
- data/lib/roda/plugins/rodauth.rb +265 -0
- data/lib/roda/plugins/rodauth/base.rb +428 -0
- data/lib/roda/plugins/rodauth/change_login.rb +48 -0
- data/lib/roda/plugins/rodauth/change_password.rb +42 -0
- data/lib/roda/plugins/rodauth/close_account.rb +42 -0
- data/lib/roda/plugins/rodauth/create_account.rb +92 -0
- data/lib/roda/plugins/rodauth/lockout.rb +292 -0
- data/lib/roda/plugins/rodauth/login.rb +77 -0
- data/lib/roda/plugins/rodauth/logout.rb +36 -0
- data/lib/roda/plugins/rodauth/remember.rb +226 -0
- data/lib/roda/plugins/rodauth/reset_password.rb +205 -0
- data/lib/roda/plugins/rodauth/verify_account.rb +228 -0
- data/spec/migrate/001_tables.rb +64 -0
- data/spec/migrate_password/001_tables.rb +38 -0
- data/spec/rodauth_spec.rb +1114 -0
- data/spec/views/layout.str +11 -0
- data/spec/views/login.str +21 -0
- data/templates/change-login.str +22 -0
- data/templates/change-password.str +21 -0
- data/templates/close-account.str +9 -0
- data/templates/confirm-password.str +16 -0
- data/templates/create-account.str +33 -0
- data/templates/login.str +25 -0
- data/templates/logout.str +9 -0
- data/templates/remember.str +28 -0
- data/templates/reset-password-email.str +5 -0
- data/templates/reset-password-request.str +7 -0
- data/templates/reset-password.str +23 -0
- data/templates/unlock-account-email.str +5 -0
- data/templates/unlock-account-request.str +11 -0
- data/templates/unlock-account.str +11 -0
- data/templates/verify-account-email.str +4 -0
- data/templates/verify-account-resend.str +7 -0
- data/templates/verify-account.str +11 -0
- metadata +227 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8a4422adf6022a2840a86586b6e453bd3661e951
|
4
|
+
data.tar.gz: 9b97988eff1528ca51c74e7b1407f7b92c147eca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4e6b4d2b641bd15b6db50267636e1e3fccbb202d26be23e597df098da039238d090c5afd16f1d7d66b5aee23fa161df7bdf9cde45730971b2f2466b2b4be610d
|
7
|
+
data.tar.gz: d0660ec47396732cdf6d4bb70765fe09d5c02eeb27a6f09811cb3a519c7befd83c86af4c7b178313991160ee10d798f4e100d682d901b46cf2242ea8c50d9b14
|
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2015 Jeremy Evans
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,484 @@
|
|
1
|
+
= Rodauth
|
2
|
+
|
3
|
+
Rodauth is an authentication framework using Roda, Sequel, and PostgreSQL.
|
4
|
+
|
5
|
+
== Design Goals
|
6
|
+
|
7
|
+
* Security: Ship in a maximum security by default configuration
|
8
|
+
* Simplicity: Allow for easy configuration via a DSL
|
9
|
+
* Flexibility: Allow for easy overriding of any part of the framework
|
10
|
+
|
11
|
+
== Features
|
12
|
+
|
13
|
+
* Login
|
14
|
+
* Logout
|
15
|
+
* Change Password
|
16
|
+
* Change Login
|
17
|
+
* Reset Password
|
18
|
+
* Create Account
|
19
|
+
* Close Account
|
20
|
+
* Verify Account
|
21
|
+
* Remember (Autologin via token)
|
22
|
+
* Lockout (Bruteforce protection)
|
23
|
+
|
24
|
+
== Resources
|
25
|
+
|
26
|
+
RDoc :: http://rodauth.jeremyevans.net
|
27
|
+
Demo Site :: http://rodauth-demo.jeremyevans.net
|
28
|
+
Source :: http://github.com/jeremyevans/rodauth
|
29
|
+
Bugs :: http://github.com/jeremyevans/rodauth/issues
|
30
|
+
|
31
|
+
== Security
|
32
|
+
|
33
|
+
=== Passwords
|
34
|
+
|
35
|
+
Passwords are hashed using bcrypt, and the password hashes are
|
36
|
+
kept in a separate table from the accounts table, with a foreign key
|
37
|
+
referencing the accounts table. A PostgreSQL function is added to
|
38
|
+
check the password for a given application account matches.
|
39
|
+
|
40
|
+
A separate database account owns the table containing the password
|
41
|
+
hashes, which the application database account cannot access.
|
42
|
+
The application database account has the ability to execute the
|
43
|
+
function to check the password, but not the ability to access the
|
44
|
+
password hashes directly, making it much more difficult for an
|
45
|
+
attacker to access the password hashes even if they are able to
|
46
|
+
exploit an SQL injection or remote code execution vulnerability
|
47
|
+
in the application. Even if an attacker was able to exploit a
|
48
|
+
vulnerability in the application, they would only be to check if
|
49
|
+
a specific password matches for a given user, which is the same
|
50
|
+
access an attacker would have anyway if they just tried to login.
|
51
|
+
|
52
|
+
While the application database account is not be able to read
|
53
|
+
password hashes, it is still be able to insert password hashes,
|
54
|
+
update passwords hashes, and delete password hashes, so the
|
55
|
+
additional security is not that painful.
|
56
|
+
|
57
|
+
The reason for extra security in regards to password hashes stems from
|
58
|
+
the fact that people tend to reuse passwords, so a compromise of one
|
59
|
+
site can result in account access on other sites, making password hash
|
60
|
+
storage of critical importance even if the other data stored is not
|
61
|
+
that important.
|
62
|
+
|
63
|
+
If you are storing other important information in your database, you
|
64
|
+
should consider using a similar approach in other areas (or all areas)
|
65
|
+
of your application.
|
66
|
+
|
67
|
+
Rodauth can still be used if you are using a more convential approach
|
68
|
+
of storing the password hash in a column in the same table, with
|
69
|
+
a single configuration setting.
|
70
|
+
|
71
|
+
=== Tokens
|
72
|
+
|
73
|
+
Account verification, password resets, remember, and lockout tokens
|
74
|
+
all use a similar approach. They all provide a token, in the format
|
75
|
+
"account-id_long-random-string". By including the id of the account
|
76
|
+
in the token, an attacker can only attempt to bruteforce the token
|
77
|
+
for a single account, instead of being able to bruteforce tokens for
|
78
|
+
all accounts at once (which would be possible if the token was just a
|
79
|
+
random string).
|
80
|
+
|
81
|
+
There is a maximum of 1 token per account for each of these features
|
82
|
+
at a time. This prevents attackers from creating an arbitrary number
|
83
|
+
of requests in order to make bruteforcing easier.
|
84
|
+
|
85
|
+
== Database Setup
|
86
|
+
|
87
|
+
In order to get full advantages of Rodauth's security design, multiple
|
88
|
+
database accounts are involved:
|
89
|
+
|
90
|
+
1) database superuser account (usually postgres)
|
91
|
+
2) application database account
|
92
|
+
3) secondary database account
|
93
|
+
|
94
|
+
The database superuser account is used to load extensions related to the
|
95
|
+
database. The application should never be run using the database
|
96
|
+
superuser account.
|
97
|
+
|
98
|
+
Note that there is not a simple way to use multiple database accounts in
|
99
|
+
the same PostgreSQL database on Heroku. You can still use Rodauth on
|
100
|
+
Heroku, it just won't have the same security benefits. That's not to say
|
101
|
+
it is insecure, just that it drops the security level for password hash
|
102
|
+
storage to the same level as other common authentication solutions.
|
103
|
+
|
104
|
+
=== Load extensions
|
105
|
+
|
106
|
+
If you want to use the login features for Rodauth, you need to load the
|
107
|
+
pgcrypto extension with the database superuser account, and load the
|
108
|
+
citext extension if you want to support case insensitive logins.
|
109
|
+
|
110
|
+
Example:
|
111
|
+
|
112
|
+
echo "CREATE EXTENSION pgcrypto" | psql -U postgres $database_name
|
113
|
+
echo "CREATE EXTENSION citext" | psql -U postgres $database_name
|
114
|
+
|
115
|
+
Note that on Heroku, both of these extensions can be loaded using a
|
116
|
+
standard database account.
|
117
|
+
|
118
|
+
=== Create database accounts
|
119
|
+
|
120
|
+
If you are currently running your application using the database superuser
|
121
|
+
account, the first thing you need to do is to create a database account for
|
122
|
+
the application. It's often best to name this account the same as the
|
123
|
+
database name.
|
124
|
+
|
125
|
+
You should also create a second database account which will own the password
|
126
|
+
hash table.
|
127
|
+
|
128
|
+
Example:
|
129
|
+
|
130
|
+
createuser -U postgres $database_name
|
131
|
+
createuser -U postgres $database_name_password_hashes
|
132
|
+
|
133
|
+
Note that if the database superuser account owns all of the items in the
|
134
|
+
database, you'll need to change the ownership to the database account you
|
135
|
+
just created. See https://gist.github.com/jeremyevans/8483320
|
136
|
+
for a way to do that.
|
137
|
+
|
138
|
+
=== Create tables
|
139
|
+
|
140
|
+
Because two different database accounts are used, two different migrations
|
141
|
+
are required, one for each database account. Here are example migrations.
|
142
|
+
You can modify them to add support for additional columns, or remove tables
|
143
|
+
or columns related to features that you don't need.
|
144
|
+
|
145
|
+
First migration, run using the application database account:
|
146
|
+
|
147
|
+
Sequel.migration do
|
148
|
+
up do
|
149
|
+
# Used by the account verification and close account features
|
150
|
+
create_table(:account_statuses) do
|
151
|
+
Integer :id, :primary_key=>true
|
152
|
+
String :name, :null=>false, :unique=>true
|
153
|
+
end
|
154
|
+
from(:account_statuses).import([:id, :name], [[1, 'Unverified'], [2, 'Verified'], [3, 'Closed']])
|
155
|
+
|
156
|
+
# Used by the create account, account verification,
|
157
|
+
# and close account features.
|
158
|
+
create_table(:accounts) do
|
159
|
+
primary_key :id, :type=>Bignum
|
160
|
+
foreign_key :status_id, :account_statuses, :null=>false, :default=>1
|
161
|
+
citext :email, :null=>false
|
162
|
+
|
163
|
+
constraint :valid_email, :email=>/^[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+$/
|
164
|
+
index :email, :unique=>true, :where=>{:status_id=>[1, 2]}
|
165
|
+
end
|
166
|
+
|
167
|
+
# Used by the password reset feature
|
168
|
+
create_table(:account_password_reset_keys) do
|
169
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>Bignum
|
170
|
+
String :key, :null=>false
|
171
|
+
DateTime :deadline, :null=>false, :default=>Sequel.lit("CURRENT_TIMESTAMP + '1 day'")
|
172
|
+
end
|
173
|
+
|
174
|
+
# Used by the account verification feature
|
175
|
+
create_table(:account_verification_keys) do
|
176
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>Bignum
|
177
|
+
String :key, :null=>false
|
178
|
+
end
|
179
|
+
|
180
|
+
# Used by the remember me feature
|
181
|
+
create_table(:account_remember_keys) do
|
182
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>Bignum
|
183
|
+
String :key, :null=>false
|
184
|
+
DateTime :deadline, :null=>false, :default=>Sequel.lit("CURRENT_TIMESTAMP + '2 weeks'")
|
185
|
+
end
|
186
|
+
|
187
|
+
# Used by the lockout feature
|
188
|
+
create_table(:account_login_failures) do
|
189
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>Bignum
|
190
|
+
Integer :number, :null=>false, :default=>1
|
191
|
+
end
|
192
|
+
create_table(:account_lockouts) do
|
193
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>Bignum
|
194
|
+
String :key, :null=>false
|
195
|
+
DateTime :deadline, :null=>false, :default=>Sequel.lit("CURRENT_TIMESTAMP + '1 day'")
|
196
|
+
end
|
197
|
+
|
198
|
+
# Grant password user access to reference accounts
|
199
|
+
pw_user = get{Sequel.lit('current_user')} + '_password'
|
200
|
+
run "GRANT REFERENCES ON accounts TO #{pw_user}"
|
201
|
+
end
|
202
|
+
|
203
|
+
down do
|
204
|
+
drop_table(:account_lockouts, :account_login_failures, :account_remember_keys,
|
205
|
+
:account_verification_keys, :account_password_reset_keys, :accounts, :account_statuses)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
Second migration, run using the secondary database account:
|
210
|
+
|
211
|
+
Sequel.migration do
|
212
|
+
up do
|
213
|
+
# Used by the login and change password features
|
214
|
+
create_table(:account_password_hashes) do
|
215
|
+
foreign_key :id, :accounts, :primary_key=>true, :type=>Bignum
|
216
|
+
String :password_hash, :null=>false
|
217
|
+
end
|
218
|
+
|
219
|
+
# Function used to check if a password is valid. Takes the related account id
|
220
|
+
# and unencrypted password, checks if password matches password hash.
|
221
|
+
run <<END
|
222
|
+
CREATE OR REPLACE FUNCTION account_valid_password(account_id int8, password text) RETURNS boolean AS $$
|
223
|
+
DECLARE valid boolean;
|
224
|
+
BEGIN
|
225
|
+
SELECT password_hash = crypt($2, password_hash) INTO valid
|
226
|
+
FROM account_password_hashes
|
227
|
+
WHERE account_id = id;
|
228
|
+
RETURN valid;
|
229
|
+
END;
|
230
|
+
$$ LANGUAGE plpgsql
|
231
|
+
SECURITY DEFINER
|
232
|
+
SET search_path = public, pg_temp;
|
233
|
+
END
|
234
|
+
|
235
|
+
# Restrict access to the password hash table
|
236
|
+
app_user = get{Sequel.lit('current_user')}.sub(/_password\z/, '')
|
237
|
+
run "REVOKE ALL ON account_password_hashes FROM public"
|
238
|
+
run "REVOKE ALL ON FUNCTION account_valid_password(int8, text) FROM public"
|
239
|
+
run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{app_user}"
|
240
|
+
run "GRANT SELECT(id) ON account_password_hashes TO #{app_user}"
|
241
|
+
run "GRANT EXECUTE ON FUNCTION account_valid_password(int8, text) TO #{app_user}"
|
242
|
+
end
|
243
|
+
|
244
|
+
down do
|
245
|
+
run "DROP FUNCTION account_valid_password(int8, text)"
|
246
|
+
drop_table(:account_password_hashes)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
If you are using a non-PostgreSQL database or cannot use multiple user
|
251
|
+
accounts, just combine the two migrations into a single migration and
|
252
|
+
exclude the GRANT/REVOKE statements.
|
253
|
+
|
254
|
+
One thing to notice in the above migrations is that Rodauth uses additional
|
255
|
+
tables for additional features, instead of additional columns in a single
|
256
|
+
table.
|
257
|
+
|
258
|
+
== Usage
|
259
|
+
|
260
|
+
=== Basic Usage
|
261
|
+
|
262
|
+
Rodauth is a Roda plugin and loaded the same way other Roda plugins
|
263
|
+
are loaded:
|
264
|
+
|
265
|
+
plugin :rodauth do
|
266
|
+
end
|
267
|
+
|
268
|
+
The block passed to the plugin call uses the Rodauth configuration DSL.
|
269
|
+
The one configuration method that should always be used is enable,
|
270
|
+
which chooses which features you would like to load:
|
271
|
+
|
272
|
+
plugin :rodauth do
|
273
|
+
enable :login, :logout
|
274
|
+
end
|
275
|
+
|
276
|
+
Once features are loaded, you can use any of the configuration methods
|
277
|
+
supported by the features. There are three types of configuration
|
278
|
+
methods. The first type are called auth methods, and they take a
|
279
|
+
block, and overrides the default method that Rodauth uses. Inside the
|
280
|
+
block, you can call super if you want to get the default behavior. For
|
281
|
+
example, if you want to add additional logging when a user logs in:
|
282
|
+
|
283
|
+
plugin :rodauth do
|
284
|
+
enable :login, :logout
|
285
|
+
after_login do
|
286
|
+
logger.info "#{account.email} logged in!"
|
287
|
+
super
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
Inside the block, you are in the context of the Rodauth::Auth
|
292
|
+
instance related to the request. This object has access to everything
|
293
|
+
related to the request via methods:
|
294
|
+
|
295
|
+
request :: RodaRequest instance
|
296
|
+
response :: RodaResponse instance
|
297
|
+
scope :: Roda instance
|
298
|
+
session :: session hash
|
299
|
+
flash :: flash message hash
|
300
|
+
account :: account model instance (if set by an earlier Rodauth method)
|
301
|
+
|
302
|
+
So if you want to log the IP address for the user during login:
|
303
|
+
|
304
|
+
plugin :rodauth do
|
305
|
+
enable :login, :logout
|
306
|
+
after_login do
|
307
|
+
logger.info "#{account.email} logged in from #{request.ip}"
|
308
|
+
super
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
The second type of configuration methods are called auth value
|
313
|
+
methods. They are similar to auth methods, but instead of just
|
314
|
+
accepting a block, they can optionally accept a single argument
|
315
|
+
without a block, which will be treated as a block that just returns
|
316
|
+
that value. For example, the account_model method sets the model
|
317
|
+
class to use for the account, so to override it, you can call the
|
318
|
+
method with another class:
|
319
|
+
|
320
|
+
plugin :rodauth do
|
321
|
+
enable :login, :logout
|
322
|
+
account_model User
|
323
|
+
end
|
324
|
+
|
325
|
+
The third type of configuration methods are called auth block methods,
|
326
|
+
and there are three of them per feature, one for handling the route
|
327
|
+
itself, one for handling just the GET route, and one for handling just
|
328
|
+
the POST route. For the login feature, login_route_block would set
|
329
|
+
the routing block to use if the login route matches, login_get_block
|
330
|
+
would set the routing block to use if the login route matches and it
|
331
|
+
is a GET request, and login_post_block would set the routing block to
|
332
|
+
use if the login route matches and it is a POST request. As auth block
|
333
|
+
methods specify the route blocks, they are executed in the context
|
334
|
+
of the Roda instance, and are passed two arguments, the first being the
|
335
|
+
RodaRequest instance, and the second being the Rodauth::Auth instance.
|
336
|
+
For example, if you wanted to override how a POST request to the login
|
337
|
+
route is handled:
|
338
|
+
|
339
|
+
plugin :rodauth do
|
340
|
+
enable :login
|
341
|
+
login_post_route do |r, auth|
|
342
|
+
# ...
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
By allowing every configuration method to take a block, Rodauth
|
347
|
+
should be flexible enough to integrate into most legacy
|
348
|
+
authentication systems.
|
349
|
+
|
350
|
+
=== Feature Documentation
|
351
|
+
|
352
|
+
The options/methods for the supported features are listed on a
|
353
|
+
separate page per feature. If these links are not active, please
|
354
|
+
view the appropriate file in the doc directory.
|
355
|
+
|
356
|
+
* {Base}[rdoc-ref:doc/base.rdoc] (this feature is autoloaded)
|
357
|
+
* {Login}[rdoc-ref:doc/login.rdoc]
|
358
|
+
* {Logout}[rdoc-ref:doc/logout.rdoc]
|
359
|
+
* {Change Password}[rdoc-ref:doc/change_password.rdoc]
|
360
|
+
* {Change Login}[rdoc-ref:doc/change_login.rdoc]
|
361
|
+
* {Reset Password}[rdoc-ref:doc/reset_password.rdoc]
|
362
|
+
* {Create Account}[rdoc-ref:doc/create_account.rdoc]
|
363
|
+
* {Close Account}[rdoc-ref:doc/close_account.rdoc]
|
364
|
+
* {Verify Account}[rdoc-ref:doc/verify_account.rdoc]
|
365
|
+
* {Remember}[rdoc-ref:doc/remember.rdoc]
|
366
|
+
* {Lockout}[rdoc-ref:doc/lockout.rdoc]
|
367
|
+
|
368
|
+
Since the auth block methods work the same way for each of these
|
369
|
+
features, they are not documented on the feature pages. Additionally,
|
370
|
+
all features have a before auth method (e.g. before_login) that is
|
371
|
+
called before either the GET or POST route blocks are handled.
|
372
|
+
|
373
|
+
=== With Multiple Configurations
|
374
|
+
|
375
|
+
Rodauth supports using multiple rodauth configurations in the same
|
376
|
+
application. You just need to load the plugin a second time,
|
377
|
+
providing a name for any alternate configuration:
|
378
|
+
|
379
|
+
plugin :rodauth do
|
380
|
+
end
|
381
|
+
plugin :rodauth, :name=>:secondary do
|
382
|
+
end
|
383
|
+
|
384
|
+
Then in your routing code, any time you call rodauth, you can provide
|
385
|
+
the name as an argument to use that configuration:
|
386
|
+
|
387
|
+
route do |r|
|
388
|
+
r.on 'secondary' do
|
389
|
+
r.rodauth(:secondary)
|
390
|
+
end
|
391
|
+
|
392
|
+
r.rodauth
|
393
|
+
end
|
394
|
+
|
395
|
+
=== With Other Databases
|
396
|
+
|
397
|
+
You can use Rodauth with other databases besides PostgreSQL. Assuming
|
398
|
+
you are storing the password hashes in the same table as the account
|
399
|
+
information, you can just do:
|
400
|
+
|
401
|
+
plugin :rodauth do
|
402
|
+
account_password_hash_column :password_hash
|
403
|
+
end
|
404
|
+
|
405
|
+
When this option is set, Rodauth will not use a database function
|
406
|
+
to authenticate, it will do the check in ruby. This feature can
|
407
|
+
also be used if you are using PostgreSQL, but for legacy reasons
|
408
|
+
are storing the password hashes in the same table as the account
|
409
|
+
information.
|
410
|
+
|
411
|
+
The Rodauth lockout feature also uses UPDATE RETURNING to update
|
412
|
+
a row and return the new value, so if you are not using PostgreSQL
|
413
|
+
and wish to use the lockout feature, you'll need to override the
|
414
|
+
invalid_login_attempted method.
|
415
|
+
|
416
|
+
=== With Other Web Frameworks
|
417
|
+
|
418
|
+
You can use Rodauth even if your application does not use the Roda web
|
419
|
+
framework. This is possible by adding a Roda middleware that uses
|
420
|
+
Rodauth:
|
421
|
+
|
422
|
+
require 'roda'
|
423
|
+
|
424
|
+
class RodauthApp < Roda
|
425
|
+
plugin :middleware
|
426
|
+
plugin :rodauth
|
427
|
+
route do |r|
|
428
|
+
r.rodauth
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
use RodauthApp
|
433
|
+
|
434
|
+
=== Using External Features
|
435
|
+
|
436
|
+
The enable configuration method is able to load features external to
|
437
|
+
Rodauth. You need to place the external feature file where it can be
|
438
|
+
required via roda/plugins/rodauth/feature_name. That file should
|
439
|
+
use the following basic structure
|
440
|
+
|
441
|
+
class Roda
|
442
|
+
module RodaPlugins
|
443
|
+
module Rodauth
|
444
|
+
# :feature_name will be the argument given to enable to
|
445
|
+
# load the feature
|
446
|
+
FeatureName = Feature.define(:feature_name) do
|
447
|
+
auth_value_methods # one argument per auth value method
|
448
|
+
auth_methods # one argument per auth method
|
449
|
+
|
450
|
+
get_block do |r, auth|
|
451
|
+
# r is the RodaRequest instance
|
452
|
+
# auth is the Rodauth::Auth instance
|
453
|
+
# This block is evaluated in the scope of the Roda instance
|
454
|
+
# ...
|
455
|
+
end
|
456
|
+
|
457
|
+
post_block do |r, auth|
|
458
|
+
# ...
|
459
|
+
end
|
460
|
+
|
461
|
+
# define the default behavior for the auth methods
|
462
|
+
# and auth value methods
|
463
|
+
# ...
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
== Possible Future Directions
|
470
|
+
|
471
|
+
* OmniAuth support. This is not something I plan to work on myself,
|
472
|
+
but I will consider patches that add it.
|
473
|
+
|
474
|
+
== Similar Projects
|
475
|
+
|
476
|
+
All of these are Rails-specific:
|
477
|
+
|
478
|
+
* Devise
|
479
|
+
* Authlogic
|
480
|
+
* Sorcery
|
481
|
+
|
482
|
+
== Author
|
483
|
+
|
484
|
+
Jeremy Evans <code@jeremyevans.net>
|