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'
 | 
			
		||||
 | 
			
		||||
DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
 | 
			
		||||
DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
 | 
			
		||||
 | 
			
		||||
GITEA_PUBLIC_URL='https://gitea.kosmos.org'
 | 
			
		||||
MASTODON_PUBLIC_URL='https://kosmos.social'
 | 
			
		||||
MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Gemfile
									
									
									
									
									
								
							@ -51,6 +51,9 @@ gem 'faraday'
 | 
			
		||||
gem 'sidekiq', '< 7'
 | 
			
		||||
gem 'sidekiq-scheduler'
 | 
			
		||||
 | 
			
		||||
# Service integrations
 | 
			
		||||
gem 'discourse_api'
 | 
			
		||||
 | 
			
		||||
# Monitoring
 | 
			
		||||
gem "sentry-ruby"
 | 
			
		||||
gem "sentry-rails"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Gemfile.lock
									
									
									
									
									
								
							@ -108,6 +108,11 @@ GEM
 | 
			
		||||
      devise (>= 3.4.1)
 | 
			
		||||
      net-ldap (>= 0.16.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-rails (2.8.1)
 | 
			
		||||
      dotenv (= 2.8.1)
 | 
			
		||||
@ -126,6 +131,10 @@ GEM
 | 
			
		||||
    faraday (2.7.1)
 | 
			
		||||
      faraday-net_http (>= 2.0, < 3.1)
 | 
			
		||||
      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)
 | 
			
		||||
    ffi (1.15.5)
 | 
			
		||||
    flipper (0.28.0)
 | 
			
		||||
@ -183,6 +192,7 @@ GEM
 | 
			
		||||
    mini_mime (1.1.2)
 | 
			
		||||
    mini_portile2 (2.8.0)
 | 
			
		||||
    minitest (5.16.3)
 | 
			
		||||
    multipart-post (2.3.0)
 | 
			
		||||
    net-imap (0.3.1)
 | 
			
		||||
      net-protocol
 | 
			
		||||
    net-ldap (0.17.1)
 | 
			
		||||
@ -386,6 +396,7 @@ DEPENDENCIES
 | 
			
		||||
  database_cleaner
 | 
			
		||||
  devise (~> 4.9.0)
 | 
			
		||||
  devise_ldap_authenticatable
 | 
			
		||||
  discourse_api
 | 
			
		||||
  dotenv-rails
 | 
			
		||||
  factory_bot_rails
 | 
			
		||||
  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
 | 
			
		||||
  cache_prefix { "v1" }
 | 
			
		||||
 | 
			
		||||
  field :accounts_domain, type: :string,
 | 
			
		||||
    default: ENV["AKKOUNTS_DOMAIN"].presence
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Internal services
 | 
			
		||||
  #
 | 
			
		||||
@ -41,6 +44,9 @@ class Setting < RailsSettings::Base
 | 
			
		||||
  field :discourse_enabled, type: :boolean,
 | 
			
		||||
    default: (ENV["DISCOURSE_PUBLIC_URL"].present?.to_s || false)
 | 
			
		||||
 | 
			
		||||
  field :discourse_connect_secret, type: :string, readonly: true,
 | 
			
		||||
    default: ENV["DISCOURSE_CONNECT_SECRET"].presence
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # ejabberd
 | 
			
		||||
  #
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,46 @@
 | 
			
		||||
    title: "Enable Discourse integration",
 | 
			
		||||
    description: "Discourse configuration present and features enabled"
 | 
			
		||||
  ) %>
 | 
			
		||||
  <% if Setting.discourse_enabled? %>
 | 
			
		||||
<% if Setting.discourse_enabled? %>
 | 
			
		||||
  <%= render FormElements::FieldsetComponent.new(title: "Public URL") do %>
 | 
			
		||||
    <%= f.text_field :discourse_public_url,
 | 
			
		||||
      value: Setting.discourse_public_url,
 | 
			
		||||
      class: "w-full", disabled: true %>
 | 
			
		||||
  <% 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>
 | 
			
		||||
<% 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>
 | 
			
		||||
    </section>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <% if content_for?(:documentation) %>
 | 
			
		||||
  <section>
 | 
			
		||||
    <%= yield :documentation %>
 | 
			
		||||
  </section>
 | 
			
		||||
  <% 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 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 %>
 | 
			
		||||
    <div class="mb-6">
 | 
			
		||||
      <%= 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"
 | 
			
		||||
 | 
			
		||||
  namespace :discourse do
 | 
			
		||||
    get "connect", to: 'sso#connect'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  authenticate :user, ->(user) { user.is_admin? } do
 | 
			
		||||
    mount Sidekiq::Web => '/sidekiq'
 | 
			
		||||
    mount Flipper::UI.app(Flipper) => '/flipper'
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user