aven 0.0.1 → 0.0.2
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/Rakefile +1 -1
- data/app/components/aven/views/oauth/error/component.html.erb +44 -0
- data/app/components/aven/views/oauth/error/component.rb +30 -0
- data/app/components/aven/views/static/index/component.html.erb +4 -4
- data/app/components/aven/views/static/index/component.rb +11 -0
- data/app/controllers/aven/admin/base.rb +4 -4
- data/app/controllers/aven/application_controller.rb +22 -0
- data/app/controllers/aven/auth_controller.rb +6 -58
- data/app/controllers/aven/oauth/auth0_controller.rb +84 -0
- data/app/controllers/aven/oauth/base_controller.rb +183 -0
- data/app/controllers/aven/oauth/documentation/auth0.md +387 -0
- data/app/controllers/aven/oauth/documentation/entra_id.md +608 -0
- data/app/controllers/aven/oauth/documentation/github.md +329 -0
- data/app/controllers/aven/oauth/documentation/google.md +253 -0
- data/app/controllers/aven/oauth/entra_id_controller.rb +92 -0
- data/app/controllers/aven/oauth/github_controller.rb +91 -0
- data/app/controllers/aven/oauth/google_controller.rb +64 -0
- data/app/controllers/aven/workspaces_controller.rb +20 -0
- data/app/controllers/concerns/aven/authentication.rb +49 -0
- data/app/controllers/concerns/aven/controller_helpers.rb +38 -0
- data/app/helpers/aven/application_helper.rb +2 -6
- data/app/models/aven/app_record.rb +1 -1
- data/app/models/aven/app_record_schema.rb +0 -1
- data/app/models/aven/log.rb +0 -1
- data/app/models/aven/loggable.rb +2 -3
- data/app/models/aven/user.rb +0 -23
- data/app/models/aven/workspace.rb +49 -5
- data/app/models/aven/workspace_role.rb +0 -1
- data/app/models/aven/workspace_user.rb +0 -1
- data/app/models/aven/workspace_user_role.rb +0 -1
- data/config/routes.rb +22 -7
- data/db/migrate/{20251003090752_create_aven_users.rb → 20200101000001_create_aven_users.rb} +1 -1
- data/db/migrate/{20251004182010_create_aven_workspace_users.rb → 20200101000003_create_aven_workspace_users.rb} +1 -1
- data/db/migrate/{20251004182020_create_aven_workspace_roles.rb → 20200101000004_create_aven_workspace_roles.rb} +1 -1
- data/db/migrate/{20251004182030_create_aven_workspace_user_roles.rb → 20200101000005_create_aven_workspace_user_roles.rb} +1 -1
- data/db/migrate/{20251004190000_create_aven_logs.rb → 20200101000006_create_aven_logs.rb} +2 -3
- data/db/migrate/{20251004190100_create_aven_app_record_schemas.rb → 20200101000007_create_aven_app_record_schemas.rb} +0 -1
- data/db/migrate/{20251004190110_create_aven_app_records.rb → 20200101000008_create_aven_app_records.rb} +0 -1
- data/lib/aven/configuration.rb +26 -10
- data/lib/aven/engine.rb +15 -16
- data/lib/aven/model/tenant_model.rb +91 -0
- data/lib/aven/model.rb +6 -0
- data/lib/aven/version.rb +1 -1
- metadata +42 -69
- data/config/initializers/devise.rb +0 -43
- /data/db/migrate/{20251004182000_create_aven_workspaces.rb → 20200101000002_create_aven_workspaces.rb} +0 -0
- /data/lib/tasks/{sqema_tasks.rake → aven_tasks.rake} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a02e3ced6d96476bc2d2237a080cd459c7787295f0838558613b8c56c65417d2
|
|
4
|
+
data.tar.gz: da6fef70eddb6b4b3c9b22d9ef9dedc3553457a6745e4e8839f45352f5685c47
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1024472cdaf1a181500949d2a40ac7d997299411f53f9614826f501c43e383a0a1f288c03bf74e508180074eaec9b89a9a451409900fb24e972033f6496799cf
|
|
7
|
+
data.tar.gz: c94494371d0a5f62d3a81bcfc8c0b31026189e7d2df8a04675dacebd3724def86e137172691ef1c905b313f14d2e3f5556edc428e7a1b4f794824f338eeedb96
|
data/Rakefile
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<div class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
|
2
|
+
<div class="max-w-md w-full space-y-8">
|
|
3
|
+
<div>
|
|
4
|
+
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
|
5
|
+
Authentication Failed
|
|
6
|
+
</h2>
|
|
7
|
+
<div class="mt-4 bg-red-50 border border-red-200 rounded-md p-4">
|
|
8
|
+
<div class="flex">
|
|
9
|
+
<div class="flex-shrink-0">
|
|
10
|
+
<svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
|
11
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
|
12
|
+
</svg>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="ml-3">
|
|
15
|
+
<h3 class="text-sm font-medium text-red-800">
|
|
16
|
+
<%= error_message %>
|
|
17
|
+
</h3>
|
|
18
|
+
<% if error_class.present? %>
|
|
19
|
+
<p class="mt-2 text-xs text-red-700">
|
|
20
|
+
Error type: <%= error_class %>
|
|
21
|
+
</p>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="space-y-4">
|
|
29
|
+
<% provider_links.each do |provider| %>
|
|
30
|
+
<%= link_to(
|
|
31
|
+
"Try again with #{provider.to_s.capitalize}",
|
|
32
|
+
oauth_path_for(provider),
|
|
33
|
+
class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
34
|
+
) %>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<%= link_to(
|
|
38
|
+
"Back to home",
|
|
39
|
+
home_path,
|
|
40
|
+
class: "group relative w-full flex justify-center py-2 px-4 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
41
|
+
) %>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Aven::Views::Oauth::Error
|
|
2
|
+
class Component < Aven::ApplicationViewComponent
|
|
3
|
+
option :error_message
|
|
4
|
+
option :error_class, optional: true
|
|
5
|
+
option :current_user, optional: true
|
|
6
|
+
|
|
7
|
+
def provider_links
|
|
8
|
+
Aven.configuration.oauth_providers.keys
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def oauth_path_for(provider)
|
|
12
|
+
case provider.to_sym
|
|
13
|
+
when :github
|
|
14
|
+
Aven::Engine.routes.url_helpers.oauth_github_path
|
|
15
|
+
when :google
|
|
16
|
+
Aven::Engine.routes.url_helpers.oauth_google_path
|
|
17
|
+
else
|
|
18
|
+
"#"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def home_path
|
|
23
|
+
if helpers.respond_to?(:main_app) && helpers.main_app.respond_to?(:root_path)
|
|
24
|
+
helpers.main_app.root_path
|
|
25
|
+
else
|
|
26
|
+
Aven::Engine.routes.url_helpers.root_path
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
<% if current_user %>
|
|
6
6
|
<div><%= current_user.id %></div>
|
|
7
|
-
<%= link_to("Logout",
|
|
7
|
+
<%= link_to("Logout", Aven::Engine.routes.url_helpers.logout_path) %>
|
|
8
8
|
<% else %>
|
|
9
|
-
<% Aven.configuration.
|
|
9
|
+
<% Aven.configuration.oauth_providers.each do |provider, config| %>
|
|
10
10
|
<%=
|
|
11
11
|
link_to(
|
|
12
|
-
"Login with #{
|
|
13
|
-
|
|
12
|
+
"Login with #{provider.to_s.capitalize}",
|
|
13
|
+
oauth_path_for(provider)
|
|
14
14
|
)
|
|
15
15
|
%>
|
|
16
16
|
<% end %>
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
module Aven::Views::Static::Index
|
|
2
2
|
class Component < Aven::ApplicationViewComponent
|
|
3
3
|
option(:current_user, optional: true)
|
|
4
|
+
|
|
5
|
+
def oauth_path_for(provider)
|
|
6
|
+
case provider.to_sym
|
|
7
|
+
when :github
|
|
8
|
+
Aven::Engine.routes.url_helpers.oauth_github_path
|
|
9
|
+
when :google
|
|
10
|
+
Aven::Engine.routes.url_helpers.oauth_google_path
|
|
11
|
+
else
|
|
12
|
+
"#"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
4
15
|
end
|
|
5
16
|
end
|
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
module Aven
|
|
2
2
|
class ApplicationController < ActionController::Base
|
|
3
3
|
include Aven::ApplicationHelper
|
|
4
|
+
|
|
5
|
+
helper_method :current_workspace
|
|
6
|
+
|
|
7
|
+
# Get the current workspace from session
|
|
8
|
+
def current_workspace
|
|
9
|
+
return @current_workspace if defined?(@current_workspace)
|
|
10
|
+
|
|
11
|
+
@current_workspace = if session[:workspace_id].present? && current_user
|
|
12
|
+
current_user.workspaces.find_by(id: session[:workspace_id])
|
|
13
|
+
elsif current_user
|
|
14
|
+
# Auto-select first workspace if none selected
|
|
15
|
+
workspace = current_user.workspaces.first
|
|
16
|
+
session[:workspace_id] = workspace&.id
|
|
17
|
+
workspace
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Set the current workspace
|
|
22
|
+
def current_workspace=(workspace)
|
|
23
|
+
@current_workspace = workspace
|
|
24
|
+
session[:workspace_id] = workspace&.id
|
|
25
|
+
end
|
|
4
26
|
end
|
|
5
27
|
end
|
|
@@ -1,64 +1,12 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
module Aven
|
|
4
2
|
class AuthController < ApplicationController
|
|
5
|
-
def authenticate
|
|
6
|
-
provider = params[:provider].to_s
|
|
7
|
-
|
|
8
|
-
raise(StandardError, "invalid provider") unless configured_providers.include?(provider)
|
|
9
|
-
|
|
10
|
-
redirect_post(
|
|
11
|
-
send("user_#{provider}_omniauth_authorize_path"),
|
|
12
|
-
params: { authenticity_token: form_authenticity_token }
|
|
13
|
-
)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def action_missing(action_name)
|
|
17
|
-
if configured_providers.include?(action_name.to_s)
|
|
18
|
-
handle_omniauth(action_name.to_s)
|
|
19
|
-
else
|
|
20
|
-
raise AbstractController::ActionNotFound, "The action '#{action_name}' could not be found for #{self.class.name}"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def passthru
|
|
25
|
-
logout if request.method == "GET"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def failure
|
|
29
|
-
logout if request.method == "GET"
|
|
30
|
-
end
|
|
31
|
-
|
|
32
3
|
def logout
|
|
33
|
-
sign_out
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def configured_providers
|
|
41
|
-
@configured_providers ||= Aven.configuration.auth.providers.map { |p| p[:provider].to_s }
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def handle_omniauth(kind)
|
|
45
|
-
auth_tenant = request.host # or however you determine tenant
|
|
46
|
-
user = Aven::User.create_from_omniauth!(request.env, auth_tenant)
|
|
47
|
-
|
|
48
|
-
if user.persisted?
|
|
49
|
-
sign_in_and_redirect user, event: :authentication
|
|
50
|
-
else
|
|
51
|
-
session["devise.auth"] = request.env["omniauth.auth"].except(:extra)
|
|
52
|
-
redirect_to new_user_registration_url
|
|
4
|
+
sign_out
|
|
5
|
+
begin
|
|
6
|
+
redirect_to(main_app.root_path, notice: "You have been signed out successfully.")
|
|
7
|
+
rescue NoMethodError
|
|
8
|
+
redirect_to(root_path, notice: "You have been signed out successfully.")
|
|
53
9
|
end
|
|
54
10
|
end
|
|
55
|
-
|
|
56
|
-
def after_sign_in_path_for(resource)
|
|
57
|
-
stored_location_for(resource) || Aven.configuration.authenticated_root_path || root_path
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def after_sign_out_path_for(resource_or_scope)
|
|
61
|
-
Aven.configuration.authenticated_root_path || root_path
|
|
62
|
-
end
|
|
63
11
|
end
|
|
64
|
-
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Aven
|
|
7
|
+
module Oauth
|
|
8
|
+
class Auth0Controller < BaseController
|
|
9
|
+
# Auth0 uses your domain (e.g., your-tenant.auth0.com or your-tenant.us.auth0.com)
|
|
10
|
+
# These URLs will be constructed dynamically based on the configured domain
|
|
11
|
+
DEFAULT_SCOPE = "openid email profile"
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def authorization_url(state)
|
|
16
|
+
params = {
|
|
17
|
+
client_id: oauth_config[:client_id],
|
|
18
|
+
redirect_uri: callback_url,
|
|
19
|
+
response_type: "code",
|
|
20
|
+
scope: oauth_config[:scope] || DEFAULT_SCOPE,
|
|
21
|
+
state:
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Optionally add audience parameter if specified (for API access)
|
|
25
|
+
params[:audience] = oauth_config[:audience] if oauth_config[:audience].present?
|
|
26
|
+
|
|
27
|
+
"#{auth0_authorization_url}?#{params.to_query}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def exchange_code_for_token(code)
|
|
31
|
+
params = {
|
|
32
|
+
grant_type: "authorization_code",
|
|
33
|
+
client_id: oauth_config[:client_id],
|
|
34
|
+
client_secret: oauth_config[:client_secret],
|
|
35
|
+
code:,
|
|
36
|
+
redirect_uri: callback_url
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
oauth_request(URI(auth0_token_url), params)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def fetch_user_info(access_token)
|
|
43
|
+
response = oauth_get_request(URI(auth0_userinfo_url), access_token)
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
id: response[:sub],
|
|
47
|
+
email: response[:email],
|
|
48
|
+
name: response[:name] || response[:nickname],
|
|
49
|
+
picture: response[:picture]
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def callback_url
|
|
56
|
+
aven.oauth_auth0_callback_url(host: request.host, protocol: request.protocol)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def oauth_config
|
|
60
|
+
@oauth_config ||= Aven.configuration.oauth_providers[:auth0] || raise("Auth0 OAuth not configured")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def auth0_domain
|
|
64
|
+
@auth0_domain ||= oauth_config[:domain] || raise("Auth0 domain not configured")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def auth0_base_url
|
|
68
|
+
@auth0_base_url ||= auth0_domain.start_with?("http") ? auth0_domain : "https://#{auth0_domain}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def auth0_authorization_url
|
|
72
|
+
"#{auth0_base_url}/authorize"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def auth0_token_url
|
|
76
|
+
"#{auth0_base_url}/oauth/token"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def auth0_userinfo_url
|
|
80
|
+
"#{auth0_base_url}/userinfo"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven
|
|
4
|
+
module Oauth
|
|
5
|
+
class BaseController < ApplicationController
|
|
6
|
+
skip_before_action :verify_authenticity_token, only: [:callback]
|
|
7
|
+
|
|
8
|
+
# Initiates OAuth flow
|
|
9
|
+
def create
|
|
10
|
+
state = SecureRandom.hex(16)
|
|
11
|
+
session[:oauth_state] = state
|
|
12
|
+
|
|
13
|
+
redirect_to authorization_url(state), allow_other_host: true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Handles OAuth callback
|
|
17
|
+
def callback
|
|
18
|
+
validate_state!
|
|
19
|
+
|
|
20
|
+
token_data = exchange_code_for_token(params[:code])
|
|
21
|
+
user_info = fetch_user_info(token_data[:access_token])
|
|
22
|
+
|
|
23
|
+
user = find_or_create_user(user_info, token_data)
|
|
24
|
+
|
|
25
|
+
if user.persisted?
|
|
26
|
+
sign_in_and_redirect(user)
|
|
27
|
+
else
|
|
28
|
+
handle_failed_authentication(user)
|
|
29
|
+
end
|
|
30
|
+
rescue => e
|
|
31
|
+
Rails.logger.error("OAuth authentication failed: #{e.class.name} - #{e.message}")
|
|
32
|
+
Rails.logger.error(e.backtrace.first(10).join("\n")) unless Rails.env.production?
|
|
33
|
+
|
|
34
|
+
error_message = if Rails.env.production?
|
|
35
|
+
"Authentication failed. Please try again."
|
|
36
|
+
else
|
|
37
|
+
"#{e.message}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
error_class = Rails.env.production? ? nil : e.class.name
|
|
41
|
+
render_error_page(error_message, error_class)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Renders OAuth error page
|
|
45
|
+
def error
|
|
46
|
+
@error_message = params[:message] || "Authentication failed"
|
|
47
|
+
@error_class = params[:error_class]
|
|
48
|
+
|
|
49
|
+
view_component(
|
|
50
|
+
"oauth/error",
|
|
51
|
+
error_message: @error_message,
|
|
52
|
+
error_class: @error_class,
|
|
53
|
+
current_user:
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
protected
|
|
58
|
+
|
|
59
|
+
# Must be implemented by subclasses
|
|
60
|
+
def authorization_url(state)
|
|
61
|
+
raise NotImplementedError
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def exchange_code_for_token(code)
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def fetch_user_info(access_token)
|
|
69
|
+
raise NotImplementedError
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Common helper methods
|
|
73
|
+
def validate_state!
|
|
74
|
+
if params[:state] != session[:oauth_state]
|
|
75
|
+
raise StandardError, "Invalid state parameter"
|
|
76
|
+
end
|
|
77
|
+
session.delete(:oauth_state)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def find_or_create_user(user_info, token_data)
|
|
81
|
+
auth_tenant = request.host
|
|
82
|
+
|
|
83
|
+
user = Aven::User.where(auth_tenant:)
|
|
84
|
+
.where("remote_id = ? OR email = ?", user_info[:id].to_s, user_info[:email])
|
|
85
|
+
.first_or_initialize
|
|
86
|
+
|
|
87
|
+
user.tap do |u|
|
|
88
|
+
u.auth_tenant = auth_tenant
|
|
89
|
+
u.remote_id = user_info[:id].to_s
|
|
90
|
+
u.email = user_info[:email]
|
|
91
|
+
u.access_token = token_data[:access_token]
|
|
92
|
+
u.save
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def sign_in_and_redirect(user)
|
|
97
|
+
sign_in(user)
|
|
98
|
+
set_current_workspace_for(user)
|
|
99
|
+
redirect_to after_sign_in_path_for(user)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def set_current_workspace_for(user)
|
|
103
|
+
workspace = user.workspaces.first
|
|
104
|
+
|
|
105
|
+
# Create default workspace if user has none (new sign up)
|
|
106
|
+
if workspace.nil?
|
|
107
|
+
workspace = Aven::Workspace.create!(label: "Default Workspace")
|
|
108
|
+
Aven::WorkspaceUser.create!(user: user, workspace: workspace)
|
|
109
|
+
user.reload
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Set current workspace in session
|
|
113
|
+
session[:workspace_id] = workspace.id
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def handle_failed_authentication(user)
|
|
117
|
+
error_message = if !Rails.env.production? && user.errors.any?
|
|
118
|
+
user.errors.full_messages.join(", ")
|
|
119
|
+
else
|
|
120
|
+
"Failed to create user account"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
error_class = Rails.env.production? ? nil : "User::ValidationError"
|
|
124
|
+
render_error_page(error_message, error_class)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def render_error_page(message, error_class = nil)
|
|
128
|
+
view_component(
|
|
129
|
+
"oauth/error",
|
|
130
|
+
error_message: message,
|
|
131
|
+
error_class:,
|
|
132
|
+
current_user:
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def after_sign_in_path_for(resource)
|
|
137
|
+
stored_location_for(resource) ||
|
|
138
|
+
Aven.configuration.resolve_authenticated_root_path ||
|
|
139
|
+
begin
|
|
140
|
+
main_app.root_path
|
|
141
|
+
rescue NoMethodError
|
|
142
|
+
root_path
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# HTTP helper for OAuth requests
|
|
147
|
+
def oauth_request(uri, params, headers = {})
|
|
148
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
149
|
+
http.use_ssl = true
|
|
150
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
|
|
151
|
+
|
|
152
|
+
request = Net::HTTP::Post.new(uri)
|
|
153
|
+
request.set_form_data(params)
|
|
154
|
+
headers.each { |key, value| request[key] = value }
|
|
155
|
+
|
|
156
|
+
response = http.request(request)
|
|
157
|
+
|
|
158
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
159
|
+
raise StandardError, "OAuth request failed: #{response.body}"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
JSON.parse(response.body, symbolize_names: true)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def oauth_get_request(uri, access_token)
|
|
166
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
167
|
+
http.use_ssl = true
|
|
168
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
|
|
169
|
+
|
|
170
|
+
request = Net::HTTP::Get.new(uri)
|
|
171
|
+
request["Authorization"] = "Bearer #{access_token}"
|
|
172
|
+
|
|
173
|
+
response = http.request(request)
|
|
174
|
+
|
|
175
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
176
|
+
raise StandardError, "OAuth request failed: #{response.body}"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
JSON.parse(response.body, symbolize_names: true)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|