Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add OAuth2 providers #260

Merged
merged 2 commits into from Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Expand Up @@ -41,6 +41,8 @@ end

gem 'net-ldap', '~> 0.17'
gem 'omniauth-cas', '~> 2.0'
gem 'omniauth-github', '~> 1.4'
gem 'omniauth-gitlab', '~> 1.0.2'
gem 'omniauth-saml', '~> 1.10'
gem 'omniauth', '~> 1.9'
gem 'omniauth-rails_csrf_protection', '~> 0.1'
Expand Down
20 changes: 19 additions & 1 deletion Gemfile.lock
Expand Up @@ -392,6 +392,7 @@ GEM
minitest (5.14.4)
msgpack (1.4.2)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.1.1)
net-ldap (0.17.0)
net-scp (3.0.0)
Expand All @@ -406,6 +407,12 @@ GEM
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
oauth2 (1.4.7)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (3.13.9)
omniauth (1.9.1)
hashie (>= 3.4.6)
Expand All @@ -414,6 +421,15 @@ GEM
addressable (~> 2.3)
nokogiri (~> 1.5)
omniauth (~> 1.2)
omniauth-github (1.4.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-gitlab (1.0.4)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0)
omniauth-oauth2 (1.7.2)
oauth2 (~> 1.4)
omniauth (>= 1.9, < 3)
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
Expand Down Expand Up @@ -769,6 +785,8 @@ DEPENDENCIES
oj (~> 3.13)
omniauth (~> 1.9)
omniauth-cas (~> 2.0)
omniauth-github (~> 1.4)
omniauth-gitlab (~> 1.0.2)
omniauth-rails_csrf_protection (~> 0.1)
omniauth-saml (~> 1.10)
ox (~> 2.14)
Expand Down Expand Up @@ -833,4 +851,4 @@ RUBY VERSION
ruby 3.0.2p107

BUNDLED WITH
2.2.22
2.2.32
6 changes: 6 additions & 0 deletions app/controllers/auth/omniauth_callbacks_controller.rb
Expand Up @@ -9,6 +9,12 @@ def self.provides_callback_for(provider)
define_method provider do
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)

if @user.nil?
redirect_to new_user_registration_url
set_flash_message(:alert, 'should_register_before_auth_login', scope: 'devise.failure')
return
end

if @user.persisted?
LoginActivity.create(
user: @user,
Expand Down
26 changes: 25 additions & 1 deletion app/javascript/styles/mastodon/components.scss
Expand Up @@ -103,7 +103,9 @@
&.button-primary,
&.button-alternative,
&.button-secondary,
&.button-alternative-2 {
&.button-alternative-2,
&.button-github,
&.button-gitlab {
font-size: 16px;
line-height: 36px;
height: auto;
Expand Down Expand Up @@ -150,6 +152,28 @@
}
}

&.button-github {
color: $white;
background: #24292f;

&:active,
&:focus,
&:hover {
background-color: lighten(#24292f, 4%);
}
}

&.button-gitlab {
color: $white;
background: #fc6d27;

&:active,
&:focus,
&:hover {
background-color: darken(#fc6d27, 4%);
}
}

&.button--block {
display: block;
width: 100%;
Expand Down
45 changes: 38 additions & 7 deletions app/models/concerns/omniauthable.rb
Expand Up @@ -31,6 +31,8 @@ def find_for_oauth(auth, signed_in_resource = nil)
user = signed_in_resource || identity.user
user ||= create_for_oauth(auth)

return nil if user.nil?

if identity.user.nil?
identity.user = user
identity.save!
Expand All @@ -49,12 +51,14 @@ def create_for_oauth(auth)
assume_verified = strategy&.security&.assume_email_is_verified
email_is_verified = auth.info.verified || auth.info.verified_email || assume_verified
email = auth.info.verified_email || auth.info.email
email = nil unless email_is_verified
email = nil unless email_is_verified or trusted_auth_provider(auth)

user = User.find_by(email: email) if email_is_verified
user = User.find_by(email: email) if email_is_verified or trusted_auth_provider(auth)

return user unless user.nil?

return nil if is_registration_limited

user = User.new(user_params_from_auth(email, auth))

user.account.avatar_remote_url = auth.info.image if /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/.match?(auth.info.image)
Expand All @@ -71,22 +75,49 @@ def user_params_from_auth(email, auth)
agreement: true,
external: true,
account_attributes: {
username: ensure_unique_username(auth.uid),
display_name: auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' '),
username: ensure_unique_username(auth),
display_name: trusted_auth_provider_display_name(auth) || auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' '),
},
}
end

def ensure_unique_username(starting_username)
username = starting_username
def ensure_unique_username(auth)
username = auth.uid
auth_provideded_username = nil
i = 0

if auth.provider == 'github'
auth_provideded_username = auth.info.nickname
elsif auth.provider == 'gitlab'
auth_provideded_username = auth.info.username
end

username = auth_provideded_username unless auth_provideded_username.empty?

while Account.exists?(username: username, domain: nil)
i += 1
username = "#{starting_username}_#{i}"
username = "#{auth_provideded_username || auth.uid}_#{i}"
end

username
end

def trusted_auth_provider(auth)
auth.provider == 'github' || auth.provider == 'gitlab'
end

def trusted_auth_provider_display_name(auth)
if auth.provider == 'github'
return auth.info.name
elsif auth.provider == 'gitlab'
return auth.info.name
end

return nil
end

def is_registration_limited()
return ENV['AUTO_REGISTRATION_WITH_AUTH_PROVIDERS'] != 'true' || Setting.registrations_mode != 'open'
end
end
end
9 changes: 9 additions & 0 deletions app/views/about/_login.html.haml
Expand Up @@ -11,3 +11,12 @@
= f.button :button, t('auth.login'), type: :submit, class: 'button button-primary'

%p.hint.subtle-hint= link_to t('auth.trouble_logging_in'), new_user_password_path

- if Devise.omniauth_configs.keys.length()
.simple_form.alternative-login
- Devise.omniauth_configs.keys.each do |provider|
.actions
= link_to omniauth_authorize_path('user', provider), class: "button button-#{provider}", method: :post do
%i{:class => ['fab', "fa-#{provider}"]}
%span
= t("auth.providers.#{provider}") || provider.to_s.chomp("_oauth2").capitalize
4 changes: 2 additions & 2 deletions app/views/auth/sessions/new.html.haml
Expand Up @@ -20,8 +20,8 @@
.simple_form.alternative-login
%h4= t('auth.or_log_in_with')

.actions
- resource_class.omniauth_providers.each do |provider|
- resource_class.omniauth_providers.each do |provider|
.actions
= link_to t("auth.providers.#{provider}", default: provider.to_s.chomp("_oauth2").capitalize), omniauth_authorize_path(resource_name, provider), class: "button button-#{provider}", method: :post

.form-footer= render 'auth/shared/links'
10 changes: 10 additions & 0 deletions config/initializers/omniauth.rb
Expand Up @@ -65,4 +65,14 @@
saml_options[:allowed_clock_drift] = ENV['SAML_ALLOWED_CLOCK_DRIFT'] if ENV['SAML_ALLOWED_CLOCK_DRIFT']
config.omniauth :saml, saml_options
end

# Github strategy
if ENV['GITHUB_OAUTH2_ENABLED'] == 'true'
config.omniauth :github, ENV['GITHUB_OAUTH2_KEY'], ENV['GITHUB_OAUTH2_SECRET'], scope: 'user.info'
end

# Gitlab strategy
if ENV['GITLAB_OAUTH2_ENABLED'] == 'true'
config.omniauth :gitlab, ENV['GITLAB_OAUTH2_KEY'], ENV['GITLAB_OAUTH2_SECRET'], scope: 'read_user'
end
end
1 change: 1 addition & 0 deletions config/locales/devise.en.yml
Expand Up @@ -16,6 +16,7 @@ en:
timeout: Your session expired. Please sign in again to continue.
unauthenticated: You need to sign in or sign up before continuing.
unconfirmed: You have to confirm your email address before continuing.
should_register_before_auth_login: You need to sign up before continuing.
mailer:
confirmation_instructions:
action: Verify email address
Expand Down
1 change: 1 addition & 0 deletions config/locales/devise.zh-CN.yml
Expand Up @@ -16,6 +16,7 @@ zh-CN:
timeout: 你的会话已过期。请重新登录再继续操作。
unauthenticated: 继续操作前请注册或者登录。
unconfirmed: 你必须先确认你的电子邮件地址才能继续。
should_register_before_auth_login: 请先注册。
mailer:
confirmation_instructions:
action: 验证电子邮件地址
Expand Down
1 change: 1 addition & 0 deletions config/locales/devise.zh-HK.yml
Expand Up @@ -16,6 +16,7 @@ zh-HK:
timeout: 你的登入階段已經過期,請重新登入以繼續使用。
unauthenticated: 你必須先登入或登記,以繼續使用。
unconfirmed: 你必須先確認電郵地址,繼續使用。
should_register_before_auth_login: 你必須先登記,以繼續使用。
mailer:
confirmation_instructions:
action: 驗證電子郵件地址
Expand Down
1 change: 1 addition & 0 deletions config/locales/devise.zh-TW.yml
Expand Up @@ -16,6 +16,7 @@ zh-TW:
timeout: 登入階段逾時。請重新登入以繼續。
unauthenticated: 您必須先登入或註冊才能繼續使用。
unconfirmed: 您必須先確認電子信箱才能繼續使用。
should_register_before_auth_login: 您必須先註冊才能繼續使用。
mailer:
confirmation_instructions:
action: 驗證電子信箱地址
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Expand Up @@ -841,6 +841,8 @@ en:
providers:
cas: CAS
saml: SAML
github: GitHub
gitlab: GitLab
register: Sign up
registration_closed: "%{instance} is not accepting new members"
resend_confirmation: Resend confirmation instructions
Expand Down