gridauth 0.1.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.
@@ -0,0 +1,48 @@
1
+ module Gridauth
2
+ # Adds the `has_grid_card` macro to Active Record models.
3
+ #
4
+ # class User < ApplicationRecord
5
+ # has_secure_password
6
+ # has_many :sessions, dependent: :destroy
7
+ # has_grid_card
8
+ # end
9
+ module Model
10
+ def has_grid_card
11
+ has_many :grid_cards, class_name: "Gridauth::GridCard", foreign_key: :user_id,
12
+ inverse_of: :user, dependent: :delete_all
13
+
14
+ include InstanceMethods
15
+ end
16
+
17
+ module InstanceMethods
18
+ # The card currently used to sign in, if any.
19
+ def grid_card
20
+ grid_cards.active.order(activated_at: :desc).first
21
+ end
22
+
23
+ # A card that has been issued but not yet confirmed by the user.
24
+ def pending_grid_card
25
+ grid_cards.pending.order(created_at: :desc).first
26
+ end
27
+
28
+ def grid_card_enabled?
29
+ grid_cards.active.exists?
30
+ end
31
+
32
+ # Issues a new pending card (replacing any other pending card) and
33
+ # returns `[card, grid]`, where `grid` is the only copy of the plaintext.
34
+ # The current card, if any, keeps working until the new one is activated.
35
+ def issue_grid_card!
36
+ Gridauth::GridCard.issue_for!(self)
37
+ end
38
+
39
+ # Revokes every card, e.g. when an administrator resets a lost card.
40
+ def revoke_grid_cards!
41
+ transaction do
42
+ grid_cards.pending.delete_all
43
+ grid_cards.active.find_each(&:revoke!)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ module Gridauth
2
+ # Draws the grid card routes into the application's route set, so the
3
+ # engine's pages render inside the app's layout with all of its route
4
+ # helpers available.
5
+ #
6
+ # Rails.application.routes.draw do
7
+ # resource :session
8
+ # gridauth_routes
9
+ # end
10
+ #
11
+ # Route helpers: new_gridauth_challenge_path, gridauth_challenge_path,
12
+ # gridauth_grid_card_path, print_gridauth_grid_card_path,
13
+ # activate_gridauth_grid_card_path and discard_gridauth_grid_card_path.
14
+ module Routing
15
+ def gridauth_routes(path: "gridauth")
16
+ scope path, module: "gridauth", as: "gridauth" do
17
+ resource :challenge, only: %i[ new create destroy ]
18
+
19
+ resource :grid_card, path: "card", only: %i[ show create destroy ] do
20
+ get :print
21
+ post :activate
22
+ delete :discard
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ ActionDispatch::Routing::Mapper.include Gridauth::Routing
@@ -0,0 +1,3 @@
1
+ module Gridauth
2
+ VERSION = "0.1.0"
3
+ end
data/lib/gridauth.rb ADDED
@@ -0,0 +1,41 @@
1
+ require "gridauth/version"
2
+ require "gridauth/configuration"
3
+ require "gridauth/grid"
4
+ require "gridauth/model"
5
+ require "gridauth/routing"
6
+ require "gridauth/authentication"
7
+ require "gridauth/engine"
8
+
9
+ # Grid card two-factor authentication for applications using the Rails 8
10
+ # authentication generator.
11
+ module Gridauth
12
+ # Rails session key holding a login that passed the password check but has
13
+ # not yet answered the grid card challenge.
14
+ PENDING_LOGIN_KEY = :gridauth_pending_login
15
+
16
+ # Rails session key holding the plaintext of a freshly issued card so it can
17
+ # be displayed and printed until the user activates it.
18
+ NEW_CARD_KEY = :gridauth_new_card
19
+
20
+ class << self
21
+ def table_name_prefix
22
+ "gridauth_"
23
+ end
24
+
25
+ def config
26
+ @config ||= Configuration.new
27
+ end
28
+
29
+ def configure
30
+ yield config
31
+ end
32
+
33
+ def reset_config!
34
+ @config = Configuration.new
35
+ end
36
+
37
+ def user_class
38
+ config.user_class.to_s.constantize
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ namespace :gridauth do
2
+ desc "Revoke all grid cards for a user (e.g. a lost card): bin/rails \"gridauth:revoke[user@example.com]\""
3
+ task :revoke, [ :user ] => :environment do |_task, args|
4
+ abort "Usage: bin/rails \"gridauth:revoke[<user id or #{Gridauth.config.user_label_attribute}>]\"" if args[:user].blank?
5
+
6
+ users = Gridauth.user_class
7
+ user = users.find_by(id: args[:user]) || users.find_by(Gridauth.config.user_label_attribute => args[:user])
8
+ abort "No user found for #{args[:user].inspect}" unless user
9
+
10
+ user.revoke_grid_cards!
11
+ puts "Revoked grid cards for #{args[:user]}. They can sign in with their password and set up a new card."
12
+ end
13
+
14
+ desc "List active grid cards that are due for rotation"
15
+ task due: :environment do
16
+ Gridauth::GridCard.active.includes(:user).find_each do |card|
17
+ puts "#{card.serial}\tuser #{card.user_id}\tactivated #{card.activated_at.to_date}\tuses #{card.use_count}" if card.rotation_due?
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gridauth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - jcallahan
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '8.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
26
+ description: 'Adds a grid card (a printed table of random characters) as a second
27
+ factor to Rails 8+ apps using `bin/rails generate authentication`: per-user cards,
28
+ card rotation, and a challenge step after the password sign-in.'
29
+ email:
30
+ - jcallahan@acm.org
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - CHANGELOG.md
36
+ - MIT-LICENSE
37
+ - README.md
38
+ - Rakefile
39
+ - app/controllers/gridauth/application_controller.rb
40
+ - app/controllers/gridauth/challenges_controller.rb
41
+ - app/controllers/gridauth/grid_cards_controller.rb
42
+ - app/helpers/gridauth/grid_helper.rb
43
+ - app/models/gridauth/application_record.rb
44
+ - app/models/gridauth/grid_card.rb
45
+ - app/views/gridauth/challenges/new.html.erb
46
+ - app/views/gridauth/grid_cards/print.html.erb
47
+ - app/views/gridauth/grid_cards/show.html.erb
48
+ - app/views/gridauth/shared/_challenge_fields.html.erb
49
+ - app/views/gridauth/shared/_grid.html.erb
50
+ - app/views/gridauth/shared/_styles.html.erb
51
+ - config/locales/en.yml
52
+ - lib/generators/gridauth/install/install_generator.rb
53
+ - lib/generators/gridauth/install/templates/create_gridauth_grid_cards.rb.tt
54
+ - lib/generators/gridauth/install/templates/initializer.rb.tt
55
+ - lib/generators/gridauth/views/views_generator.rb
56
+ - lib/gridauth.rb
57
+ - lib/gridauth/authentication.rb
58
+ - lib/gridauth/configuration.rb
59
+ - lib/gridauth/engine.rb
60
+ - lib/gridauth/grid.rb
61
+ - lib/gridauth/model.rb
62
+ - lib/gridauth/routing.rb
63
+ - lib/gridauth/version.rb
64
+ - lib/tasks/gridauth_tasks.rake
65
+ homepage: https://github.com/johncallahan/gridauth
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '3.2'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 3.6.9
84
+ specification_version: 4
85
+ summary: Grid card two-factor authentication for Rails 8 built-in authentication.
86
+ test_files: []