1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
class WelcomeController < ApplicationController
# GET /
def index
@resources = Resource.order(:uuid).page params[:page]
Rails.logger.info "WECLOME ///// #{@resources&.count || 0}"
end
# GET /authenticate(/:token)
# Discourse SSO Authentication
def authenticate
validate_token_format!
# Try an ongoing SSO or create a new one
@sso = SSO::FromDiscourse.new(token: params[:token], nonce: session[params[:token]])
clear_current_session
# Start SSO roundtrip if we're not passed a token
if params[:token].nil?
# Record this token and nonce in the session
session[@sso.token] = @sso.nonce
# Send to SSO authenticator
redirect_to @sso.request_uri and return
end
# Validate authentication params from SSO
begin
@sso.parse(params)
rescue ArgumentError => e
Rails.logger.debug("SSO request failed: #{e.message}")
return :forbidden
end
# Resolve SSO and finish authentication
case @sso.status
when :ok
Rails.logger.info("Authentication succeeded!")
find_or_create_current_user
perform_background_jobs
update_current_session
when :unauthorized
Rails.logger.info("Authentication failed!")
end
return :forbidden unless @current_user.present?
# TODO add some memory of previously called URL and return there
redirect_to '/my/dashboard'
end
# GET /dashboard
def dashboard
redirect_to '/authenticate' and return unless current_user.present?
@stats = {
counts: {
resources: Resource.count,
agents: Agent.count,
categories: Category.count,
sections: Section.count
},
current_agent: {
name: current_agent.name,
uuid: current_agent.uuid,
counts: {
resources: current_agent.resources.count,
taxonomies: current_agent.taxonomies.count,
categories: current_agent.categories.count,
sectiions: current_agent.sections.count
}
},
my_agents: current_user.agents.map { |a| { uuid: a.uuid, name: a.name } }
}
end
# GET /logout
def logout
session.destroy
render :index
end
private
# Ensure nobody tries silly things with our session
def validate_token_format!
if params[:token].present? && !params[:token].match?(/[a-z0-9]{32}/)
raise(ArgumentError, "Token invalid")
end
end
# Remove any current session
def clear_current_session
Rails.logger.info("Removing current session (#{session[:current_user]})")
session.destroy
@current_user = nil
end
# Set @current_user to existing or new User record from SSO user info
def find_or_create_current_user
@current_user = User.find_by(external_id: @sso.user_info[:external_id]) ||
begin
Rails.logger.info('new user...')
u = User.create(
external_id: @sso.user_info[:external_id],
avatar_url: @sso.user_info[:avatar_url],
email: @sso.user_info[:email],
name: @sso.user_info[:name],
username: @sso.user_info[:username])
Rails.logger.info('created user %s' % u.inspect)
u
rescue Exception => e
Rails.logger.warning("#{e.type}: #{e.message}")
end
end
# Update user agents
def perform_background_jobs
if @current_user.present?
AgencyWatcherJob.perform_later(@current_user, @sso.user_info[:groups].split(','))
end
end
# Save User ID and current agent in session
def update_current_session
if @current_user.present?
session[:current_user] = @current_user[:external_id]
# TODO: make this a bit smarter
session[:current_agent] = @current_user&.agents&.pluck(:name)&.last
end
end
end
|