Integrate Discourse Connect (SSO)
This commit is contained in:
parent
d130f2f68b
commit
19bafe081f
@ -19,6 +19,8 @@ LDAP_SUFFIX='dc=kosmos,dc=org'
|
|||||||
WEBHOOKS_ALLOWED_IPS='10.1.1.163'
|
WEBHOOKS_ALLOWED_IPS='10.1.1.163'
|
||||||
|
|
||||||
DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
|
DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
|
||||||
|
DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
|
||||||
|
|
||||||
GITEA_PUBLIC_URL='https://gitea.kosmos.org'
|
GITEA_PUBLIC_URL='https://gitea.kosmos.org'
|
||||||
MASTODON_PUBLIC_URL='https://kosmos.social'
|
MASTODON_PUBLIC_URL='https://kosmos.social'
|
||||||
MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
|
MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
|
||||||
|
3
Gemfile
3
Gemfile
@ -51,6 +51,9 @@ gem 'faraday'
|
|||||||
gem 'sidekiq', '< 7'
|
gem 'sidekiq', '< 7'
|
||||||
gem 'sidekiq-scheduler'
|
gem 'sidekiq-scheduler'
|
||||||
|
|
||||||
|
# Service integrations
|
||||||
|
gem 'discourse_api'
|
||||||
|
|
||||||
# Monitoring
|
# Monitoring
|
||||||
gem "sentry-ruby"
|
gem "sentry-ruby"
|
||||||
gem "sentry-rails"
|
gem "sentry-rails"
|
||||||
|
11
Gemfile.lock
11
Gemfile.lock
@ -108,6 +108,11 @@ GEM
|
|||||||
devise (>= 3.4.1)
|
devise (>= 3.4.1)
|
||||||
net-ldap (>= 0.16.0)
|
net-ldap (>= 0.16.0)
|
||||||
diff-lcs (1.5.0)
|
diff-lcs (1.5.0)
|
||||||
|
discourse_api (2.0.0)
|
||||||
|
faraday (~> 2.7)
|
||||||
|
faraday-follow_redirects
|
||||||
|
faraday-multipart
|
||||||
|
rack (>= 1.6)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
dotenv-rails (2.8.1)
|
dotenv-rails (2.8.1)
|
||||||
dotenv (= 2.8.1)
|
dotenv (= 2.8.1)
|
||||||
@ -126,6 +131,10 @@ GEM
|
|||||||
faraday (2.7.1)
|
faraday (2.7.1)
|
||||||
faraday-net_http (>= 2.0, < 3.1)
|
faraday-net_http (>= 2.0, < 3.1)
|
||||||
ruby2_keywords (>= 0.0.4)
|
ruby2_keywords (>= 0.0.4)
|
||||||
|
faraday-follow_redirects (0.3.0)
|
||||||
|
faraday (>= 1, < 3)
|
||||||
|
faraday-multipart (1.0.4)
|
||||||
|
multipart-post (~> 2)
|
||||||
faraday-net_http (3.0.2)
|
faraday-net_http (3.0.2)
|
||||||
ffi (1.15.5)
|
ffi (1.15.5)
|
||||||
flipper (0.28.0)
|
flipper (0.28.0)
|
||||||
@ -183,6 +192,7 @@ GEM
|
|||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.8.0)
|
mini_portile2 (2.8.0)
|
||||||
minitest (5.16.3)
|
minitest (5.16.3)
|
||||||
|
multipart-post (2.3.0)
|
||||||
net-imap (0.3.1)
|
net-imap (0.3.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.17.1)
|
net-ldap (0.17.1)
|
||||||
@ -386,6 +396,7 @@ DEPENDENCIES
|
|||||||
database_cleaner
|
database_cleaner
|
||||||
devise (~> 4.9.0)
|
devise (~> 4.9.0)
|
||||||
devise_ldap_authenticatable
|
devise_ldap_authenticatable
|
||||||
|
discourse_api
|
||||||
dotenv-rails
|
dotenv-rails
|
||||||
factory_bot_rails
|
factory_bot_rails
|
||||||
faker
|
faker
|
||||||
|
17
app/controllers/discourse/sso_controller.rb
Normal file
17
app/controllers/discourse/sso_controller.rb
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
class Discourse::SsoController < ApplicationController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
|
||||||
|
def connect
|
||||||
|
secret = Setting.discourse_connect_secret
|
||||||
|
sso = DiscourseApi::SingleSignOn.parse(request.query_string, secret)
|
||||||
|
sso.external_id = current_user.id
|
||||||
|
sso.email = current_user.email
|
||||||
|
sso.username = current_user.cn
|
||||||
|
sso.name = current_user.display_name
|
||||||
|
sso.admin = current_user.is_admin?
|
||||||
|
sso.sso_secret = secret
|
||||||
|
|
||||||
|
redirect_to sso.to_url("#{Setting.discourse_public_url}/session/sso_login"),
|
||||||
|
allow_other_host: true
|
||||||
|
end
|
||||||
|
end
|
@ -2,6 +2,9 @@
|
|||||||
class Setting < RailsSettings::Base
|
class Setting < RailsSettings::Base
|
||||||
cache_prefix { "v1" }
|
cache_prefix { "v1" }
|
||||||
|
|
||||||
|
field :accounts_domain, type: :string,
|
||||||
|
default: ENV["AKKOUNTS_DOMAIN"].presence
|
||||||
|
|
||||||
#
|
#
|
||||||
# Internal services
|
# Internal services
|
||||||
#
|
#
|
||||||
@ -41,6 +44,9 @@ class Setting < RailsSettings::Base
|
|||||||
field :discourse_enabled, type: :boolean,
|
field :discourse_enabled, type: :boolean,
|
||||||
default: (ENV["DISCOURSE_PUBLIC_URL"].present?.to_s || false)
|
default: (ENV["DISCOURSE_PUBLIC_URL"].present?.to_s || false)
|
||||||
|
|
||||||
|
field :discourse_connect_secret, type: :string, readonly: true,
|
||||||
|
default: ENV["DISCOURSE_CONNECT_SECRET"].presence
|
||||||
|
|
||||||
#
|
#
|
||||||
# ejabberd
|
# ejabberd
|
||||||
#
|
#
|
||||||
|
@ -7,11 +7,46 @@
|
|||||||
title: "Enable Discourse integration",
|
title: "Enable Discourse integration",
|
||||||
description: "Discourse configuration present and features enabled"
|
description: "Discourse configuration present and features enabled"
|
||||||
) %>
|
) %>
|
||||||
<% if Setting.discourse_enabled? %>
|
<% if Setting.discourse_enabled? %>
|
||||||
<%= render FormElements::FieldsetComponent.new(title: "Public URL") do %>
|
<%= render FormElements::FieldsetComponent.new(title: "Public URL") do %>
|
||||||
<%= f.text_field :discourse_public_url,
|
<%= f.text_field :discourse_public_url,
|
||||||
value: Setting.discourse_public_url,
|
value: Setting.discourse_public_url,
|
||||||
class: "w-full", disabled: true %>
|
class: "w-full", disabled: true %>
|
||||||
<% end %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<%= render FormElements::FieldsetComponent.new(title: "Connect secret") do %>
|
||||||
|
<%= f.password_field :discourse_connect_secret,
|
||||||
|
value: Setting.discourse_connect_secret,
|
||||||
|
class: "w-full", disabled: true %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
|
<% if Setting.discourse_enabled? %>
|
||||||
|
<% content_for :documentation do %>
|
||||||
|
<h3 class="mt-8">How to configure Discourse</h3>
|
||||||
|
<ol class="list-decimal list-inside">
|
||||||
|
<li class="mb-6">
|
||||||
|
Set the <strong>Discourse Connect URL</strong> to the following URL:
|
||||||
|
</li>
|
||||||
|
<li data-controller="clipboard" class="mb-6 flex gap-1">
|
||||||
|
<input type="text" class="grow" disabled="disabled"
|
||||||
|
value="https://<%= Setting.accounts_domain %>/discourse/connect"
|
||||||
|
data-clipboard-target="source" />
|
||||||
|
<button class="btn-md btn-icon btn-blue shrink-0"
|
||||||
|
data-clipboard-target="trigger" data-action="clipboard#copy"
|
||||||
|
title="Copy to clipboard">
|
||||||
|
<span class="content-initial">
|
||||||
|
<%= render partial: "icons/copy", locals: { custom_class: "text-white h-4 w-4 inline" } %>
|
||||||
|
</span>
|
||||||
|
<span class="content-active hidden">
|
||||||
|
<%= render partial: "icons/check", locals: { custom_class: "text-white h-4 w-4 inline" } %>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li class="mb-6">
|
||||||
|
Set the <strong>Discourse Connect Secret</strong> to the value above.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Enable Discourse Connect.
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
@ -20,4 +20,10 @@
|
|||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<% if content_for?(:documentation) %>
|
||||||
|
<section>
|
||||||
|
<%= yield :documentation %>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
|
<%
|
||||||
|
# TODO remove when https://github.com/hotwired/turbo/issues/203 is fixed
|
||||||
|
enable_turbo = !session[:user_return_to].match?('/discourse/connect')
|
||||||
|
%>
|
||||||
|
|
||||||
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|
||||||
<%= render MainCompactComponent.new do %>
|
<%= render MainCompactComponent.new do %>
|
||||||
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
<%= form_for(resource, as: resource_name, url: session_path(resource_name),
|
||||||
|
data: { turbo: enable_turbo.to_s }) do |f| %>
|
||||||
<%= render "devise/shared/error_messages", resource: resource %>
|
<%= render "devise/shared/error_messages", resource: resource %>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<%= f.label :cn, 'User', class: 'block mb-2 font-bold' %>
|
<%= f.label :cn, 'User', class: 'block mb-2 font-bold' %>
|
||||||
|
@ -63,6 +63,10 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
get ".well-known/webfinger" => "webfinger#show"
|
get ".well-known/webfinger" => "webfinger#show"
|
||||||
|
|
||||||
|
namespace :discourse do
|
||||||
|
get "connect", to: 'sso#connect'
|
||||||
|
end
|
||||||
|
|
||||||
authenticate :user, ->(user) { user.is_admin? } do
|
authenticate :user, ->(user) { user.is_admin? } do
|
||||||
mount Sidekiq::Web => '/sidekiq'
|
mount Sidekiq::Web => '/sidekiq'
|
||||||
mount Flipper::UI.app(Flipper) => '/flipper'
|
mount Flipper::UI.app(Flipper) => '/flipper'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user