forget-passwords 0.2.9 → 0.2.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c60a2d4e21288d85c0331dc52cf188779d3cb868126f9307046a715f6cb9ffe
4
- data.tar.gz: fcb2d206ae7f90152033156061793e6ad8453d862aff8ed1f33697d4c7f3901a
3
+ metadata.gz: a3215dc2df30a7f53896530fe46e576ccc68e69a9bdeb9dfdcc1d8d55f482077
4
+ data.tar.gz: 56479273ba73c937bda4449b3a9ebbae2aa41736cf8e01bc58c3c209f3179b51
5
5
  SHA512:
6
- metadata.gz: 62c6dd29832cc21fed041dc49dd57557de4db7f9d6e73a3dd19624c50655d9cde301dfc02ca96877e273ed0f11c9b2731e2e7d0b0862a032d941a21584036519
7
- data.tar.gz: 57b901b1dee840cd0bec6f4cf3211a30df85fbb946f7e335cf011297a40071f67a4fc84a63e25e783c5817c5db3c57fa22f339190f8b123eba7177c6d01319fe
6
+ metadata.gz: 4c95ee03bc4b33e7bce7ef05ea11633defac41664eecec042b0ff15ccdd2ef5dbd95ad3faa9336e9f2dcbd583adf0db4cf1674a585007027a31c73d3a732e9b9
7
+ data.tar.gz: 4f98e7c9feb6fd09470c93f820ff5aca5bdfaa27a4e845e6a8efb484cde2ff319224cb3a18435c805ac4998f0ad1f6975d22c8ccb813e76343beadc981625de3
data/README.md CHANGED
@@ -95,10 +95,11 @@ module to operate.
95
95
 
96
96
  ## Usage
97
97
 
98
- To start using ForgetPasswords, we'll assume you have done the necessary
99
- setup on the server (below), as well as all the necessary setup for an
100
- address to send e-mail from. After that, we'll need a database (this
101
- example uses PostgreSQL; you can of course skip this step for SQLite):
98
+ To start using Forget Passwords, we'll assume you have done the
99
+ necessary setup on the server (below), as well as all the necessary
100
+ setup for an address to send e-mail from. After that, we'll need a
101
+ database (this example uses PostgreSQL; you can of course skip this
102
+ step for SQLite):
102
103
 
103
104
  $ createdb forgetpw
104
105
 
@@ -134,8 +135,8 @@ principle it is usable in other systems. What follows is the
134
135
  configuration for Apache 2.4.x or newer.
135
136
 
136
137
  First, we need to declare the authenticator (here it can be called
137
- anything but we are appropriately calling it `ForgetPasswords`) and where
138
- it's listening:
138
+ anything but we are appropriately calling it `ForgetPasswords`) and
139
+ where it's listening:
139
140
 
140
141
  ```apache
141
142
  AuthnzFcgiDefineProvider authn ForgetPasswords fcgi://localhost:10101/
@@ -155,7 +156,7 @@ throwaway user like `nobody`, and then subsequently deny that user. (I
155
156
  would consider this a design flaw in `mod_authnz_fcgi`.) The
156
157
  expression `%{reqenv:FCGI_USER}` (where the slug `FCGI_USER` is
157
158
  configurable on our side) is how the identity gets transmitted
158
- upstream from ForgetPasswords to the server.
159
+ upstream from Forget Passwords to the server.
159
160
 
160
161
  ```apache
161
162
  <Location /protected>
@@ -174,7 +175,7 @@ Another idiosyncrasy of `mod_authnz_fcgi` is that while it uses the
174
175
  to the client necessarily has to come from the downstram content
175
176
  handler. As such, any other information from a _successful_
176
177
  authentication response needs to be smuggled out through environment
177
- variables. Since ForgetPasswords performs a redirect to remove the
178
+ variables. Since Forget Passwords performs a redirect to remove the
178
179
  authentication token from the URL upon successful authentication, the
179
180
  following `mod_rewrite` configuration needs to be in place to turn the
180
181
  environment variable back into an actual redirect:
@@ -224,17 +225,42 @@ ProxyPass /logout fcgi://localhost:10101/logout
224
225
  > crash with a protocol error. While the handling is less than
225
226
  > delicate, this is actually a reasonable expectation, as request
226
227
  > bodies are only read once off the wire and will thus be already
227
- > consumed (whether or not they contain the fields to which ForgetPasswords
228
- > is sensitive) when the content handler is invoked. (The way Apache
229
- > handles the request body, it _can_ be duplicated and reinserted into
230
- > the input stream, but that is a whole project unto itself.
228
+ > consumed (whether or not they contain the fields to which Forget
229
+ > Passwords is sensitive) when the content handler is invoked. (The
230
+ > way Apache handles the request body, it _can_ be duplicated and
231
+ > reinserted into the input stream, but that is a whole project unto
232
+ > itself.
233
+
234
+ ### Caveats
235
+
236
+ I have noticed that a `RewriteRule` (in a `.htaccess`) with the
237
+ passthrough (`PT`) flag will short-circuit the redirect that happens
238
+ when a user follows the link off an e-mail. Same ostensibly goes for
239
+ overriding `DirectoryIndex` in a `.htaccess`. The observable effect is
240
+ that the server returns 401 (and doesn't redirect/remove the query
241
+ string) even though the cookie is set and the knock token is consumed.
242
+ If you refresh the page, then it will say (correctly, from its point
243
+ of view) that the link is expired. If you manually chop off the query
244
+ string, it will correctly display the logged-in state.
245
+
246
+ > One thing I didn't check is if it still returned a `Location:`
247
+ > header, which the browser will ignore if the response code is
248
+ > anything other than most (but not all) of the 300s and 201.
249
+
250
+ This is likely because these configuration directives are causing
251
+ subrequests and/or internal redirects, which triggers the handler, but
252
+ doesn't convey its response to the client. This might be an inherent
253
+ limitation of using FastCGI in `AUTHORIZER` mode, because there is no
254
+ way to tell it that it is being triggered from a subrequest (unless
255
+ there is?). More research is needed to probe potential interactions
256
+ with other handlers.
231
257
 
232
258
  ## Templates
233
259
 
234
- ForgetPasswords has a number of UI states that are embedded in the gem. These
235
- take the form of template files. The functionality of these templates
236
- is currently at the absolute bare minimum required to do the job. The
237
- templates are XHTML, with a basic placeholder substitution
260
+ Forget Passwords has a number of UI states that are embedded in the
261
+ gem. These take the form of template files. The functionality of these
262
+ templates is currently at the absolute bare minimum required to do the
263
+ job. The templates are XHTML, with a basic placeholder substitution
238
264
  functionality, which can take place either in processing instructions
239
265
  (`<?var $WHATEVER?>`), or attribute values (`<elem
240
266
  attr="$WHATEVER"/>`).
@@ -303,7 +329,7 @@ form field by the name of `forward` that contains the current URL.
303
329
 
304
330
  This resource should actually never be seen, as it currently only
305
331
  arises when outside content-handling traffic is directed to locations
306
- other than the two specified by ForgetPasswords.
332
+ other than the two specified by Forget Passwords.
307
333
 
308
334
  ### `knock_bad` (currently handled by `basic-409.xhtml`)
309
335
 
@@ -378,8 +404,8 @@ script can't connectd to the specified SMTP server.
378
404
 
379
405
  ### `email_sent` (currently handled by `email-sent.xhtml`)
380
406
 
381
- This is the confirmation page people see when ForgetPasswords has accepted
382
- their e-mmail address and sent the link-containing e-mail.
407
+ This is the confirmation page people see when Forget Passwords has
408
+ accepted their e-mmail address and sent the link-containing e-mail.
383
409
 
384
410
  ### `post_only` (currently handled by `post-405.xhtml`)
385
411
 
@@ -450,14 +476,15 @@ specific functions within the system, and have a stable location.
450
476
 
451
477
  * `login` is the target that accepts the `POST` request from the `401`
452
478
  page and others, that sends the e-mail and issues a confirmation. It
453
- defaults to `/email-link`. This resource is powered by ForgetPasswords and
454
- is used internally to configure the location of that resource.
479
+ defaults to `/email-link`. This resource is powered by Forget
480
+ Passwords and is used internally to configure the location of that
481
+ resource.
455
482
  * `logout` is the target that accepts the `POST` request to log
456
483
  out. It (rather predictably) defaults to `/logout`. This location is
457
- also handled by ForgetPasswords.
484
+ also handled by Forget Passwords.
458
485
  * `logout_one` is a _static_ (or other arbitrary) target (i.e., _not_
459
- handled by ForgetPasswords) that confirms the user has logged out their
460
- current session. It defaults to `/logged-out`.
486
+ handled by Forget Passwords) that confirms the user has logged out
487
+ their current session. It defaults to `/logged-out`.
461
488
  * `logout_all` is another static target that confirms the user has
462
489
  logged out of all devices.
463
490
 
@@ -534,22 +561,22 @@ of 2022-04-22), the focus can shift to keeping it that way.
534
561
  ### How about expanding out the templates?
535
562
 
536
563
  Localizing the templates is definitely a possibility, as well as
537
- making domain-specific overrides so a single ForgetPasswords daemon could
538
- handle multiple domains with tailor-fit responses for each. I am less
539
- sanguine about going hog-wild with the templates but I could see some
540
- kind of future plug-in interface so people could use their favourite
541
- flavour of templating engine.
564
+ making domain-specific overrides so a single Forget Passwords daemon
565
+ could handle multiple domains with tailor-fit responses for each. I am
566
+ less sanguine about going hog-wild with the templates but I could see
567
+ some kind of future plug-in interface so people could use their
568
+ favourite flavour of templating engine.
542
569
 
543
570
  ### Reconcile with OAuth
544
571
 
545
- The authentication cookie used by ForgetPasswords bears a striking
572
+ The authentication cookie used by Forget Passwords bears a striking
546
573
  resemblance to an [OAuth](https://oauth.net/) bearer token, such that
547
574
  could actually _be_ (at least a proxy for) an OAuth bearer token.
548
575
  Indeed, bearer tokens would make for an _excellent_ cleavage plane for
549
576
  _segmented_ authentication: Method X to bearer token, then bearer
550
577
  token to `REMOTE_USER`. This means we could have multiple
551
- authentication mechanisms (ForgetPasswords, OAuth, X.509, Kerberos, boring
552
- old password, whatever) operating in the same space at once.
578
+ authentication mechanisms (Forget Passwords, OAuth, X.509, Kerberos,
579
+ boring old password, whatever) operating in the same space at once.
553
580
 
554
581
  ### The really interesting thing is `mod_authnz_fcgi`
555
582
 
@@ -566,7 +593,7 @@ the content handler, that can be addressed directly—provided you write
566
593
  your module in C. What `mod_authnz_fcgi` does is tap the
567
594
  _authentication_ phase of Apache's request-handling loop and open it
568
595
  up to cheap scripts written in any language that speak FastCGI. This
569
- means that stand-alone modules like ForgetPasswords can be used in
596
+ means that stand-alone modules like Forget Passwords can be used in
570
597
  conjunction with *any* downstream Web application framework or
571
598
  development strategy. Some additional observations:
572
599
 
@@ -1,3 +1,3 @@
1
1
  module ForgetPasswords
2
- VERSION = '0.2.9'
2
+ VERSION = '0.2.12'
3
3
  end
@@ -384,7 +384,8 @@ module ForgetPasswords
384
384
  resp.set_header "Variable-#{@vars[:redirect]}", target.to_s if
385
385
  target != uri # (note this should always be true)
386
386
  resp.set_cookie @keys[:cookie], {
387
- value: token, secure: req.ssl?, httponly: true, domain: uri.host,
387
+ value: token, secure: req.ssl?, httponly: true,
388
+ domain: uri.host, path: ?/, same_site: :strict,
388
389
  expires: time_delta(@state.expiry[:cookie]),
389
390
  }
390
391
 
@@ -397,12 +398,12 @@ module ForgetPasswords
397
398
  resp
398
399
  end
399
400
 
400
- def handle_cookie req, token = nil
401
- token ||= req.cookies[@keys[:cookie]]
402
-
401
+ def handle_token req, token, now = Time.now
403
402
  resp = Rack::Response.new
404
403
 
405
- vars = { LOGIN: @targets[:login], FORWARD: req_uri(req).to_s }
404
+ uri = req_uri req
405
+
406
+ vars = { LOGIN: @targets[:login], FORWARD: uri.to_s }
406
407
 
407
408
  # check if token is well-formed
408
409
  raise_error(409, :cookie_bad, req, vars: vars) unless token_ok? token
@@ -416,20 +417,13 @@ module ForgetPasswords
416
417
  user = @state.user_for(token, record: true, cookie: true)
417
418
 
418
419
  raise_error(403, :email_not_listed, req, vars: vars) unless
419
- @state.acl.listed? req_uri(req), user.email
420
+ @state.acl.listed? uri, user.email
420
421
 
421
- now = Time.now
422
422
  @state.freshen_token token, from: now
423
423
 
424
424
  # stamp the token
425
425
  @state.stamp_token token, req.ip, seen: now
426
426
 
427
- # update the cookie expiration
428
- resp.set_cookie @keys[:cookie], {
429
- value: token, secure: req.ssl?, httponly: true,
430
- expires: time_delta(@state.expiry[:cookie], now),
431
- }
432
-
433
427
  # just set the variable
434
428
  resp.set_header "Variable-#{@vars[:user]}", user.principal.to_s
435
429
 
@@ -439,6 +433,23 @@ module ForgetPasswords
439
433
  resp
440
434
  end
441
435
 
436
+ def handle_cookie req, token = nil
437
+ token ||= req.cookies[@keys[:cookie]]
438
+
439
+ now = Time.now
440
+ resp = handle_token req, token, now
441
+ uri = req_uri req
442
+
443
+ # update the cookie expiration
444
+ resp.set_cookie @keys[:cookie], {
445
+ value: token, secure: req.ssl?, httponly: true,
446
+ domain: uri.host, path: ?/, same_site: :strict,
447
+ expires: time_delta(@state.expiry[:cookie], now),
448
+ }
449
+
450
+ resp
451
+ end
452
+
442
453
  def handle_login req
443
454
  uri = req_uri req
444
455
  resp = Rack::Response.new
@@ -519,23 +530,21 @@ module ForgetPasswords
519
530
  resp
520
531
  end
521
532
 
522
- # def handle_post req
523
- # return Rack::Response[403, { 'Content-Type' => 'text/plain' }, 'wat lol']
524
-
525
- # if logout = req.POST[@keys[:logout]]
526
- # handle_logout req, logout
527
- # elsif email = req.POST[@keys[:email]]
528
- # handle_login req, email
529
- # elsif token = req.cookies[@keys[:cookie]]
530
- # # next check for a cookie
531
- # handle_cookie req, token
532
- # else
533
- # default_401 req
534
- # end
535
- # end
536
-
537
533
  def handle_auth req
538
- if knock = req.GET[@keys[:query]]
534
+ if auth = req.get_header('Authorization')
535
+ token = if req.basic?
536
+ # auto-decodes (XXX do we care about the username??)
537
+ req.credentials.last
538
+ elsif auth.strip.downcase.start_with? 'bearer'
539
+ auth.strip.split[1]
540
+ end
541
+ if token
542
+ handle_token req, token
543
+ else
544
+ # XXX one day maybe this can be more descriptive??
545
+ default_401 req
546
+ end
547
+ elsif knock = req.GET[@keys[:query]]
539
548
  # check for a knock first; this overrides everything
540
549
  handle_knock req, knock
541
550
  # elsif req.post?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forget-passwords
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Taylor
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-24 00:00:00.000000000 Z
11
+ date: 2022-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -305,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
307
  requirements: []
308
- rubygems_version: 3.3.7
308
+ rubygems_version: 3.3.11
309
309
  signing_key:
310
310
  specification_version: 4
311
311
  summary: Web authentication module for the extremely lazy