DEV: Apply syntax_tree formatting to lib/*

This commit is contained in:
David Taylor
2023-01-09 12:10:19 +00:00
parent b0fda61a8e
commit 6417173082
507 changed files with 16550 additions and 12627 deletions

View File

@@ -8,32 +8,60 @@ class Auth::AuthProvider
end
def self.auth_attributes
[:authenticator, :pretty_name, :title, :message, :frame_width, :frame_height,
:pretty_name_setting, :title_setting, :enabled_setting, :full_screen_login, :full_screen_login_setting,
:custom_url, :background_color, :icon]
%i[
authenticator
pretty_name
title
message
frame_width
frame_height
pretty_name_setting
title_setting
enabled_setting
full_screen_login
full_screen_login_setting
custom_url
background_color
icon
]
end
attr_accessor(*auth_attributes)
def enabled_setting=(val)
Discourse.deprecate("(#{authenticator.name}) enabled_setting is deprecated. Please define authenticator.enabled? instead", drop_from: '2.9.0')
Discourse.deprecate(
"(#{authenticator.name}) enabled_setting is deprecated. Please define authenticator.enabled? instead",
drop_from: "2.9.0",
)
@enabled_setting = val
end
def background_color=(val)
Discourse.deprecate("(#{authenticator.name}) background_color is no longer functional. Please use CSS instead", drop_from: '2.9.0')
Discourse.deprecate(
"(#{authenticator.name}) background_color is no longer functional. Please use CSS instead",
drop_from: "2.9.0",
)
end
def full_screen_login=(val)
Discourse.deprecate("(#{authenticator.name}) full_screen_login is now forced. The full_screen_login parameter can be removed from the auth_provider.", drop_from: '2.9.0')
Discourse.deprecate(
"(#{authenticator.name}) full_screen_login is now forced. The full_screen_login parameter can be removed from the auth_provider.",
drop_from: "2.9.0",
)
end
def full_screen_login_setting=(val)
Discourse.deprecate("(#{authenticator.name}) full_screen_login is now forced. The full_screen_login_setting parameter can be removed from the auth_provider.", drop_from: '2.9.0')
Discourse.deprecate(
"(#{authenticator.name}) full_screen_login is now forced. The full_screen_login_setting parameter can be removed from the auth_provider.",
drop_from: "2.9.0",
)
end
def message=(val)
Discourse.deprecate("(#{authenticator.name}) message is no longer used because all logins are full screen. It should be removed from the auth_provider", drop_from: '2.9.0')
Discourse.deprecate(
"(#{authenticator.name}) message is no longer used because all logins are full screen. It should be removed from the auth_provider",
drop_from: "2.9.0",
)
end
def name
@@ -47,5 +75,4 @@ class Auth::AuthProvider
def can_revoke
authenticator.can_revoke?
end
end

View File

@@ -1,8 +1,8 @@
# frozen_string_literal: true
module Auth; end
module Auth
end
class Auth::CurrentUserProvider
# do all current user initialization here
def initialize(env)
raise NotImplementedError

View File

@@ -1,5 +1,5 @@
# frozen_string_literal: true
require_relative '../route_matcher'
require_relative "../route_matcher"
# You may have seen references to v0 and v1 of our auth cookie in the codebase
# and you're not sure how they differ, so here is an explanation:
@@ -23,7 +23,6 @@ require_relative '../route_matcher'
# We'll drop support for v0 after Discourse 2.9 is released.
class Auth::DefaultCurrentUserProvider
CURRENT_USER_KEY ||= "_DISCOURSE_CURRENT_USER"
USER_TOKEN_KEY ||= "_DISCOURSE_USER_TOKEN"
API_KEY ||= "api_key"
@@ -37,7 +36,7 @@ class Auth::DefaultCurrentUserProvider
USER_API_CLIENT_ID ||= "HTTP_USER_API_CLIENT_ID"
API_KEY_ENV ||= "_DISCOURSE_API"
USER_API_KEY_ENV ||= "_DISCOURSE_USER_API"
TOKEN_COOKIE ||= ENV['DISCOURSE_TOKEN_COOKIE'] || "_t"
TOKEN_COOKIE ||= ENV["DISCOURSE_TOKEN_COOKIE"] || "_t"
PATH_INFO ||= "PATH_INFO"
COOKIE_ATTEMPTS_PER_MIN ||= 10
BAD_TOKEN ||= "_DISCOURSE_BAD_TOKEN"
@@ -59,30 +58,20 @@ class Auth::DefaultCurrentUserProvider
"badges#show",
"tags#tag_feed",
"tags#show",
*[:latest, :unread, :new, :read, :posted, :bookmarks].map { |f| "list##{f}_feed" },
*[:all, :yearly, :quarterly, :monthly, :weekly, :daily].map { |p| "list#top_#{p}_feed" },
*[:latest, :unread, :new, :read, :posted, :bookmarks].map { |f| "tags#show_#{f}" }
*%i[latest unread new read posted bookmarks].map { |f| "list##{f}_feed" },
*%i[all yearly quarterly monthly weekly daily].map { |p| "list#top_#{p}_feed" },
*%i[latest unread new read posted bookmarks].map { |f| "tags#show_#{f}" },
],
formats: :rss
),
RouteMatcher.new(
methods: :get,
actions: "users#bookmarks",
formats: :ics
),
RouteMatcher.new(
methods: :post,
actions: "admin/email#handle_mail",
formats: nil
formats: :rss,
),
RouteMatcher.new(methods: :get, actions: "users#bookmarks", formats: :ics),
RouteMatcher.new(methods: :post, actions: "admin/email#handle_mail", formats: nil),
]
def self.find_v0_auth_cookie(request)
cookie = request.cookies[TOKEN_COOKIE]
if cookie&.valid_encoding? && cookie.present? && cookie.size == TOKEN_SIZE
cookie
end
cookie if cookie&.valid_encoding? && cookie.present? && cookie.size == TOKEN_SIZE
end
def self.find_v1_auth_cookie(env)
@@ -111,12 +100,10 @@ class Auth::DefaultCurrentUserProvider
return @env[CURRENT_USER_KEY] if @env.key?(CURRENT_USER_KEY)
# bypass if we have the shared session header
if shared_key = @env['HTTP_X_SHARED_SESSION_KEY']
if shared_key = @env["HTTP_X_SHARED_SESSION_KEY"]
uid = Discourse.redis.get("shared_session_key_#{shared_key}")
user = nil
if uid
user = User.find_by(id: uid.to_i)
end
user = User.find_by(id: uid.to_i) if uid
@env[CURRENT_USER_KEY] = user
return user
end
@@ -130,28 +117,27 @@ class Auth::DefaultCurrentUserProvider
user_api_key ||= request[PARAMETER_USER_API_KEY]
end
if !@env.blank? && request[API_KEY] && api_parameter_allowed?
api_key ||= request[API_KEY]
end
api_key ||= request[API_KEY] if !@env.blank? && request[API_KEY] && api_parameter_allowed?
auth_token = find_auth_token
current_user = nil
if auth_token
limiter = RateLimiter.new(nil, "cookie_auth_#{request.ip}", COOKIE_ATTEMPTS_PER_MIN , 60)
limiter = RateLimiter.new(nil, "cookie_auth_#{request.ip}", COOKIE_ATTEMPTS_PER_MIN, 60)
if limiter.can_perform?
@env[USER_TOKEN_KEY] = @user_token = begin
UserAuthToken.lookup(
auth_token,
seen: true,
user_agent: @env['HTTP_USER_AGENT'],
path: @env['REQUEST_PATH'],
client_ip: @request.ip
)
rescue ActiveRecord::ReadOnlyError
nil
end
@env[USER_TOKEN_KEY] = @user_token =
begin
UserAuthToken.lookup(
auth_token,
seen: true,
user_agent: @env["HTTP_USER_AGENT"],
path: @env["REQUEST_PATH"],
client_ip: @request.ip,
)
rescue ActiveRecord::ReadOnlyError
nil
end
current_user = @user_token.try(:user)
end
@@ -161,14 +147,10 @@ class Auth::DefaultCurrentUserProvider
begin
limiter.performed!
rescue RateLimiter::LimitExceeded
raise Discourse::InvalidAccess.new(
'Invalid Access',
nil,
delete_cookie: TOKEN_COOKIE
)
raise Discourse::InvalidAccess.new("Invalid Access", nil, delete_cookie: TOKEN_COOKIE)
end
end
elsif @env['HTTP_DISCOURSE_LOGGED_IN']
elsif @env["HTTP_DISCOURSE_LOGGED_IN"]
@env[BAD_TOKEN] = true
end
@@ -177,10 +159,10 @@ class Auth::DefaultCurrentUserProvider
current_user = lookup_api_user(api_key, request)
if !current_user
raise Discourse::InvalidAccess.new(
I18n.t('invalid_api_credentials'),
nil,
custom_message: "invalid_api_credentials"
)
I18n.t("invalid_api_credentials"),
nil,
custom_message: "invalid_api_credentials",
)
end
raise Discourse::InvalidAccess if current_user.suspended? || !current_user.active
admin_api_key_limiter.performed! if !Rails.env.profile?
@@ -191,12 +173,13 @@ class Auth::DefaultCurrentUserProvider
if user_api_key
@hashed_user_api_key = ApiKey.hash_key(user_api_key)
user_api_key_obj = UserApiKey
.active
.joins(:user)
.where(key_hash: @hashed_user_api_key)
.includes(:user, :scopes)
.first
user_api_key_obj =
UserApiKey
.active
.joins(:user)
.where(key_hash: @hashed_user_api_key)
.includes(:user, :scopes)
.first
raise Discourse::InvalidAccess unless user_api_key_obj
@@ -208,18 +191,14 @@ class Auth::DefaultCurrentUserProvider
current_user = user_api_key_obj.user
raise Discourse::InvalidAccess if current_user.suspended? || !current_user.active
if can_write?
user_api_key_obj.update_last_used(@env[USER_API_CLIENT_ID])
end
user_api_key_obj.update_last_used(@env[USER_API_CLIENT_ID]) if can_write?
@env[USER_API_KEY_ENV] = true
end
# keep this rule here as a safeguard
# under no conditions to suspended or inactive accounts get current_user
if current_user && (current_user.suspended? || !current_user.active)
current_user = nil
end
current_user = nil if current_user && (current_user.suspended? || !current_user.active)
if current_user && should_update_last_seen?
ip = request.ip
@@ -247,31 +226,40 @@ class Auth::DefaultCurrentUserProvider
if !is_user_api? && @user_token && @user_token.user == user
rotated_at = @user_token.rotated_at
needs_rotation = @user_token.auth_token_seen ? rotated_at < UserAuthToken::ROTATE_TIME.ago : rotated_at < UserAuthToken::URGENT_ROTATE_TIME.ago
needs_rotation =
(
if @user_token.auth_token_seen
rotated_at < UserAuthToken::ROTATE_TIME.ago
else
rotated_at < UserAuthToken::URGENT_ROTATE_TIME.ago
end
)
if needs_rotation
if @user_token.rotate!(user_agent: @env['HTTP_USER_AGENT'],
client_ip: @request.ip,
path: @env['REQUEST_PATH'])
if @user_token.rotate!(
user_agent: @env["HTTP_USER_AGENT"],
client_ip: @request.ip,
path: @env["REQUEST_PATH"],
)
set_auth_cookie!(@user_token.unhashed_auth_token, user, cookie_jar)
DiscourseEvent.trigger(:user_session_refreshed, user)
end
end
end
if !user && cookie_jar.key?(TOKEN_COOKIE)
cookie_jar.delete(TOKEN_COOKIE)
end
cookie_jar.delete(TOKEN_COOKIE) if !user && cookie_jar.key?(TOKEN_COOKIE)
end
def log_on_user(user, session, cookie_jar, opts = {})
@env[USER_TOKEN_KEY] = @user_token = UserAuthToken.generate!(
user_id: user.id,
user_agent: @env['HTTP_USER_AGENT'],
path: @env['REQUEST_PATH'],
client_ip: @request.ip,
staff: user.staff?,
impersonate: opts[:impersonate])
@env[USER_TOKEN_KEY] = @user_token =
UserAuthToken.generate!(
user_id: user.id,
user_agent: @env["HTTP_USER_AGENT"],
path: @env["REQUEST_PATH"],
client_ip: @request.ip,
staff: user.staff?,
impersonate: opts[:impersonate],
)
set_auth_cookie!(@user_token.unhashed_auth_token, user, cookie_jar)
user.unstage!
@@ -288,23 +276,19 @@ class Auth::DefaultCurrentUserProvider
token: unhashed_auth_token,
user_id: user.id,
trust_level: user.trust_level,
issued_at: Time.zone.now.to_i
issued_at: Time.zone.now.to_i,
}
if SiteSetting.persistent_sessions
expires = SiteSetting.maximum_session_age.hours.from_now
end
expires = SiteSetting.maximum_session_age.hours.from_now if SiteSetting.persistent_sessions
if SiteSetting.same_site_cookies != "Disabled"
same_site = SiteSetting.same_site_cookies
end
same_site = SiteSetting.same_site_cookies if SiteSetting.same_site_cookies != "Disabled"
cookie_jar.encrypted[TOKEN_COOKIE] = {
value: data,
httponly: true,
secure: SiteSetting.force_https,
expires: expires,
same_site: same_site
same_site: same_site,
}
end
@@ -313,10 +297,8 @@ class Auth::DefaultCurrentUserProvider
# for signup flow, since all admin emails are stored in
# DISCOURSE_DEVELOPER_EMAILS for self-hosters.
def make_developer_admin(user)
if user.active? &&
!user.admin &&
Rails.configuration.respond_to?(:developer_emails) &&
Rails.configuration.developer_emails.include?(user.email)
if user.active? && !user.admin && Rails.configuration.respond_to?(:developer_emails) &&
Rails.configuration.developer_emails.include?(user.email)
user.admin = true
user.save
Group.refresh_automatic_groups!(:staff, :admins)
@@ -347,7 +329,7 @@ class Auth::DefaultCurrentUserProvider
@user_token.destroy
end
cookie_jar.delete('authentication_data')
cookie_jar.delete("authentication_data")
cookie_jar.delete(TOKEN_COOKIE)
end
@@ -384,9 +366,7 @@ class Auth::DefaultCurrentUserProvider
if api_key = ApiKey.active.with_key(api_key_value).includes(:user).first
api_username = header_api_key? ? @env[HEADER_API_USERNAME] : request[API_USERNAME]
if !api_key.request_allowed?(@env)
return nil
end
return nil if !api_key.request_allowed?(@env)
user =
if api_key.user
@@ -395,7 +375,8 @@ class Auth::DefaultCurrentUserProvider
User.find_by(username_lower: api_username.downcase)
elsif user_id = header_api_key? ? @env[HEADER_API_USER_ID] : request["api_user_id"]
User.find_by(id: user_id.to_i)
elsif external_id = header_api_key? ? @env[HEADER_API_USER_EXTERNAL_ID] : request["api_user_external_id"]
elsif external_id =
header_api_key? ? @env[HEADER_API_USER_EXTERNAL_ID] : request["api_user_external_id"]
SingleSignOnRecord.find_by(external_id: external_id.to_s).try(:user)
end
@@ -435,52 +416,48 @@ class Auth::DefaultCurrentUserProvider
limit = GlobalSetting.max_admin_api_reqs_per_minute.to_i
if GlobalSetting.respond_to?(:max_admin_api_reqs_per_key_per_minute)
Discourse.deprecate("DISCOURSE_MAX_ADMIN_API_REQS_PER_KEY_PER_MINUTE is deprecated. Please use DISCOURSE_MAX_ADMIN_API_REQS_PER_MINUTE", drop_from: '2.9.0')
limit = [
GlobalSetting.max_admin_api_reqs_per_key_per_minute.to_i,
limit
].max
Discourse.deprecate(
"DISCOURSE_MAX_ADMIN_API_REQS_PER_KEY_PER_MINUTE is deprecated. Please use DISCOURSE_MAX_ADMIN_API_REQS_PER_MINUTE",
drop_from: "2.9.0",
)
limit = [GlobalSetting.max_admin_api_reqs_per_key_per_minute.to_i, limit].max
end
@admin_api_key_limiter = RateLimiter.new(
nil,
"admin_api_min",
limit,
60,
error_code: "admin_api_key_rate_limit"
)
@admin_api_key_limiter =
RateLimiter.new(nil, "admin_api_min", limit, 60, error_code: "admin_api_key_rate_limit")
end
def user_api_key_limiter_60_secs
@user_api_key_limiter_60_secs ||= RateLimiter.new(
nil,
"user_api_min_#{@hashed_user_api_key}",
GlobalSetting.max_user_api_reqs_per_minute,
60,
error_code: "user_api_key_limiter_60_secs"
)
@user_api_key_limiter_60_secs ||=
RateLimiter.new(
nil,
"user_api_min_#{@hashed_user_api_key}",
GlobalSetting.max_user_api_reqs_per_minute,
60,
error_code: "user_api_key_limiter_60_secs",
)
end
def user_api_key_limiter_1_day
@user_api_key_limiter_1_day ||= RateLimiter.new(
nil,
"user_api_day_#{@hashed_user_api_key}",
GlobalSetting.max_user_api_reqs_per_day,
86400,
error_code: "user_api_key_limiter_1_day"
)
@user_api_key_limiter_1_day ||=
RateLimiter.new(
nil,
"user_api_day_#{@hashed_user_api_key}",
GlobalSetting.max_user_api_reqs_per_day,
86_400,
error_code: "user_api_key_limiter_1_day",
)
end
def find_auth_token
return @auth_token if defined?(@auth_token)
@auth_token = begin
if v0 = self.class.find_v0_auth_cookie(@request)
v0
elsif v1 = self.class.find_v1_auth_cookie(@env)
if v1[:issued_at] >= SiteSetting.maximum_session_age.hours.ago.to_i
v1[:token]
@auth_token =
begin
if v0 = self.class.find_v0_auth_cookie(@request)
v0
elsif v1 = self.class.find_v1_auth_cookie(@env)
v1[:token] if v1[:issued_at] >= SiteSetting.maximum_session_age.hours.ago.to_i
end
end
end
end
end

View File

@@ -2,35 +2,34 @@
class Auth::DiscordAuthenticator < Auth::ManagedAuthenticator
class DiscordStrategy < OmniAuth::Strategies::OAuth2
option :name, 'discord'
option :scope, 'identify email guilds'
option :name, "discord"
option :scope, "identify email guilds"
option :client_options,
site: 'https://discord.com/api',
authorize_url: 'oauth2/authorize',
token_url: 'oauth2/token'
site: "https://discord.com/api",
authorize_url: "oauth2/authorize",
token_url: "oauth2/token"
option :authorize_options, %i[scope permissions]
uid { raw_info['id'] }
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']}"
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
extra { { "raw_info" => raw_info } }
def raw_info
@raw_info ||= access_token.get('users/@me').parsed.
merge(guilds: access_token.get('users/@me/guilds').parsed)
@raw_info ||=
access_token
.get("users/@me")
.parsed
.merge(guilds: access_token.get("users/@me/guilds").parsed)
end
def callback_url
@@ -39,7 +38,7 @@ class Auth::DiscordAuthenticator < Auth::ManagedAuthenticator
end
def name
'discord'
"discord"
end
def enabled?
@@ -48,23 +47,26 @@ class Auth::DiscordAuthenticator < Auth::ManagedAuthenticator
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
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'] }
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
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

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
class Auth::FacebookAuthenticator < Auth::ManagedAuthenticator
AVATAR_SIZE ||= 480
def name
@@ -14,15 +13,19 @@ class Auth::FacebookAuthenticator < Auth::ManagedAuthenticator
def register_middleware(omniauth)
omniauth.provider :facebook,
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.facebook_app_id
strategy.options[:client_secret] = SiteSetting.facebook_app_secret
strategy.options[:info_fields] = 'name,first_name,last_name,email'
strategy.options[:image_size] = { width: AVATAR_SIZE, height: AVATAR_SIZE }
strategy.options[:secure_image_url] = true
},
scope: "email"
setup:
lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.facebook_app_id
strategy.options[:client_secret] = SiteSetting.facebook_app_secret
strategy.options[:info_fields] = "name,first_name,last_name,email"
strategy.options[:image_size] = {
width: AVATAR_SIZE,
height: AVATAR_SIZE,
}
strategy.options[:secure_image_url] = true
},
scope: "email"
end
# facebook doesn't return unverified email addresses so it's safe to assume

View File

@@ -1,9 +1,8 @@
# frozen_string_literal: true
require 'has_errors'
require "has_errors"
class Auth::GithubAuthenticator < Auth::ManagedAuthenticator
def name
"github"
end
@@ -50,12 +49,13 @@ class Auth::GithubAuthenticator < Auth::ManagedAuthenticator
def register_middleware(omniauth)
omniauth.provider :github,
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.github_client_id
strategy.options[:client_secret] = SiteSetting.github_client_secret
},
scope: "user:email"
setup:
lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.github_client_id
strategy.options[:client_secret] = SiteSetting.github_client_secret
},
scope: "user:email"
end
# the omniauth-github gem only picks up the primary email if it's verified:

View File

@@ -22,47 +22,46 @@ class Auth::GoogleOAuth2Authenticator < Auth::ManagedAuthenticator
def register_middleware(omniauth)
options = {
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.google_oauth2_client_id
strategy.options[:client_secret] = SiteSetting.google_oauth2_client_secret
setup:
lambda do |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.google_oauth2_client_id
strategy.options[:client_secret] = SiteSetting.google_oauth2_client_secret
if (google_oauth2_hd = SiteSetting.google_oauth2_hd).present?
strategy.options[:hd] = google_oauth2_hd
end
if (google_oauth2_hd = SiteSetting.google_oauth2_hd).present?
strategy.options[:hd] = google_oauth2_hd
end
if (google_oauth2_prompt = SiteSetting.google_oauth2_prompt).present?
strategy.options[:prompt] = google_oauth2_prompt.gsub("|", " ")
end
if (google_oauth2_prompt = SiteSetting.google_oauth2_prompt).present?
strategy.options[:prompt] = google_oauth2_prompt.gsub("|", " ")
end
# All the data we need for the `info` and `credentials` auth hash
# are obtained via the user info API, not the JWT. Using and verifying
# the JWT can fail due to clock skew, so let's skip it completely.
# https://github.com/zquestz/omniauth-google-oauth2/pull/392
strategy.options[:skip_jwt] = true
}
# All the data we need for the `info` and `credentials` auth hash
# are obtained via the user info API, not the JWT. Using and verifying
# the JWT can fail due to clock skew, so let's skip it completely.
# https://github.com/zquestz/omniauth-google-oauth2/pull/392
strategy.options[:skip_jwt] = true
end,
}
omniauth.provider :google_oauth2, options
end
def after_authenticate(auth_token, existing_account: nil)
groups = provides_groups? ? raw_groups(auth_token.uid) : nil
if groups
auth_token.extra[:raw_groups] = groups
end
auth_token.extra[:raw_groups] = groups if groups
result = super
if groups
result.associated_groups = groups.map { |group| group.with_indifferent_access.slice(:id, :name) }
result.associated_groups =
groups.map { |group| group.with_indifferent_access.slice(:id, :name) }
end
result
end
def provides_groups?
SiteSetting.google_oauth2_hd.present? &&
SiteSetting.google_oauth2_hd_groups &&
SiteSetting.google_oauth2_hd.present? && SiteSetting.google_oauth2_hd_groups &&
SiteSetting.google_oauth2_hd_groups_service_account_admin_email.present? &&
SiteSetting.google_oauth2_hd_groups_service_account_json.present?
end
@@ -77,20 +76,20 @@ class Auth::GoogleOAuth2Authenticator < Auth::ManagedAuthenticator
return if client.nil?
loop do
params = {
userKey: uid
}
params = { userKey: uid }
params[:pageToken] = page_token if page_token
response = client.get(groups_url, params: params, raise_errors: false)
if response.status == 200
response = response.parsed
groups.push(*response['groups'])
page_token = response['nextPageToken']
groups.push(*response["groups"])
page_token = response["nextPageToken"]
break if page_token.nil?
else
Rails.logger.error("[Discourse Google OAuth2] failed to retrieve groups for #{uid} - status #{response.status}")
Rails.logger.error(
"[Discourse Google OAuth2] failed to retrieve groups for #{uid} - status #{response.status}",
)
break
end
end
@@ -107,26 +106,35 @@ class Auth::GoogleOAuth2Authenticator < Auth::ManagedAuthenticator
scope: GROUPS_SCOPE,
iat: Time.now.to_i,
exp: Time.now.to_i + 60,
sub: SiteSetting.google_oauth2_hd_groups_service_account_admin_email
sub: SiteSetting.google_oauth2_hd_groups_service_account_admin_email,
}
headers = { "alg" => "RS256", "typ" => "JWT" }
key = OpenSSL::PKey::RSA.new(service_account_info["private_key"])
encoded_jwt = ::JWT.encode(payload, key, 'RS256', headers)
encoded_jwt = ::JWT.encode(payload, key, "RS256", headers)
client = OAuth2::Client.new(
SiteSetting.google_oauth2_client_id,
SiteSetting.google_oauth2_client_secret,
site: OAUTH2_BASE_URL
)
client =
OAuth2::Client.new(
SiteSetting.google_oauth2_client_id,
SiteSetting.google_oauth2_client_secret,
site: OAUTH2_BASE_URL,
)
token_response = client.request(:post, '/token', body: {
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: encoded_jwt
}, raise_errors: false)
token_response =
client.request(
:post,
"/token",
body: {
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: encoded_jwt,
},
raise_errors: false,
)
if token_response.status != 200
Rails.logger.error("[Discourse Google OAuth2] failed to retrieve group fetch token - status #{token_response.status}")
Rails.logger.error(
"[Discourse Google OAuth2] failed to retrieve group fetch token - status #{token_response.status}",
)
return
end

View File

@@ -56,28 +56,27 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
def after_authenticate(auth_token, existing_account: nil)
# Try and find an association for this account
association = UserAssociatedAccount.find_or_initialize_by(provider_name: auth_token[:provider], provider_uid: auth_token[:uid])
association =
UserAssociatedAccount.find_or_initialize_by(
provider_name: auth_token[:provider],
provider_uid: auth_token[:uid],
)
# Reconnecting to existing account
if can_connect_existing_user? && existing_account && (association.user.nil? || existing_account.id != association.user_id)
if can_connect_existing_user? && existing_account &&
(association.user.nil? || existing_account.id != association.user_id)
association.user = existing_account
end
# Matching an account by email
if match_by_email &&
association.user.nil? &&
(user = find_user_by_email(auth_token))
if match_by_email && association.user.nil? && (user = find_user_by_email(auth_token))
UserAssociatedAccount.where(user: user, provider_name: auth_token[:provider]).destroy_all # Destroy existing associations for the new user
association.user = user
end
# Matching an account by username
if match_by_username &&
association.user.nil? &&
SiteSetting.username_change_period.zero? &&
(user = find_user_by_username(auth_token))
if match_by_username && association.user.nil? && SiteSetting.username_change_period.zero? &&
(user = find_user_by_username(auth_token))
UserAssociatedAccount.where(user: user, provider_name: auth_token[:provider]).destroy_all # Destroy existing associations for the new user
association.user = user
end
@@ -100,7 +99,14 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
result = Auth::Result.new
info = auth_token[:info]
result.email = info[:email]
result.name = (info[:first_name] && info[:last_name]) ? "#{info[:first_name]} #{info[:last_name]}" : info[:name]
result.name =
(
if (info[:first_name] && info[:last_name])
"#{info[:first_name]} #{info[:last_name]}"
else
info[:name]
end
)
if result.name.present? && result.name == result.email
# Some IDPs send the email address in the name parameter (e.g. Auth0 with default configuration)
# We add some generic protection here, so that users don't accidently make their email addresses public
@@ -109,10 +115,7 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
result.username = info[:nickname]
result.email_valid = primary_email_verified?(auth_token) if result.email.present?
result.overrides_email = always_update_user_email?
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid]
}
result.extra_data = { provider: auth_token[:provider], uid: auth_token[:uid] }
result.user = association.user
result
@@ -120,7 +123,11 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
def after_create_account(user, auth_result)
auth_token = auth_result[:extra_data]
association = UserAssociatedAccount.find_or_initialize_by(provider_name: auth_token[:provider], provider_uid: auth_token[:uid])
association =
UserAssociatedAccount.find_or_initialize_by(
provider_name: auth_token[:provider],
provider_uid: auth_token[:uid],
)
association.user = user
association.save!
@@ -132,16 +139,12 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
def find_user_by_email(auth_token)
email = auth_token.dig(:info, :email)
if email && primary_email_verified?(auth_token)
User.find_by_email(email)
end
User.find_by_email(email) if email && primary_email_verified?(auth_token)
end
def find_user_by_username(auth_token)
username = auth_token.dig(:info, :nickname)
if username
User.find_by_username(username)
end
User.find_by_username(username) if username
end
def retrieve_avatar(user, url)
@@ -158,7 +161,7 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
if bio || location
profile = user.user_profile
profile.bio_raw = bio unless profile.bio_raw.present?
profile.bio_raw = bio unless profile.bio_raw.present?
profile.location = location unless profile.location.present?
profile.save
end

View File

@@ -1,48 +1,48 @@
# frozen_string_literal: true
class Auth::Result
ATTRIBUTES = [
:user,
:name,
:username,
:email,
:email_valid,
:extra_data,
:awaiting_activation,
:awaiting_approval,
:authenticated,
:authenticator_name,
:requires_invite,
:not_allowed_from_ip_address,
:admin_not_allowed_from_ip_address,
:skip_email_validation,
:destination_url,
:omniauth_disallow_totp,
:failed,
:failed_reason,
:failed_code,
:associated_groups,
:overrides_email,
:overrides_username,
:overrides_name,
ATTRIBUTES = %i[
user
name
username
email
email_valid
extra_data
awaiting_activation
awaiting_approval
authenticated
authenticator_name
requires_invite
not_allowed_from_ip_address
admin_not_allowed_from_ip_address
skip_email_validation
destination_url
omniauth_disallow_totp
failed
failed_reason
failed_code
associated_groups
overrides_email
overrides_username
overrides_name
]
attr_accessor *ATTRIBUTES
# These are stored in the session during
# account creation. The user cannot read or modify them
SESSION_ATTRIBUTES = [
:email,
:username,
:email_valid,
:name,
:authenticator_name,
:extra_data,
:skip_email_validation,
:associated_groups,
:overrides_email,
:overrides_username,
:overrides_name,
SESSION_ATTRIBUTES = %i[
email
username
email_valid
name
authenticator_name
extra_data
skip_email_validation
associated_groups
overrides_email
overrides_username
overrides_name
]
def [](key)
@@ -59,9 +59,7 @@ class Auth::Result
end
def email_valid=(val)
if !val.in? [true, false, nil]
raise ArgumentError, "email_valid should be boolean or nil"
end
raise ArgumentError, "email_valid should be boolean or nil" if !val.in? [true, false, nil]
@email_valid = !!val
end
@@ -83,14 +81,14 @@ class Auth::Result
def apply_user_attributes!
change_made = false
if (SiteSetting.auth_overrides_username? || overrides_username) && (resolved_username = resolve_username).present?
if (SiteSetting.auth_overrides_username? || overrides_username) &&
(resolved_username = resolve_username).present?
change_made = UsernameChanger.override(user, resolved_username)
end
if (SiteSetting.auth_overrides_email || overrides_email || user&.email&.ends_with?(".invalid")) &&
email_valid &&
email.present? &&
user.email != Email.downcase(email)
if (
SiteSetting.auth_overrides_email || overrides_email || user&.email&.ends_with?(".invalid")
) && email_valid && email.present? && user.email != Email.downcase(email)
user.email = email
change_made = true
end
@@ -109,11 +107,12 @@ class Auth::Result
associated_groups.uniq.each do |associated_group|
begin
associated_group = AssociatedGroup.find_or_create_by(
name: associated_group[:name],
provider_id: associated_group[:id],
provider_name: extra_data[:provider]
)
associated_group =
AssociatedGroup.find_or_create_by(
name: associated_group[:name],
provider_id: associated_group[:id],
provider_name: extra_data[:provider],
)
rescue ActiveRecord::RecordNotUnique
retry
end
@@ -135,22 +134,12 @@ class Auth::Result
end
def to_client_hash
if requires_invite
return { requires_invite: true }
end
return { requires_invite: true } if requires_invite
if user&.suspended?
return {
suspended: true,
suspended_message: user.suspended_message
}
end
return { suspended: true, suspended_message: user.suspended_message } if user&.suspended?
if omniauth_disallow_totp
return {
omniauth_disallow_totp: !!omniauth_disallow_totp,
email: email
}
return { omniauth_disallow_totp: !!omniauth_disallow_totp, email: email }
end
if user
@@ -159,7 +148,7 @@ class Auth::Result
awaiting_activation: !!awaiting_activation,
awaiting_approval: !!awaiting_approval,
not_allowed_from_ip_address: !!not_allowed_from_ip_address,
admin_not_allowed_from_ip_address: !!admin_not_allowed_from_ip_address
admin_not_allowed_from_ip_address: !!admin_not_allowed_from_ip_address,
}
result[:destination_url] = destination_url if authenticated && destination_url.present?
@@ -173,7 +162,7 @@ class Auth::Result
auth_provider: authenticator_name,
email_valid: !!email_valid,
can_edit_username: can_edit_username,
can_edit_name: can_edit_name
can_edit_name: can_edit_name,
}
result[:destination_url] = destination_url if destination_url.present?
@@ -190,9 +179,7 @@ class Auth::Result
def staged_user
return @staged_user if defined?(@staged_user)
if email.present? && email_valid
@staged_user = User.where(staged: true).find_by_email(email)
end
@staged_user = User.where(staged: true).find_by_email(email) if email.present? && email_valid
end
def username_suggester_attributes

View File

@@ -17,11 +17,12 @@ class Auth::TwitterAuthenticator < Auth::ManagedAuthenticator
def register_middleware(omniauth)
omniauth.provider :twitter,
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:consumer_key] = SiteSetting.twitter_consumer_key
strategy.options[:consumer_secret] = SiteSetting.twitter_consumer_secret
}
setup:
lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:consumer_key] = SiteSetting.twitter_consumer_key
strategy.options[:consumer_secret] = SiteSetting.twitter_consumer_secret
}
end
# twitter doesn't return unverfied email addresses in the API