From bedac898214eaf86e1ce0acc1b1f8587e0ac8438 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Fri, 14 Nov 2025 18:54:35 +0100 Subject: [PATCH] Move omniauthable to a concern --- .env.template | 50 ----------------------------- CHANGELOG.md | 1 - Gemfile | 2 +- Gemfile.lock | 21 +++++++++++- app/models/concerns/omniauthable.rb | 40 +++++++++++++++++++++++ app/models/user.rb | 34 +------------------- app/views/settings/index.html.erb | 5 +-- config/initializers/devise.rb | 4 +-- config/initializers/omniauth.rb | 4 --- docker/.env.example | 46 ++++++++++++++++++++++++++ 10 files changed, 111 insertions(+), 96 deletions(-) create mode 100644 app/models/concerns/omniauthable.rb delete mode 100644 config/initializers/omniauth.rb diff --git a/.env.template b/.env.template index c53818ae..e69de29b 100644 --- a/.env.template +++ b/.env.template @@ -1,50 +0,0 @@ -# OAuth Configuration - -# GitHub OAuth -GITHUB_OAUTH_CLIENT_ID= -GITHUB_OAUTH_CLIENT_SECRET= - -# Google OAuth2 -GOOGLE_OAUTH_CLIENT_ID= -GOOGLE_OAUTH_CLIENT_SECRET= - -# Generic OpenID Connect (for Authelia, Authentik, Keycloak, etc.) -# Option 1: Using OIDC Discovery (Recommended) -# Set OIDC_ISSUER to your provider's issuer URL (e.g., https://auth.example.com) -# The provider must support OpenID Connect Discovery (.well-known/openid-configuration) -OIDC_CLIENT_ID= -OIDC_CLIENT_SECRET= -OIDC_ISSUER= -OIDC_REDIRECT_URI= - -# Option 2: Manual Endpoint Configuration (if discovery is not supported) -# Use this if your provider doesn't support OIDC discovery -# OIDC_CLIENT_ID= -# OIDC_CLIENT_SECRET= -# OIDC_HOST=auth.example.com -# OIDC_SCHEME=https -# OIDC_PORT=443 -# OIDC_AUTHORIZATION_ENDPOINT=/authorize -# OIDC_TOKEN_ENDPOINT=/token -# OIDC_USERINFO_ENDPOINT=/userinfo -# OIDC_REDIRECT_URI=https://yourdomain.com/users/auth/openid_connect/callback - -# Example configurations: -# -# Authelia: -# OIDC_ISSUER=https://auth.example.com -# OIDC_CLIENT_ID=your-client-id -# OIDC_CLIENT_SECRET=your-client-secret -# OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback -# -# Authentik: -# OIDC_ISSUER=https://authentik.example.com/application/o/dawarich/ -# OIDC_CLIENT_ID=your-client-id -# OIDC_CLIENT_SECRET=your-client-secret -# OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback -# -# Keycloak: -# OIDC_ISSUER=https://keycloak.example.com/realms/your-realm -# OIDC_CLIENT_ID=dawarich -# OIDC_CLIENT_SECRET=your-client-secret -# OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback diff --git a/CHANGELOG.md b/CHANGELOG.md index d0c5e380..5e79c617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Implemented authentication via GitHub and Google for Dawarich Cloud. - Implemented OpenID Connect authentication for self-hosted Dawarich instances. #66 -- Added Patreon OAuth integration for Dawarich Cloud, allowing users to connect their Patreon accounts in account settings. ## TODO: diff --git a/Gemfile b/Gemfile index 219fa0e2..36cf0d9c 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby File.read('.ruby-version').strip -gem 'activerecord-postgis-adapter', '~> 11.0' +gem 'activerecord-postgis-adapter', '11.0' # https://meta.discourse.org/t/cant-rebuild-due-to-aws-sdk-gem-bump-and-new-aws-data-integrity-protections/354217/40 gem 'aws-sdk-core', '~> 3.215.1', require: false gem 'aws-sdk-kms', '~> 1.96.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index dadaade0..a32eb801 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,6 +110,7 @@ GEM bcrypt (3.1.20) benchmark (0.4.1) bigdecimal (3.3.1) + bindata (2.5.1) bootsnap (1.18.6) msgpack (~> 1.2) brakeman (7.1.0) @@ -163,6 +164,8 @@ GEM dotenv (= 3.1.8) railties (>= 6.1) drb (2.2.3) + email_validator (2.2.4) + activemodel erb (5.1.3) erubi (1.13.1) et-orbi (1.4.0) @@ -384,6 +387,17 @@ GEM raabro (1.4.0) racc (1.8.1) rack (3.2.3) + rack-oauth2 (2.3.0) + activesupport + attr_required + faraday (~> 2.0) + faraday-follow_redirects + json-jwt (>= 1.11.0) + rack (>= 2.1.0) + rack-protection (4.2.1) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) @@ -558,6 +572,11 @@ GEM attr_extras (>= 6.2.4) diff-lcs patience_diff + swd (2.0.3) + activesupport (>= 3) + attr_required (>= 0.0.5) + faraday (~> 2.0) + faraday-follow_redirects tailwindcss-rails (3.3.2) railties (>= 7.0.0) tailwindcss-ruby (~> 3.0) @@ -614,7 +633,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - activerecord-postgis-adapter (~> 11.0) + activerecord-postgis-adapter (= 11.0) aws-sdk-core (~> 3.215.1) aws-sdk-kms (~> 1.96.0) aws-sdk-s3 (~> 1.177.0) diff --git a/app/models/concerns/omniauthable.rb b/app/models/concerns/omniauthable.rb new file mode 100644 index 00000000..29e09c3d --- /dev/null +++ b/app/models/concerns/omniauthable.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Omniauthable + extend ActiveSupport::Concern + + class_methods do + def from_omniauth(access_token) + data = access_token.info + provider = access_token.provider + uid = access_token.uid + + # First, try to find user by provider and uid (for linked accounts) + user = find_by(provider: provider, uid: uid) + + if user + # User found by provider/uid + return user + end + + # If not found, try to find by email + user = find_by(email: data['email']) + + if user + # Update provider and uid for existing user (first-time linking) + user.update(provider: provider, uid: uid) + return user + end + + # Create new user if not found + user = create( + email: data['email'], + password: Devise.friendly_token[0, 20], + provider: provider, + uid: uid + ) + + user + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 8a44e379..d328cb20 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,6 +2,7 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength include UserFamily + include Omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :trackable, @@ -147,39 +148,6 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength points.where.not(city: [nil, '']).distinct.pluck(:city).compact end - def self.from_omniauth(access_token) - data = access_token.info - provider = access_token.provider - uid = access_token.uid - - # First, try to find user by provider and uid (for linked accounts) - user = User.find_by(provider: provider, uid: uid) - - if user - # User found by provider/uid - return user - end - - # If not found, try to find by email - user = User.find_by(email: data['email']) - - if user - # Update provider and uid for existing user (first-time linking) - user.update(provider: provider, uid: uid) - return user - end - - # Create new user if not found - user = User.create( - email: data['email'], - password: Devise.friendly_token[0, 20], - provider: provider, - uid: uid - ) - - user - end - private def create_api_key diff --git a/app/views/settings/index.html.erb b/app/views/settings/index.html.erb index 7b412fa8..3653fe56 100644 --- a/app/views/settings/index.html.erb +++ b/app/views/settings/index.html.erb @@ -72,10 +72,7 @@ <% unless DawarichSettings.self_hosted? %>

- - - - Connected Accounts + <%= icon 'link', class: "h-6 w-6 text-info-content" %>Connected Accounts

diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 2deaf387..51e15216 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -266,8 +266,8 @@ Devise.setup do |config| # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. - # Cloud version: only GitHub, Google, and Patreon OAuth (when env vars present) - unless SELF_HOSTED + # Cloud version: only GitHub, Google (when env vars present) + if !SELF_HOSTED if ENV['GITHUB_OAUTH_CLIENT_ID'].present? && ENV['GITHUB_OAUTH_CLIENT_SECRET'].present? config.omniauth :github, ENV['GITHUB_OAUTH_CLIENT_ID'], ENV['GITHUB_OAUTH_CLIENT_SECRET'], scope: 'user:email' Rails.logger.info 'OAuth: GitHub configured' diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb deleted file mode 100644 index aa158eb6..00000000 --- a/config/initializers/omniauth.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -# Load custom OmniAuth strategies -# (none currently needed) diff --git a/docker/.env.example b/docker/.env.example index 008b2af6..afc8625c 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -139,3 +139,49 @@ APP_MEMORY_LIMIT=4G # SECRET_KEY_BASE=your-generated-secret-key # SELF_HOSTED=true # PROMETHEUS_EXPORTER_ENABLED=true + +# ============================================================================= +# Example of configuration for OpenID Connect (OIDC) authentication +# +# ============================================================================= + +# Generic OpenID Connect (for Authelia, Authentik, Keycloak, etc.) +# Option 1: Using OIDC Discovery (Recommended) +# Set OIDC_ISSUER to your provider's issuer URL (e.g., https://auth.example.com) +# The provider must support OpenID Connect Discovery (.well-known/openid-configuration) +OIDC_CLIENT_ID= +OIDC_CLIENT_SECRET= +OIDC_ISSUER= +OIDC_REDIRECT_URI= + +# Option 2: Manual Endpoint Configuration (if discovery is not supported) +# Use this if your provider doesn't support OIDC discovery +# OIDC_CLIENT_ID= +# OIDC_CLIENT_SECRET= +# OIDC_HOST=auth.example.com +# OIDC_SCHEME=https +# OIDC_PORT=443 +# OIDC_AUTHORIZATION_ENDPOINT=/authorize +# OIDC_TOKEN_ENDPOINT=/token +# OIDC_USERINFO_ENDPOINT=/userinfo +# OIDC_REDIRECT_URI=https://yourdomain.com/users/auth/openid_connect/callback + +# Example configurations: +# +# Authelia: +# OIDC_ISSUER=https://auth.example.com +# OIDC_CLIENT_ID=your-client-id +# OIDC_CLIENT_SECRET=your-client-secret +# OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback +# +# Authentik: +# OIDC_ISSUER=https://authentik.example.com/application/o/dawarich/ +# OIDC_CLIENT_ID=your-client-id +# OIDC_CLIENT_SECRET=your-client-secret +# OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback +# +# Keycloak: +# OIDC_ISSUER=https://keycloak.example.com/realms/your-realm +# OIDC_CLIENT_ID=dawarich +# OIDC_CLIENT_SECRET=your-client-secret +# OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback