rodauth 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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>
|