Discourse. SSO за 10 кроків (на основі Docker)

Як налаштувати SSO для Discourse, коли у вас є веб-проєкт на Ruby on Rails як сервер для входу

Крок 1. Стабільна гілка для початку!

Завжди використовуйте стабільну гілку для початку ваших експериментів з Discourse.
https://github.com/discourse/discourse/tree/stable

Основна гілка нестабільна, і це нормально, якщо вона не працює.

Крок 2. Інсталяція

Мій файл docker-compose.yml може стати в пригоді

name: discourse  

services:  
 postgres:  
 image: postgres:13.4  
 environment:  
 - POSTGRES_USER=postgres  
 - POSTGRES_DB=discourse_development  
 - POSTGRES_PASSWORD=qwerty  
 - PSQL_HISTFILE=/root/log/.psql_history  
 ports:  
 - ${POSTGRES_PORT-5432}:${POSTGRES_PORT:-5432}  
 volumes:  
 - ./data/PSQL:/var/lib/postgresql/data  

 redis:  
 image: redis:7.4.2  
 volumes:  
 - ./data/REDIS:/data  

 app:  
 build:  
 context: ..

dockerfile: ./docker/Dockerfile  
 environment:  
 - DISCOURSE_DB_HOST=postgres  
 - DISCOURSE_DB_PORT=5432  
 - DISCOURSE_DEV_DB=discourse_development  
 - DISCOURSE_DB_USERNAME=postgres  
 - DISCOURSE_DB_PASSWORD=qwerty  

 - DISCOURSE_REDIS_HOST=redis  
 - DISCOURSE_REDIS_PORT=6379  
 ports:  
 - "3000:3000"  
 - "4200:4200"  
 volumes:  
 - ..:/app  
 command: sleep infinity

Мій Dockerfile (Mac OS / M1)

# https://meta.discourse.org/t/install-discourse-on-ubuntu-or-debian-for-development/14727/1  
# bash <(wget -qO- https://raw.githubusercontent.com/discourse/install-rails/main/linux)  
# https://github.com/discourse/discourse/blob/main/docs/DEVELOPER-ADVANCED.md  

FROM ruby:3.2-bookworm  

ARG PROJECT_PATH=${PROJECT_PATH:-__PROJECTS__/discourse}  

# ВСТАНОВЛЕННЯ ЗАЛЕЖНОСТЕЙ  
#  
# build-essential - Основні інструменти для компіляції програм  
# libxslt1-dev - Бібліотека для обробки XSLT  
# libcurl4-openssl-dev - Бібліотека для HTTP-запитів з підтримкою SSL  
# libksba8 - Бібліотеки для криптографічної функціональності  
# libksba-dev - Бібліотеки для криптографічної функціональності  
# libreadline-dev - Бібліотека для GNU readline (інтерактивна командна строка)  
# libssl-dev - Бібліотека для підтримки SSL/TLS  
# zlib1g-dev - Бібліотека для стиснення  
# libsnappy-dev - Бібліотека для стиснення Snappy  
# libyaml-dev - Бібліотека для розбору YAML  
# libpq-dev - Бібліотека клієнта PostgreSQL для підключення до бази даних  
# postgresql-client - Клієнт PostgreSQL для взаємодії з віддаленими базами даних  
# telnet - Інструмент для тестування мережевих сервісів  
# nano - Текстовий редактор командного рядка  
# git - Система контролю версій Git  
# net-tools - Утиліти для діагностики та тестування мережевих з'єднань  
# dnsutils - Інструменти для запитів DNS  
# iputils-ping - Утиліти для пінгу хостів та тестування з'єднань  
# curl - Командний інструмент для передачі даних з URL  
# wget - Командний інструмент для завантаження файлів  
# tzdata - Дані про часові пояси для керування часом  
# advancecomp - Інструменти для оптимізації PNG та MNG файлів  
# jhead - Інструмент для відображення та маніпулювання даними Exif  
# jpegoptim - Інструмент для оптимізації JPEG файлів  
# libjpeg-turbo-progs - Інструменти для оптимізації JPEG файлів  
# optipng - Інструмент для оптимізації PNG файлів  
# pngcrush - Інструмент для оптимізації PNG файлів  
# pngquant - Інструмент для оптимізації PNG файлів  
# gnupg2 - GNU Privacy Guard для безпечного зв'язку та зберігання даних  
# libjpeg-dev - Розробницькі файли для бібліотеки JPEG  
# libpng-dev - Розробницькі файли для бібліотеки PNG  
# libtiff-dev - Розробницькі файли для бібліотеки TIFF  
# libwebp-dev - Розробницькі файли для бібліотеки WebP  
# libxml2-dev - Розробницькі файли для бібліотеки XML  
# libltdl-dev - Розробницькі файли для бібліотеки libtool  
# libfreetype6-dev - Розробницькі файли для бібліотеки FreeType  
# liblcms2-dev - Розробницькі файли для бібліотеки Little CMS  
# liblqr-1-0-dev - Розробницькі файли для бібліотеки Liquid Rescale  
# libfftw3-dev - Розробницькі файли для бібліотеки Fastest Fourier Transform in the West  
# ghostscript - Інтерпретатор для мови PostScript та PDF  
#  
RUN apt-get update -qq && apt-get install -y \  
 build-essential \  
 libxs  
 libksba-dev \  
 libreadline-dev \  
 libssl-dev \  
 zlib1g-dev \  
 libsnappy-dev \  
 libyaml-dev \  
 libpq-dev \  
 postgresql-client \  
 telnet \  
 nano \  
 git \  
 net-tools \  
 dnsutils \  
 iputils-ping \  
 curl \  
 wget \  
 tzdata \  
 advancecomp \  
 jhead \  
 jpegoptim \  
 libjpeg-turbo-progs \  
 optipng \  
 pngcrush \  
 pngquant \  
 gnupg2 \  
 libjpeg-dev \  
 libpng-dev \  
 libtiff-dev \  
 libwebp-dev \  
 libxml2-dev \  
 libl  
 liblqr-1-0-dev \  
 libfftw3-dev \  
 ghostscript \  
 && rm -rf /var/lib/apt/lists/*  

# РОБОЧА КАТАЛОГІЯ  
#  
WORKDIR /tmp  

# Завантажити та встановити ImageMagick 7

RUN cd /tmp && wget https://imagemagick.org/download/ImageMagick.tar.gz && \  
 tar xvzf ImageMagick.tar.gz && \  
 cd ImageMagick-* && \  
 ./configure && \  
 make && \  
 make install && \  
 ldconfig /usr/local/lib && \  
 cd ..

&& \  
 rm -rf ImageMagick* && \  
 magick --version  

## OXIPNG - ОПТИМІЗАЦІЯ PNG ФАЙЛІВ (ARM64)  
# https://github.com/shssoichiro/oxipng/releases/  
RUN wget https://github.com/shssoichiro/oxipng/releases/download/v9.1.3/oxipng_9.1.3-1_arm64.deb  
RUN dpkg -i oxipng_9.1.3-1_arm64.deb  

SHELL ["/bin/bash", "-c"]  

## ВСТАНОВЛЕННЯ NODEJS, PNPM І YARN  
#  
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash  
RUN source /root/.nvm/nvm.sh && nvm install lts/hydrogen --default  

# RUN source /root/.nvm/nvm.sh && \  
# corepack enable pnpm && \  
# corepack use pnpm@9  

RUN source /root/.nvm/nvm.sh && \  
 npm install -g yarn  

## РОБОЧА КАТАЛОГІЯ  
#  
WORKDIR /app  

## ВСТАНОВЛЕННЯ ЗАЛЕЖНОСТЕЙ RUBY ON RAILS  
#  
RUN gem install bundler -v 2.5.9  

COPY ${PROJECT_PATH}/Gemfile /app/Gemfile  
COPY ${PROJECT_PATH}/Gemfile.lock /app/Gemfile.lock  

RUN bundle install --frozen  

## ВСТАНОВЛЕННЯ ЗАЛЕЖНОСТЕЙ NODEJS  
#  
RUN source /root/.nvm/nvm.sh && npm install -g svgo  

COPY ${PROJECT_PATH}/package.json /app/package.json  
COPY ${PROJECT_PATH}/patches /app/patches  

RUN source /root/.nvm/nvm.sh && yarn -v

Крок 4. Налаштування бази даних

export SKIP_MULTISITE=1
congif/database.yml

development:  
 adapter: postgresql  
 database: discourse_development  
 username: postgres  
 password: password  
 host: postgres  
 port: 5432  
 pool: 5  

test:  
 adapter: postgresql  
 database: discourse_test  
 username: postgres  
 password: password  
 host: postgres  
 port: 5432  
 pool: 5
$ yarn install  
$ SKIP_MULTISITE=1 bundle exec rake db:create db:migrate

Крок 5. Створення адміністратора

В контейнері на localhost

$ bin/rails admin:create  

Email: [email protected]  
Password:   
Repeat password:   

Ensuring account is active!  

Account created successfully with username `newforum`  
Do you want to grant Admin privileges to this account? (Y/n) Y  

Your account now has Admin privileges!

Крок 6. Запуск проєкту

export DISCOURSE_HOSTNAME=localhost  
export DISCOURSE_PORT=4200  
export SKIP_MULTISITE=1  

bin/ember-cli -u

http://localhost:4200

pic

Крок 7. Налаштування DiscourseConnect (SSO)

http://localhost:4200/admin/site_settings/category/login

pic

enable_discourse_connect : повинен бути увімкнений, глобальний перемикач
discourse_connect_url: зовнішня URL-адреса, на яку користувачів буде перенаправлено під час спроби увійти
discourse_connect_secret: секретний рядок, який використовується для хешування SSO навантажень. Забезпечує автентичність навантажень.

Мій сервер для входу запущений на localhost:3002

enable discourse connect: true
discourse connect allowed redirect domains: http://localhost:3002
discourse connect url: http://localhost:3002/connect/sso
discourse connect secret: MySecretKey

pic

Крок 8. Кнопка входу тепер веде на http://localhost:3002/connect/sso

pic

http://localhost:3002/connect/sso?sso=PAYLOAD&sig=SIG

class SsoController < ActionController::Base  
 def sso  
 render json: params  
 end  
end
Rails.application.routes.draw do  
 get '/connect/sso', to: 'sso#sso', as: 'sso'  
end

Давайте розглянемо запит до сервера входу

pic

Крок 9.

SSO контролер на вашій стороні

Давайте реалізуємо SSO контролер

require 'base64'  
require 'openssl'  

class SsoController < ActionController::Base  
 # Має бути рівним тому, що ви зберегли в налаштуваннях Discourse  
 DISCOURSE_SECRET = "MySecretKey"  

 before_action :store_user_location!, if: :storable_location?  
 before_action :authenticate_user!  

 def sso  
 # Отримуємо параметри з запиту  
 sso = params[:sso]  
 sig = params[:sig]  

 # Перевіряємо підпис  
 unless valid_signature?(sso, sig)  
 render plain: 'Невірний підпис', status: :unauthorized  
 return  
 end  

 # Декодуємо навантаження SSO  
 sso_params = decode_sso_payload(sso)  

 # Формуємо навантаження для відправки назад до Discourse  
 response_payload = {  
 nonce: sso_params['nonce'],  
 email: current_user.email,  
 external_id: current_user.id.to_s,  
 username: current_user.username  
 }  

 # Генеруємо відповідь  
 encoded_response, response_sig = generate_response(sso_params, response_payload)  

 # http://postgres:4200/session/sso_login?sso=PAYLOAD=&sig=SINGNATURE  
 # Перенаправляємо назад до Discourse  
 # МОЖЕ ПРИПАДАТИ ДОПОМІНІТЬ ДОДАТКОВІ НАЛАШТУВАННЯ  
 redirect_to "#{sso_params['return_sso_url']}?sso=#{encoded_response}&sig=#{response_sig}"  
 end  

 private  

 # Перевіряє підпис за допомогою секретного ключа Discourse  
 def valid_signature?(sso, sig)  
 computed_sig = OpenSSL::HMAC.hexdigest('sha256', DISCOURSE_SECRET, sso)  
 computed_sig == sig  
 end  

 # Декодує Base64-encoded навантаження SSO  
 def decode_sso_payload(sso)  
 decoded_sso = Base64.decode64(sso)  
 Rack::Utils.parse_nested_query(decoded_sso)  
 end  

 # Генерує відповідь і її підпис  
 def generate_response(sso_params, response_payload)  
 raw_response = URI.encode_www_form(response_payload)  
 encoded_response = Base64.strict_encode64(raw_response)  
 response_sig = OpenSSL::HMAC.hexdigest('sha256', DISCOURSE_SECRET, encoded_response)  

 [encoded_response, response_sig]  
 end  

 def storable_location?  
 request.get? && is_navigational_format? && !devise_controller? && !request.xhr?  
 end  

 def store_user_location!  
 session[:return_to] = request.original_url  
 end  
end

pic

pic

SiteSetting.port = 4200
SiteSetting.forcehostname = “localhost”
Discourse.base
url => “
http://localhost:4200"

Крок 10. Увійдіть і побачте свій новий акаунт

pic

Висновок

Тепер ви знаєте, як налаштувати SSO для Discourse, якщо ваш сервер для входу є застосунком на основі Rails.

Щасливого кодування!
Слідкуйте за мною на github: https://github.com/the-teacher

Перекладено з: Discourse. SSO in 10 steps (Docker based)

Leave a Reply

Your email address will not be published. Required fields are marked *