linked_rails-auth 0.0.1
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/LICENSE +674 -0
- data/README.md +28 -0
- data/Rakefile +34 -0
- data/app/actions/linked_rails/auth/access_token_action_list.rb +16 -0
- data/app/actions/linked_rails/auth/confirmation_action_list.rb +17 -0
- data/app/actions/linked_rails/auth/otp_attempt_action_list.rb +13 -0
- data/app/actions/linked_rails/auth/otp_secret_action_list.rb +31 -0
- data/app/actions/linked_rails/auth/password_action_list.rb +25 -0
- data/app/actions/linked_rails/auth/registration_action_list.rb +15 -0
- data/app/actions/linked_rails/auth/session_action_list.rb +22 -0
- data/app/actions/linked_rails/auth/unlock_action_list.rb +17 -0
- data/app/controllers/linked_rails/auth/access_tokens_controller.rb +131 -0
- data/app/controllers/linked_rails/auth/confirmations_controller.rb +87 -0
- data/app/controllers/linked_rails/auth/otp_attempts_controller.rb +21 -0
- data/app/controllers/linked_rails/auth/otp_secrets_controller.rb +40 -0
- data/app/controllers/linked_rails/auth/passwords_controller.rb +63 -0
- data/app/controllers/linked_rails/auth/registrations_controller.rb +33 -0
- data/app/controllers/linked_rails/auth/sessions_controller.rb +55 -0
- data/app/controllers/linked_rails/auth/unlocks_controller.rb +44 -0
- data/app/forms/linked_rails/auth/access_token_form.rb +20 -0
- data/app/forms/linked_rails/auth/confirmation_form.rb +9 -0
- data/app/forms/linked_rails/auth/otp_attempt_form.rb +9 -0
- data/app/forms/linked_rails/auth/otp_secret_form.rb +12 -0
- data/app/forms/linked_rails/auth/password_form.rb +21 -0
- data/app/forms/linked_rails/auth/registration_form.rb +21 -0
- data/app/forms/linked_rails/auth/session_form.rb +13 -0
- data/app/forms/linked_rails/auth/unlock_form.rb +9 -0
- data/app/helpers/linked_rails/auth/otp_helper.rb +30 -0
- data/app/models/linked_rails/auth/access_token.rb +40 -0
- data/app/models/linked_rails/auth/confirmation.rb +70 -0
- data/app/models/linked_rails/auth/guest_user.rb +29 -0
- data/app/models/linked_rails/auth/otp_attempt.rb +41 -0
- data/app/models/linked_rails/auth/otp_base.rb +57 -0
- data/app/models/linked_rails/auth/otp_secret.rb +91 -0
- data/app/models/linked_rails/auth/password.rb +47 -0
- data/app/models/linked_rails/auth/registration.rb +39 -0
- data/app/models/linked_rails/auth/session.rb +46 -0
- data/app/models/linked_rails/auth/unlock.rb +59 -0
- data/app/policies/linked_rails/auth/access_token_policy.rb +17 -0
- data/app/policies/linked_rails/auth/confirmation_policy.rb +17 -0
- data/app/policies/linked_rails/auth/otp_attempt_policy.rb +17 -0
- data/app/policies/linked_rails/auth/otp_secret_policy.rb +37 -0
- data/app/policies/linked_rails/auth/password_policy.rb +23 -0
- data/app/policies/linked_rails/auth/registration_policy.rb +13 -0
- data/app/policies/linked_rails/auth/session_policy.rb +17 -0
- data/app/policies/linked_rails/auth/unlock_policy.rb +21 -0
- data/app/serializers/linked_rails/auth/access_token_serializer.rb +11 -0
- data/app/serializers/linked_rails/auth/confirmation_serializer.rb +10 -0
- data/app/serializers/linked_rails/auth/otp_attempt_serializer.rb +12 -0
- data/app/serializers/linked_rails/auth/otp_secret_serializer.rb +14 -0
- data/app/serializers/linked_rails/auth/password_serializer.rb +18 -0
- data/app/serializers/linked_rails/auth/registration_serializer.rb +12 -0
- data/app/serializers/linked_rails/auth/session_serializer.rb +10 -0
- data/app/serializers/linked_rails/auth/unlock_serializer.rb +9 -0
- data/config/routes.rb +4 -0
- data/lib/generators/linked_rails/auth/install_generator.rb +155 -0
- data/lib/generators/linked_rails/auth/templates/README +2 -0
- data/lib/generators/linked_rails/auth/templates/doorkeeper_jwt_initializer.rb +52 -0
- data/lib/generators/linked_rails/auth/templates/locales.yml +39 -0
- data/lib/generators/linked_rails/auth/templates/migration.rb.erb +20 -0
- data/lib/linked_rails/auth/auth_helper.rb +101 -0
- data/lib/linked_rails/auth/controller/error_handling.rb +17 -0
- data/lib/linked_rails/auth/controller.rb +16 -0
- data/lib/linked_rails/auth/engine.rb +8 -0
- data/lib/linked_rails/auth/errors/account_locked.rb +10 -0
- data/lib/linked_rails/auth/errors/expired.rb +10 -0
- data/lib/linked_rails/auth/errors/unauthorized.rb +10 -0
- data/lib/linked_rails/auth/errors/unknown_email.rb +14 -0
- data/lib/linked_rails/auth/errors/wrong_password.rb +14 -0
- data/lib/linked_rails/auth/errors.rb +7 -0
- data/lib/linked_rails/auth/routes.rb +86 -0
- data/lib/linked_rails/auth/version.rb +7 -0
- data/lib/linked_rails/auth.rb +46 -0
- data/lib/tasks/linked_rails/auth_tasks.rake +6 -0
- metadata +257 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class OtpAttemptsController < LinkedRails.controller_parent_class
|
6
|
+
private
|
7
|
+
|
8
|
+
def create_success
|
9
|
+
sign_in(current_resource.owner, otp_verified: true)
|
10
|
+
|
11
|
+
head 200
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def controller_class
|
16
|
+
LinkedRails.otp_attempt_class
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class OtpSecretsController < LinkedRails.controller_parent_class
|
6
|
+
active_response :show
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def create_success
|
11
|
+
active_response_block do
|
12
|
+
sign_in(current_resource.owner, otp_verified: true) if current_user.guest?
|
13
|
+
|
14
|
+
respond_with_redirect(
|
15
|
+
location: current_resource.redirect_url,
|
16
|
+
reload: true
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy_success
|
22
|
+
active_response_block do
|
23
|
+
respond_with_redirect(location: LinkedRails.iri.to_s, reload: true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def permit_params
|
28
|
+
return super unless action_name == 'create'
|
29
|
+
|
30
|
+
super.merge(active: true)
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def controller_class
|
35
|
+
LinkedRails.otp_secret_class
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class PasswordsController < Devise::PasswordsController
|
6
|
+
skip_before_action :require_no_authentication, only: :create
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def after_sending_reset_password_instructions_path_for(_resource_name)
|
11
|
+
LinkedRails.iri(path: '/u/session/new').path
|
12
|
+
end
|
13
|
+
|
14
|
+
def after_resetting_password_path_for(_resource)
|
15
|
+
LinkedRails.iri(path: '/u/session/new').path
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_execute
|
19
|
+
@current_resource = resource_class.send_reset_password_instructions(resource_params)
|
20
|
+
successfully_sent?(current_resource)
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_failure_message; end
|
24
|
+
|
25
|
+
def create_success_location
|
26
|
+
after_sending_reset_password_instructions_path_for(resource_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_success_message
|
30
|
+
find_message(:send_instructions)
|
31
|
+
end
|
32
|
+
|
33
|
+
def new_session_path(*_args)
|
34
|
+
LinkedRails.iri(path: 'u/session/new').path
|
35
|
+
end
|
36
|
+
|
37
|
+
def resource_params
|
38
|
+
params.fetch(resource_name, nil) ||
|
39
|
+
params.fetch(controller_name.singularize, {})
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_execute
|
43
|
+
@current_resource = resource_class.reset_password_by_token(resource_params)
|
44
|
+
|
45
|
+
current_resource.errors.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_success_message
|
49
|
+
find_message(:updated_not_active)
|
50
|
+
end
|
51
|
+
|
52
|
+
def update_success_location
|
53
|
+
after_resetting_password_path_for(current_resource)
|
54
|
+
end
|
55
|
+
|
56
|
+
class << self
|
57
|
+
def controller_class
|
58
|
+
LinkedRails.password_class
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class RegistrationsController < Devise::RegistrationsController
|
6
|
+
skip_before_action :assert_is_devise_resource!, only: :show
|
7
|
+
active_response :show
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def active_response_success_message; end
|
12
|
+
|
13
|
+
def create_success
|
14
|
+
sign_in(current_resource)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_success_location
|
19
|
+
current_resource.redirect_url
|
20
|
+
end
|
21
|
+
|
22
|
+
def resource_params
|
23
|
+
params.require(permit_param_key)
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def controller_class
|
28
|
+
LinkedRails.registration_class
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class SessionsController < ApplicationController
|
6
|
+
active_response :create
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def active_response_success_message; end
|
11
|
+
|
12
|
+
def active_response_failure_message; end
|
13
|
+
|
14
|
+
def create_execute
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_success_location
|
19
|
+
if requested_user
|
20
|
+
LinkedRails.iri(path: 'u/access_token/new').to_s
|
21
|
+
else
|
22
|
+
LinkedRails.iri(path: 'u/registration/new').to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def requested_user
|
27
|
+
@requested_user ||= LinkedRails.user_class.find_for_database_authentication(email: permit_params[:email])
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy_execute
|
31
|
+
sign_out
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroy_success
|
35
|
+
respond_with_redirect(
|
36
|
+
location: '/'
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def permit_params
|
41
|
+
params.require(:session).permit(:redirect_url, :email)
|
42
|
+
end
|
43
|
+
|
44
|
+
def r_param
|
45
|
+
new_resource_params[:redirect_url] || (params.key?(:session) ? permit_params[:redirect_url] : nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
def controller_class
|
50
|
+
LinkedRails.session_class
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class UnlocksController < Devise::UnlocksController
|
6
|
+
private
|
7
|
+
|
8
|
+
def after_sending_unlock_instructions_path_for(_resource)
|
9
|
+
LinkedRails.iri(path: '/u/session/new').path
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_unlock_path_for(_resource)
|
13
|
+
LinkedRails.iri(path: '/u/session/new').path
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_execute
|
17
|
+
@current_resource = resource_class.send_unlock_instructions(resource_params)
|
18
|
+
|
19
|
+
successfully_sent?(current_resource!)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_failure_message; end
|
23
|
+
|
24
|
+
def create_success_location
|
25
|
+
after_sending_unlock_instructions_path_for(current_resource)
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_success_message
|
29
|
+
find_message(:send_instructions)
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource_params
|
33
|
+
params.fetch(resource_name, nil) ||
|
34
|
+
params.fetch(controller_name.singularize, {})
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
def controller_class
|
39
|
+
LinkedRails.unlock_class
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class AccessTokenForm < LinkedRails.form_parent_class
|
6
|
+
field :email,
|
7
|
+
input_field: LinkedRails::Form::Field::EmailInput,
|
8
|
+
min_count: 1
|
9
|
+
field :password,
|
10
|
+
description: '',
|
11
|
+
input_field: LinkedRails::Form::Field::PasswordInput,
|
12
|
+
min_count: 1
|
13
|
+
resource :reset_password, url: -> { LinkedRails.iri(path: '/u/password/new') }
|
14
|
+
|
15
|
+
hidden do
|
16
|
+
field :redirect_url
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class OtpSecretForm < LinkedRails.form_parent_class
|
6
|
+
resource :provision_image,
|
7
|
+
description: -> { I18n.t('otp_secrets.properties.provision_image.description') },
|
8
|
+
path: Vocab.schema.image
|
9
|
+
field :otp_attempt, description: '', min_count: 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class PasswordForm < LinkedRails.form_parent_class
|
6
|
+
field :email,
|
7
|
+
input_field: LinkedRails::Form::Field::EmailInput,
|
8
|
+
min_count: 1
|
9
|
+
field :password,
|
10
|
+
input_field: LinkedRails::Form::Field::PasswordInput,
|
11
|
+
min_count: 1
|
12
|
+
field :password_confirmation,
|
13
|
+
input_field: LinkedRails::Form::Field::PasswordInput,
|
14
|
+
min_count: 1
|
15
|
+
|
16
|
+
hidden do
|
17
|
+
field :reset_password_token
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class RegistrationForm < LinkedRails.form_parent_class
|
6
|
+
field :email,
|
7
|
+
input_field: LinkedRails::Form::Field::EmailInput,
|
8
|
+
min_count: 1
|
9
|
+
field :password,
|
10
|
+
input_field: LinkedRails::Form::Field::PasswordInput,
|
11
|
+
min_count: 1
|
12
|
+
field :password_confirmation,
|
13
|
+
input_field: LinkedRails::Form::Field::PasswordInput,
|
14
|
+
min_count: 1
|
15
|
+
|
16
|
+
hidden do
|
17
|
+
field :redirect_url
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class SessionForm < LinkedRails.form_parent_class
|
6
|
+
field :email, input_field: LinkedRails::Form::Field::EmailInput, min_count: 1
|
7
|
+
|
8
|
+
hidden do
|
9
|
+
field :redirect_url
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
module OtpHelper
|
6
|
+
def handle_expired_session
|
7
|
+
raise LinkedRails::Auth::Errors::Expired, I18n.t('messages.otp_secrets.expired')
|
8
|
+
end
|
9
|
+
|
10
|
+
def session_from_param(session_param)
|
11
|
+
return {} unless session_param
|
12
|
+
|
13
|
+
JWT.decode(
|
14
|
+
session_param,
|
15
|
+
Doorkeeper::JWT.configuration.secret_key,
|
16
|
+
true,
|
17
|
+
algorithms: [Doorkeeper::JWT.configuration.encryption_method.to_s.upcase]
|
18
|
+
).first || {}
|
19
|
+
rescue JWT::ExpiredSignature
|
20
|
+
handle_expired_session
|
21
|
+
end
|
22
|
+
|
23
|
+
def owner_from_session(session_param)
|
24
|
+
user_id = session_from_param(session_param)['user_id']
|
25
|
+
|
26
|
+
LinkedRails.otp_owner_class.find_by(id: user_id) if user_id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LinkedRails
|
4
|
+
module Auth
|
5
|
+
class AccessToken < LinkedRails::Resource
|
6
|
+
enhance LinkedRails::Enhancements::Actionable
|
7
|
+
enhance LinkedRails::Enhancements::Creatable
|
8
|
+
enhance LinkedRails::Enhancements::Singularable
|
9
|
+
|
10
|
+
attr_accessor :email, :redirect_url, :password
|
11
|
+
alias root_relative_iri root_relative_singular_iri
|
12
|
+
|
13
|
+
def singular_iri_opts
|
14
|
+
{redirect_url: redirect_url}
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def action_list
|
19
|
+
LinkedRails.access_token_action_list_class
|
20
|
+
end
|
21
|
+
|
22
|
+
def form_class
|
23
|
+
LinkedRails.access_token_form_class
|
24
|
+
end
|
25
|
+
|
26
|
+
def singular_iri_template
|
27
|
+
@singular_iri_template ||= URITemplate.new("/#{singular_route_key}{?redirect_url}")
|
28
|
+
end
|
29
|
+
|
30
|
+
def singular_route_key
|
31
|
+
'u/access_token'
|
32
|
+
end
|
33
|
+
|
34
|
+
def requested_singular_resource(params, _user_context)
|
35
|
+
new(redirect_url: params[:redirect_url])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|