foobara-auth 0.0.8 → 0.0.10
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/src/authenticate_with_api_key.rb +59 -0
- data/src/create_reset_password_token.rb +45 -0
- data/src/refresh_login.rb +5 -8
- data/src/register.rb +1 -0
- data/src/reset_password.rb +123 -0
- data/src/types/user.rb +1 -0
- data/src/verify_access_token.rb +4 -2
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45cdb3b28235c09c136eb81a09662517dd017afef86cb5fd11b1c966a264685d
|
4
|
+
data.tar.gz: 65b323560c3469fa6b1c29e20d39f4ecf4c6e42011da3a7244876863f87057ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48db1658d6fa78ae0cfe733c7bb58288519399311007851d03c5253f2ebd44f089027820f788c1bfe7af012372520639a56594471d6f50269e75e75c47c884a7
|
7
|
+
data.tar.gz: c6c486c5f4a408177e6a534169bea9d0a77068d8208ed99f5c4217ca37d6f247ffc00743041ff4306f858c5963592ebf9bbd857b6422412a8618cb4157d29df6
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative "verify_token"
|
2
|
+
|
3
|
+
module Foobara
|
4
|
+
module Auth
|
5
|
+
class AuthenticateWithApiKey < Foobara::Command
|
6
|
+
class InvalidApiKeyError < Foobara::RuntimeError
|
7
|
+
context api_key_id: :string
|
8
|
+
message "Invalid api key"
|
9
|
+
end
|
10
|
+
|
11
|
+
depends_on VerifyToken
|
12
|
+
depends_on_entities Types::Token
|
13
|
+
|
14
|
+
inputs do
|
15
|
+
api_key :string, :required, :sensitive
|
16
|
+
access_token_ttl :integer, default: 30 * 60
|
17
|
+
api_key_ttl :integer, default: 7 * 24 * 60 * 60
|
18
|
+
end
|
19
|
+
|
20
|
+
result [Types::User, Types::Token]
|
21
|
+
|
22
|
+
def execute
|
23
|
+
determine_api_key_id_and_secret
|
24
|
+
load_api_key_record
|
25
|
+
verify_api_key
|
26
|
+
|
27
|
+
load_user
|
28
|
+
|
29
|
+
user_and_credential
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_accessor :expires_at, :api_key_record, :api_key_id, :api_key_secret, :user
|
33
|
+
|
34
|
+
def determine_api_key_id_and_secret
|
35
|
+
self.api_key_id, self.api_key_secret = api_key.split("_")
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_api_key_record
|
39
|
+
self.api_key_record = Types::Token.load(api_key_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_api_key
|
43
|
+
valid = run_subcommand!(VerifyToken, token_string: api_key)
|
44
|
+
|
45
|
+
unless valid[:verified]
|
46
|
+
add_runtime_error(InvalidApiKeyError.new(context: { api_key_id: }))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_user
|
51
|
+
self.user ||= Types::User.that_owns(api_key_record, "api_keys")
|
52
|
+
end
|
53
|
+
|
54
|
+
def user_and_credential
|
55
|
+
[user, api_key_record]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
require_relative "create_token"
|
4
|
+
|
5
|
+
module Foobara
|
6
|
+
module Auth
|
7
|
+
class CreateResetPasswordToken < Foobara::Command
|
8
|
+
depends_on CreateToken
|
9
|
+
|
10
|
+
inputs do
|
11
|
+
user Types::User, :required
|
12
|
+
token_ttl :integer, default: 5 * 60
|
13
|
+
end
|
14
|
+
|
15
|
+
result :string, :sensitive_exposed
|
16
|
+
|
17
|
+
def execute
|
18
|
+
determine_timestamps
|
19
|
+
|
20
|
+
generate_new_reset_password_token
|
21
|
+
save_new_reset_password_token_on_user
|
22
|
+
|
23
|
+
reset_password_token_secret
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :expires_at, :reset_password_token_record, :reset_password_token_secret
|
27
|
+
|
28
|
+
def determine_timestamps
|
29
|
+
now = Time.now
|
30
|
+
self.expires_at = now + token_ttl
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate_new_reset_password_token
|
34
|
+
result = run_subcommand!(CreateToken, expires_at:)
|
35
|
+
|
36
|
+
self.reset_password_token_record = result[:token_record]
|
37
|
+
self.reset_password_token_secret = result[:token_string]
|
38
|
+
end
|
39
|
+
|
40
|
+
def save_new_reset_password_token_on_user
|
41
|
+
user.reset_password_token = reset_password_token_record
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/src/refresh_login.rb
CHANGED
@@ -6,11 +6,6 @@ module Foobara
|
|
6
6
|
message "Invalid refresh token"
|
7
7
|
end
|
8
8
|
|
9
|
-
class RefreshTokenNotOwnedByUser < Foobara::RuntimeError
|
10
|
-
context refresh_token_id: :string
|
11
|
-
message "This refresh token is not owned by this user"
|
12
|
-
end
|
13
|
-
|
14
9
|
depends_on CreateRefreshToken, VerifyToken, BuildAccessToken
|
15
10
|
depends_on_entities Types::Token
|
16
11
|
|
@@ -32,6 +27,8 @@ module Foobara
|
|
32
27
|
# Delete it instead maybe?
|
33
28
|
mark_refresh_token_as_used
|
34
29
|
|
30
|
+
load_user
|
31
|
+
|
35
32
|
generate_access_token
|
36
33
|
generate_new_refresh_token
|
37
34
|
|
@@ -39,7 +36,7 @@ module Foobara
|
|
39
36
|
end
|
40
37
|
|
41
38
|
attr_accessor :access_token, :new_refresh_token, :expires_at, :refresh_token_record,
|
42
|
-
:refresh_token_id, :refresh_token_secret
|
39
|
+
:refresh_token_id, :refresh_token_secret, :user
|
43
40
|
|
44
41
|
def determine_refresh_token_id_and_secret
|
45
42
|
self.refresh_token_id, self.refresh_token_secret = refresh_token.split("_")
|
@@ -65,8 +62,8 @@ module Foobara
|
|
65
62
|
self.access_token = run_subcommand!(BuildAccessToken, user:, token_ttl: access_token_ttl)
|
66
63
|
end
|
67
64
|
|
68
|
-
def
|
69
|
-
|
65
|
+
def load_user
|
66
|
+
self.user ||= Types::User.that_owns(refresh_token_record, "refresh_tokens")
|
70
67
|
end
|
71
68
|
|
72
69
|
def generate_new_refresh_token
|
data/src/register.rb
CHANGED
@@ -0,0 +1,123 @@
|
|
1
|
+
module Foobara
|
2
|
+
module Auth
|
3
|
+
class ResetPassword < Foobara::Command
|
4
|
+
class NoPasswordResetTokenOrOldPasswordGivenError < Foobara::RuntimeError
|
5
|
+
context({})
|
6
|
+
message "Must give either a password reset token or an old password"
|
7
|
+
end
|
8
|
+
|
9
|
+
class BothPasswordResetTokenAndOldPasswordGivenError < Foobara::RuntimeError
|
10
|
+
context({})
|
11
|
+
message "Cannot give both a password reset token and an old password"
|
12
|
+
end
|
13
|
+
|
14
|
+
class IncorrectOldPasswordError < Foobara::RuntimeError
|
15
|
+
context({})
|
16
|
+
message "Incorrect old password"
|
17
|
+
end
|
18
|
+
|
19
|
+
class InvalidResetPasswordTokenError < Foobara::RuntimeError
|
20
|
+
context({}) # TODO: make this the default
|
21
|
+
message "Invalid password reset token"
|
22
|
+
end
|
23
|
+
|
24
|
+
class UserNotGivenError < Foobara::RuntimeError
|
25
|
+
context({})
|
26
|
+
message "Must give a user if giving an old password to reset password"
|
27
|
+
end
|
28
|
+
|
29
|
+
class UserNotFoundForResetTokenError < Foobara::RuntimeError
|
30
|
+
context({}) # TODO: make this the default?
|
31
|
+
message "No user found for reset password token"
|
32
|
+
end
|
33
|
+
|
34
|
+
inputs do
|
35
|
+
user Types::User
|
36
|
+
old_password :string, :sensitive_exposed
|
37
|
+
reset_password_token_secret :string, :sensitive_exposed
|
38
|
+
new_password :string, :sensitive, :required
|
39
|
+
end
|
40
|
+
result Types::User
|
41
|
+
|
42
|
+
depends_on BuildSecret, VerifyPassword, VerifyToken
|
43
|
+
|
44
|
+
# TODO: should we enforce certain password requirements?
|
45
|
+
def execute
|
46
|
+
if old_password_given?
|
47
|
+
verify_old_password
|
48
|
+
else
|
49
|
+
verify_and_use_up_password_reset_token
|
50
|
+
load_user
|
51
|
+
end
|
52
|
+
|
53
|
+
build_new_password
|
54
|
+
set_password_on_user
|
55
|
+
|
56
|
+
user
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate
|
60
|
+
if old_password_given?
|
61
|
+
unless user
|
62
|
+
add_runtime_error(UserNotGivenError)
|
63
|
+
end
|
64
|
+
if reset_password_token_given?
|
65
|
+
add_runtime_error(BothPasswordResetTokenAndOldPasswordGivenError)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
unless reset_password_token_given?
|
69
|
+
add_runtime_error(NoPasswordResetTokenOrOldPasswordGivenError)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_accessor :password_secret, :reset_password_token_record
|
75
|
+
attr_writer :user
|
76
|
+
|
77
|
+
def old_password_given?
|
78
|
+
!!old_password
|
79
|
+
end
|
80
|
+
|
81
|
+
def reset_password_token_given?
|
82
|
+
!!reset_password_token_secret
|
83
|
+
end
|
84
|
+
|
85
|
+
def verify_old_password
|
86
|
+
unless run_subcommand!(VerifyPassword, user:, plaintext_password: old_password)
|
87
|
+
add_runtime_error(IncorrectOldPasswordError)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def verify_and_use_up_password_reset_token
|
92
|
+
verified_result = run_subcommand!(VerifyToken, token_string: reset_password_token_secret)
|
93
|
+
|
94
|
+
unless verified_result[:verified]
|
95
|
+
add_runtime_error(InvalidResetPasswordTokenError)
|
96
|
+
end
|
97
|
+
|
98
|
+
self.reset_password_token_record = verified_result[:token_record]
|
99
|
+
reset_password_token_record.use_up!
|
100
|
+
end
|
101
|
+
|
102
|
+
def load_user
|
103
|
+
self.user = Types::User.that_owns(reset_password_token_record, "reset")
|
104
|
+
|
105
|
+
unless user
|
106
|
+
add_runtime_error(UserNotFoundForResetTokenError)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def user
|
111
|
+
@user || inputs[:user]
|
112
|
+
end
|
113
|
+
|
114
|
+
def build_new_password
|
115
|
+
self.password_secret = run_subcommand!(BuildSecret, secret: new_password)
|
116
|
+
end
|
117
|
+
|
118
|
+
def set_password_on_user
|
119
|
+
user.password_secret = password_secret
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/src/types/user.rb
CHANGED
@@ -13,6 +13,7 @@ module Foobara
|
|
13
13
|
api_keys [Types::Token], :sensitive, default: []
|
14
14
|
refresh_tokens [Types::Token], :sensitive, default: []
|
15
15
|
password_secret Types::Secret, :sensitive, :allow_nil
|
16
|
+
reset_password_token Types::Token, :sensitive, :allow_nil
|
16
17
|
end
|
17
18
|
|
18
19
|
primary_key :id
|
data/src/verify_access_token.rb
CHANGED
@@ -10,7 +10,7 @@ module Foobara
|
|
10
10
|
|
11
11
|
result do
|
12
12
|
verified :boolean, :required
|
13
|
-
failure_reason :string, :allow_nil, one_of: %w[invalid expired]
|
13
|
+
failure_reason :string, :allow_nil, one_of: %w[invalid expired cannot_verify]
|
14
14
|
payload :associative_array, :allow_nil
|
15
15
|
headers :associative_array, :allow_nil
|
16
16
|
end
|
@@ -27,9 +27,11 @@ module Foobara
|
|
27
27
|
def decode_access_token
|
28
28
|
self.payload, self.headers = JWT.decode(access_token, jwt_secret)
|
29
29
|
rescue JWT::VerificationError
|
30
|
-
self.failure_reason = "
|
30
|
+
self.failure_reason = "cannot_verify"
|
31
31
|
rescue JWT::ExpiredSignature
|
32
32
|
self.failure_reason = "expired"
|
33
|
+
rescue JWT::DecodeError
|
34
|
+
self.failure_reason = "invalid"
|
33
35
|
end
|
34
36
|
|
35
37
|
def set_verified_flag
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara-auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 2025-05-01 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: argon2
|
@@ -64,10 +64,12 @@ files:
|
|
64
64
|
- README.md
|
65
65
|
- lib/foobara/auth.rb
|
66
66
|
- src/approve_token.rb
|
67
|
+
- src/authenticate_with_api_key.rb
|
67
68
|
- src/build_access_token.rb
|
68
69
|
- src/build_secret.rb
|
69
70
|
- src/create_api_key.rb
|
70
71
|
- src/create_refresh_token.rb
|
72
|
+
- src/create_reset_password_token.rb
|
71
73
|
- src/create_role.rb
|
72
74
|
- src/create_token.rb
|
73
75
|
- src/create_user.rb
|
@@ -76,6 +78,7 @@ files:
|
|
76
78
|
- src/logout.rb
|
77
79
|
- src/refresh_login.rb
|
78
80
|
- src/register.rb
|
81
|
+
- src/reset_password.rb
|
79
82
|
- src/set_password.rb
|
80
83
|
- src/types/role.rb
|
81
84
|
- src/types/secret.rb
|
@@ -109,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
112
|
- !ruby/object:Gem::Version
|
110
113
|
version: '0'
|
111
114
|
requirements: []
|
112
|
-
rubygems_version: 3.6.
|
115
|
+
rubygems_version: 3.6.2
|
113
116
|
specification_version: 4
|
114
117
|
summary: Provides various auth domain commands and models
|
115
118
|
test_files: []
|