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
131
132
133
134
135
136
137
138
139
140
141
142
|
# SPDX-FileCopyrightText: 2020 IN COMMON Collective <collective@incommon.cc>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
class WelcomeController < ApplicationController
# GET /
def index
@map = Map.first
@taxonomy = @map.taxonomy
@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
user_data = {
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]
}
@current_user = User.find_by(external_id: user_data[:external_id]) ||
begin
Rails.logger.info('new user...')
u = User.create(user_data)
Rails.logger.info('created user %s' % u.inspect)
u
rescue Exception => e
Rails.logger.warning("#{e.type}: #{e.message}")
end
user_data.reverse_merge!(@current_user.attributes.symbolize_keys)
@current_user.update(user_data) if user_data != @current_user.attributes
@current_user
end
# Update user agents
def perform_background_jobs
if @current_user.present?
EnsureAgentJob.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]
session[:current_agent] = current_agent_name
end
end
end
|