FEATURE: Login with Discord (#8053)
This migrates the functionality of discourse-plugin-discord-auth into core.
The plugin will automatically disable itself when core is updated: fd0867844d
?w=1
For setup instructions, visit https://meta.discourse.org/t/configuring-discord-login-for-discourse/127129
This commit is contained in:
parent
ac7d68a745
commit
be96c4478e
|
@ -231,6 +231,12 @@
|
|||
background: lighten($github, 20%);
|
||||
}
|
||||
}
|
||||
&.discord {
|
||||
background: $discord;
|
||||
&:hover {
|
||||
background: darken($discord, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button Sizes
|
||||
|
|
|
@ -23,6 +23,7 @@ $facebook: #4267b2 !default;
|
|||
$cas: #70ba61 !default;
|
||||
$twitter: #1da1f2 !default;
|
||||
$github: #100e0f !default;
|
||||
$discord: #7289da !default;
|
||||
|
||||
// Badge color variables
|
||||
// --------------------------------------------------
|
||||
|
|
|
@ -1469,6 +1469,10 @@ en:
|
|||
name: "GitHub"
|
||||
title: "with GitHub"
|
||||
message: "Authenticating with GitHub (make sure pop up blockers are not enabled)"
|
||||
discord:
|
||||
name: "Discord"
|
||||
title: "with Discord"
|
||||
message: "Authenticating with Discord"
|
||||
invites:
|
||||
accept_title: "Invitation"
|
||||
welcome_to: "Welcome to %{site_name}!"
|
||||
|
|
|
@ -1551,6 +1551,11 @@ en:
|
|||
github_client_id: "Client id for Github authentication, registered at <a href='https://github.com/settings/developers/' target='_blank'>https://github.com/settings/developers</a>"
|
||||
github_client_secret: "Client secret for Github authentication, registered at <a href='https://github.com/settings/developers/' target='_blank'>https://github.com/settings/developers</a>"
|
||||
|
||||
enable_discord_logins: 'Allow users to authenticate using Discord?'
|
||||
discord_client_id: 'Discord Client ID (need one? visit <a href="https://discordapp.com/developers/applications/me">the Discord developer portal</a>)'
|
||||
discord_secret: 'Discord Secret Key'
|
||||
discord_trusted_guilds: 'Only allow members of these Discord guilds to login via Discord. Use the numeric ID for the guild. For more information, check the instructions <a href="https://meta.discourse.org/t/configuring-discord-login-for-discourse/127129">here</a>. Leave blank to allow any guild.'
|
||||
|
||||
readonly_mode_during_backup: "Enable read only mode while taking a backup"
|
||||
enable_backups: "Allow administrators to create backups of the forum"
|
||||
allow_restore: "Allow restore, which can replace ALL site data! Leave false unless you plan to restore a backup"
|
||||
|
@ -4569,3 +4574,6 @@ en:
|
|||
|
||||
email_style:
|
||||
html_missing_placeholder: "The html template must include %{placeholder}"
|
||||
|
||||
discord:
|
||||
not_in_allowed_guild: 'Authentication failed. You are not a member of a permitted Discord guild.'
|
|
@ -390,6 +390,16 @@ login:
|
|||
default: ""
|
||||
regex: "^[a-f0-9]+$"
|
||||
secret: true
|
||||
enable_discord_logins:
|
||||
default: false
|
||||
discord_client_id:
|
||||
default: ''
|
||||
discord_secret:
|
||||
default: ''
|
||||
secret: true
|
||||
discord_trusted_guilds:
|
||||
default: ''
|
||||
type: list
|
||||
enable_sso:
|
||||
client: true
|
||||
default: false
|
||||
|
|
|
@ -12,3 +12,4 @@ require_dependency 'auth/github_authenticator'
|
|||
require_dependency 'auth/twitter_authenticator'
|
||||
require_dependency 'auth/google_oauth2_authenticator'
|
||||
require_dependency 'auth/instagram_authenticator'
|
||||
require_dependency 'auth/discord_authenticator'
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Auth::DiscordAuthenticator < Auth::ManagedAuthenticator
|
||||
class DiscordStrategy < OmniAuth::Strategies::OAuth2
|
||||
option :name, 'discord'
|
||||
option :scope, 'identify email guilds'
|
||||
|
||||
option :client_options,
|
||||
site: 'https://discordapp.com/api',
|
||||
authorize_url: 'oauth2/authorize',
|
||||
token_url: 'oauth2/token'
|
||||
|
||||
option :authorize_options, %i[scope permissions]
|
||||
|
||||
uid { raw_info['id'] }
|
||||
|
||||
info do
|
||||
{
|
||||
name: raw_info['username'],
|
||||
email: raw_info['verified'] ? raw_info['email'] : nil,
|
||||
image: "https://cdn.discordapp.com/avatars/#{raw_info['id']}/#{raw_info['avatar']}"
|
||||
}
|
||||
end
|
||||
|
||||
extra do
|
||||
{
|
||||
'raw_info' => raw_info
|
||||
}
|
||||
end
|
||||
|
||||
def raw_info
|
||||
@raw_info ||= access_token.get('users/@me').parsed.
|
||||
merge(guilds: access_token.get('users/@me/guilds').parsed)
|
||||
end
|
||||
|
||||
def callback_url
|
||||
full_host + script_name + callback_path
|
||||
end
|
||||
end
|
||||
|
||||
def name
|
||||
'discord'
|
||||
end
|
||||
|
||||
def enabled?
|
||||
SiteSetting.enable_discord_logins?
|
||||
end
|
||||
|
||||
def register_middleware(omniauth)
|
||||
omniauth.provider DiscordStrategy,
|
||||
setup: lambda { |env|
|
||||
strategy = env["omniauth.strategy"]
|
||||
strategy.options[:client_id] = SiteSetting.discord_client_id
|
||||
strategy.options[:client_secret] = SiteSetting.discord_secret
|
||||
}
|
||||
end
|
||||
|
||||
def after_authenticate(auth_token, existing_account: nil)
|
||||
allowed_guild_ids = SiteSetting.discord_trusted_guilds.split("|")
|
||||
|
||||
if allowed_guild_ids.length > 0
|
||||
user_guild_ids = auth_token.extra[:raw_info][:guilds].map { |g| g['id'] }
|
||||
if (user_guild_ids & allowed_guild_ids).empty? # User is not in any allowed guilds
|
||||
return Auth::Result.new.tap do |auth_result|
|
||||
auth_result.failed = true
|
||||
auth_result.failed_reason = I18n.t("discord.not_in_allowed_guild")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
end
|
|
@ -254,7 +254,8 @@ module Discourse
|
|||
Auth::AuthProvider.new(authenticator: Auth::GoogleOAuth2Authenticator.new, frame_width: 850, frame_height: 500), # Custom icon implemented in client
|
||||
Auth::AuthProvider.new(authenticator: Auth::GithubAuthenticator.new, icon: "fab-github"),
|
||||
Auth::AuthProvider.new(authenticator: Auth::TwitterAuthenticator.new, icon: "fab-twitter"),
|
||||
Auth::AuthProvider.new(authenticator: Auth::InstagramAuthenticator.new, icon: "fab-instagram")
|
||||
Auth::AuthProvider.new(authenticator: Auth::InstagramAuthenticator.new, icon: "fab-instagram"),
|
||||
Auth::AuthProvider.new(authenticator: Auth::DiscordAuthenticator.new, icon: "fab-discord", full_screen_login: true)
|
||||
]
|
||||
|
||||
def self.auth_providers
|
||||
|
|
|
@ -71,6 +71,7 @@ module SvgSprite
|
|||
"fab-android",
|
||||
"fab-apple",
|
||||
"fab-chrome",
|
||||
"fab-discord",
|
||||
"fab-discourse",
|
||||
"fab-facebook-square",
|
||||
"fab-facebook",
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Auth::DiscordAuthenticator do
|
||||
let(:hash) {
|
||||
OmniAuth::AuthHash.new(
|
||||
provider: "facebook",
|
||||
extra: {
|
||||
raw_info: {
|
||||
id: "100",
|
||||
username: "bobbob",
|
||||
guilds: [
|
||||
{
|
||||
"id": "80351110224678912",
|
||||
"name": "1337 Krew",
|
||||
"icon": "8342729096ea3675442027381ff50dfe",
|
||||
"owner": true,
|
||||
"permissions": 36953089
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
info: {
|
||||
email: "bob@bob.com",
|
||||
name: "bobbob"
|
||||
},
|
||||
uid: "100"
|
||||
)
|
||||
}
|
||||
|
||||
let(:authenticator) { described_class.new }
|
||||
|
||||
context 'after_authenticate' do
|
||||
it 'works normally' do
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user).to eq(nil)
|
||||
expect(result.failed).to eq(false)
|
||||
expect(result.name).to eq("bobbob")
|
||||
expect(result.email).to eq("bob@bob.com")
|
||||
end
|
||||
|
||||
it 'denies access when guilds are restricted' do
|
||||
SiteSetting.discord_trusted_guilds = ["someguildid", "someotherguildid"].join("|")
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user).to eq(nil)
|
||||
expect(result.failed).to eq(true)
|
||||
expect(result.failed_reason).to eq(I18n.t("discord.not_in_allowed_guild"))
|
||||
end
|
||||
|
||||
it 'allows access when in an allowed guild' do
|
||||
SiteSetting.discord_trusted_guilds = ["80351110224678912", "anothertrustedguild"].join("|")
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user).to eq(nil)
|
||||
expect(result.failed).to eq(false)
|
||||
expect(result.name).to eq("bobbob")
|
||||
expect(result.email).to eq("bob@bob.com")
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue