Commit 70de5114 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'auth-icons-labels' into 'master'

Allow custom label to be set for authentication providers.

Addresses internal issue https://dev.gitlab.org/gitlab/gitlabhq/issues/2341

Beside the above, I've:
- Refactored `OauthHelper` to have clearer method names and behaviour
- Moved some of `OauthHelper` behaviour to `Gitlab::OAuth::Provider`
- Renamed `OauthHelper` to `AuthHelper` since LDAP, SAML, Kerberos aren't OAuth
- Updated the icons for GitHub and GitLab

In the examples below, "OurAuth" is a SAML provider with a custom label.

![Screen_Shot_2015-07-02_at_16.29.52](https://gitlab.com/gitlab-org/gitlab-ce/uploads/7d425bde69dc34e1667ebd5375d0266d/Screen_Shot_2015-07-02_at_16.29.52.png)

![Screen_Shot_2015-07-02_at_16.31.40](https://gitlab.com/gitlab-org/gitlab-ce/uploads/cbb273321ecdf4cab3d3ef0dc35553e7/Screen_Shot_2015-07-02_at_16.31.40.png)

![Screen_Shot_2015-07-02_at_16.32.39](https://gitlab.com/gitlab-org/gitlab-ce/uploads/d8dd6e1d0dc45a788e869cdcdc99e178/Screen_Shot_2015-07-02_at_16.32.39.png)

![Screen_Shot_2015-07-02_at_16.33.18](https://gitlab.com/gitlab-org/gitlab-ce/uploads/7dbfe8b0ae229c32a08d6c7442976d83/Screen_Shot_2015-07-02_at_16.33.18.png)


See merge request !927
parents f84ba4c0 70a3c165
...@@ -77,6 +77,7 @@ v 7.12.2 ...@@ -77,6 +77,7 @@ v 7.12.2
- Faster automerge check and merge itself when source and target branches are in same repository - Faster automerge check and merge itself when source and target branches are in same repository
- Audit log for user authentication - Audit log for user authentication
- Fix transferring of project to another group using the API. - Fix transferring of project to another group using the API.
- Allow custom label to be set for authentication providers.
v 7.12.1 v 7.12.1
- Fix error when deleting a user who has projects (Stan Hu) - Fix error when deleting a user who has projects (Stan Hu)
......
...@@ -299,14 +299,14 @@ class ApplicationController < ActionController::Base ...@@ -299,14 +299,14 @@ class ApplicationController < ActionController::Base
end end
def github_import_enabled? def github_import_enabled?
OauthHelper.enabled_oauth_providers.include?(:github) Gitlab::OAuth::Provider.enabled?(:github)
end end
def gitlab_import_enabled? def gitlab_import_enabled?
OauthHelper.enabled_oauth_providers.include?(:gitlab) Gitlab::OAuth::Provider.enabled?(:gitlab)
end end
def bitbucket_import_enabled? def bitbucket_import_enabled?
OauthHelper.enabled_oauth_providers.include?(:bitbucket) && Gitlab::BitbucketImport.public_key.present? Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
end end
end end
...@@ -72,10 +72,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -72,10 +72,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end end
end end
rescue Gitlab::OAuth::SignupDisabledError => e rescue Gitlab::OAuth::SignupDisabledError => e
message = "Signing in using your #{oauth['provider']} account without a pre-existing GitLab account is not allowed." label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
if current_application_settings.signup_enabled? if current_application_settings.signup_enabled?
message << " Create a GitLab account first, and then connect it to your #{oauth['provider']} account." message << " Create a GitLab account first, and then connect it to your #{label} account."
end end
flash[:notice] = message flash[:notice] = message
......
...@@ -90,7 +90,7 @@ class SessionsController < Devise::SessionsController ...@@ -90,7 +90,7 @@ class SessionsController < Devise::SessionsController
# Prevent alert from popping up on the first page shown after authentication. # Prevent alert from popping up on the first page shown after authentication.
flash[:alert] = nil flash[:alert] = nil
redirect_to omniauth_authorize_path(:user, provider.to_sym) redirect_to user_omniauth_authorize_path(provider.to_sym)
end end
def valid_otp_attempt?(user) def valid_otp_attempt?(user)
......
module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos'].freeze
def ldap_enabled?
Gitlab.config.ldap.enabled
end
def provider_has_icon?(name)
PROVIDERS_WITH_ICONS.include?(name.to_s)
end
def auth_providers
Gitlab::OAuth::Provider.providers
end
def label_for_provider(name)
Gitlab::OAuth::Provider.label_for(name)
end
def form_based_provider?(name)
FORM_BASED_PROVIDERS.any? { |pattern| pattern === name.to_s }
end
def form_based_providers
auth_providers.select { |provider| form_based_provider?(provider) }
end
def button_based_providers
auth_providers.reject { |provider| form_based_provider?(provider) }
end
def provider_image_tag(provider, size = 64)
label = label_for_provider(provider)
if provider_has_icon?(provider)
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
image_tag(image_path("auth_buttons/#{file_name}"), alt: label, title: "Sign in with #{label}")
else
label
end
end
def auth_active?(provider)
current_user.identities.exists?(provider: provider.to_s)
end
extend self
end
module OauthHelper
def ldap_enabled?
Gitlab.config.ldap.enabled
end
def default_providers
[:twitter, :github, :gitlab, :bitbucket, :google_oauth2, :ldap]
end
def enabled_oauth_providers
Devise.omniauth_providers
end
def enabled_social_providers
enabled_oauth_providers.select do |name|
[:saml, :twitter, :gitlab, :github, :bitbucket, :google_oauth2].include?(name.to_sym)
end
end
def additional_providers
enabled_oauth_providers.reject{|provider| provider.to_s.starts_with?('ldap')}
end
def oauth_image_tag(provider, size = 64)
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
image_tag(image_path("authbuttons/#{file_name}"), alt: "Sign in with #{provider.to_s.titleize}")
end
def oauth_active?(provider)
current_user.identities.exists?(provider: provider.to_s)
end
extend self
end
module ProfileHelper
def show_profile_username_tab?
current_user.can_change_username?
end
def show_profile_social_tab?
enabled_social_providers.any?
end
def show_profile_remove_tab?
signup_enabled?
end
end
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
.form-group .form-group
= f.label :provider, class: 'control-label' = f.label :provider, class: 'control-label'
.col-sm-10 .col-sm-10
= f.select :provider, Gitlab::OAuth::Provider.names, { allow_blank: false }, class: 'form-control' - values = Gitlab::OAuth::Provider.providers.map { |name| ["#{Gitlab::OAuth::Provider.label_for(name)} (#{name})", name] }
= f.select :provider, values, { allow_blank: false }, class: 'form-control'
.form-group .form-group
= f.label :extern_uid, "Identifier", class: 'control-label' = f.label :extern_uid, "Identifier", class: 'control-label'
.col-sm-10 .col-sm-10
......
%tr %tr
%td %td
= identity.provider = "#{Gitlab::OAuth::Provider.label_for(identity.provider)} (#{identity.provider})"
%td %td
= identity.extern_uid = identity.extern_uid
%td %td
......
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
%label{for: "remember_me"} %label{for: "remember_me"}
= check_box_tag :remember_me, '1', false, id: 'remember_me' = check_box_tag :remember_me, '1', false, id: 'remember_me'
%span Remember me %span Remember me
= button_tag "#{server['label']} Sign in", class: "btn-save btn" = button_tag "Sign in", class: "btn-save btn"
%p %p
%span.light %span.light
Sign in with &nbsp; Sign in with &nbsp;
- providers = additional_providers - providers = button_based_providers
- providers.each do |provider| - providers.each do |provider|
%span.light %span.light
- if default_providers.include?(provider) - has_icon = provider_has_icon?(provider)
= link_to oauth_image_tag(provider), omniauth_authorize_path(resource_name, provider), method: :post, class: 'oauth-image-link' = link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true"
- else
= link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), method: :post, class: "btn", "data-no-turbolink" => "true"
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.login-heading .login-heading
%h3 Sign in %h3 Sign in
.login-body .login-body
- if ldap_enabled? - if form_based_providers.any?
%ul.nav.nav-tabs %ul.nav.nav-tabs
- @ldap_servers.each_with_index do |server, i| - @ldap_servers.each_with_index do |server, i|
%li{class: (:active if i.zero?)} %li{class: (:active if i.zero?)}
......
...@@ -59,22 +59,22 @@ ...@@ -59,22 +59,22 @@
%div %div
= link_to 'Enable Two-factor Authentication', new_profile_two_factor_auth_path, class: 'btn btn-success' = link_to 'Enable Two-factor Authentication', new_profile_two_factor_auth_path, class: 'btn btn-success'
- if show_profile_social_tab? - if button_based_providers.any?
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
Connected Accounts Connected Accounts
.panel-body .panel-body
.oauth-buttons.append-bottom-10 .oauth-buttons.append-bottom-10
%p Click on icon to activate signin with one of the following services %p Click on icon to activate signin with one of the following services
- enabled_social_providers.each do |provider| - button_based_providers.each do |provider|
.btn-group .btn-group
= link_to oauth_image_tag(provider), omniauth_authorize_path(User, provider), = link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: "btn btn-lg #{'active' if auth_active?(provider)}", "data-no-turbolink" => "true"
method: :post, class: "btn btn-lg #{'active' if oauth_active?(provider)}"
- if oauth_active?(provider) - if auth_active?(provider)
= link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'btn btn-lg' do = link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'btn btn-lg' do
= icon('close') = icon('close')
- if show_profile_username_tab? - if current_user.can_change_username?
.panel.panel-warning.update-username .panel.panel-warning.update-username
.panel-heading .panel-heading
Change Username Change Username
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
%div %div
= f.submit 'Save username', class: "btn btn-warning" = f.submit 'Save username', class: "btn btn-warning"
- if show_profile_remove_tab? - if signup_enabled?
.panel.panel-danger.remove-account .panel.panel-danger.remove-account
.panel-heading .panel-heading
Remove account Remove account
......
...@@ -209,20 +209,29 @@ production: &base ...@@ -209,20 +209,29 @@ production: &base
# arguments, followed by optional 'args' which can be either a hash or an array. # arguments, followed by optional 'args' which can be either a hash or an array.
# Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html # Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
providers: providers:
# - { name: 'google_oauth2', app_id: 'YOUR_APP_ID', # - { name: 'google_oauth2',
# label: 'Google',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET', # app_secret: 'YOUR_APP_SECRET',
# args: { access_type: 'offline', approval_prompt: '' } } # args: { access_type: 'offline', approval_prompt: '' } }
# - { name: 'twitter', app_id: 'YOUR_APP_ID', # - { name: 'twitter',
# app_secret: 'YOUR_APP_SECRET'} # app_id: 'YOUR_APP_ID',
# - { name: 'github', app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET' }
# - { name: 'github',
# label: 'GitHub',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET', # app_secret: 'YOUR_APP_SECRET',
# args: { scope: 'user:email' } } # args: { scope: 'user:email' } }
# - { name: 'gitlab', app_id: 'YOUR_APP_ID', # - { name: 'gitlab',
# label: 'GitLab.com',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET', # app_secret: 'YOUR_APP_SECRET',
# args: { scope: 'api' } } # args: { scope: 'api' } }
# - { name: 'bitbucket', app_id: 'YOUR_APP_ID', # - { name: 'bitbucket',
# app_secret: 'YOUR_APP_SECRET'} # app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET' }
# - { name: 'saml', # - { name: 'saml',
# label: 'Our SAML Provider',
# args: { # args: {
# assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', # assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
# idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', # idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
......
...@@ -84,7 +84,7 @@ Existing users can enable OmniAuth for specific providers after the account is c ...@@ -84,7 +84,7 @@ Existing users can enable OmniAuth for specific providers after the account is c
1. Sign in normally - whether standard sign in, LDAP, or another OmniAuth provider. 1. Sign in normally - whether standard sign in, LDAP, or another OmniAuth provider.
1. Go to profile settings (the silhouette icon in the top right corner). 1. Go to profile settings (the silhouette icon in the top right corner).
1. Select the "Account" tab. 1. Select the "Account" tab.
1. Under "Social Accounts" select the desired OmniAuth provider, such as Twitter. 1. Under "Connected Accounts" select the desired OmniAuth provider, such as Twitter.
1. The user will be redirected to the provider. Once the user authorized GitLab they will be redirected back to GitLab. 1. The user will be redirected to the provider. Once the user authorized GitLab they will be redirected back to GitLab.
The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on. The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on.
......
...@@ -3,6 +3,14 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps ...@@ -3,6 +3,14 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
include SharedPaths include SharedPaths
include SharedAdmin include SharedAdmin
before do
allow(Devise).to receive(:omniauth_providers).and_return([:twitter, :twitter_updated])
end
after do
allow(Devise).to receive(:omniauth_providers).and_call_original
end
step 'I should see all users' do step 'I should see all users' do
User.all.each do |user| User.all.each do |user|
expect(page).to have_content user.name expect(page).to have_content user.name
...@@ -121,7 +129,6 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps ...@@ -121,7 +129,6 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
end end
step 'I visit "Pete" identities page in admin' do step 'I visit "Pete" identities page in admin' do
allow(Gitlab::OAuth::Provider).to receive(:names).and_return(%w(twitter twitter_updated))
visit admin_user_identities_path(@user) visit admin_user_identities_path(@user)
end end
......
module Gitlab module Gitlab
module OAuth module OAuth
class Provider class Provider
def self.names def self.providers
providers = [] Devise.omniauth_providers
end
def self.enabled?(name)
providers.include?(name.to_sym)
end
Gitlab.config.ldap.servers.values.each do |server| def self.ldap_provider?(name)
providers << server['provider_name'] name.to_s.start_with?('ldap')
end end
Gitlab.config.omniauth.providers.each do |provider| def self.config_for(name)
providers << provider['name'] name = name.to_s
if ldap_provider?(name)
Gitlab::LDAP::Config.new(name).options
else
Gitlab.config.omniauth.providers.find { |provider| provider.name == name }
end
end end
providers def self.label_for(name)
config = config_for(name)
(config && config['label']) || name.to_s.titleize
end end
end end
end end
......
require "spec_helper"
describe AuthHelper do
describe "button_based_providers" do
it 'returns all enabled providers' do
allow(helper).to receive(:auth_providers) { [:twitter, :github] }
expect(helper.button_based_providers).to include(*[:twitter, :github])
end
it 'does not return ldap provider' do
allow(helper).to receive(:auth_providers) { [:twitter, :ldapmain] }
expect(helper.button_based_providers).to include(:twitter)
end
it 'returns empty array' do
allow(helper).to receive(:auth_providers) { [] }
expect(helper.button_based_providers).to eq([])
end
end
end
require "spec_helper"
describe OauthHelper do
describe "additional_providers" do
it 'returns all enabled providers' do
allow(helper).to receive(:enabled_oauth_providers) { [:twitter, :github] }
expect(helper.additional_providers).to include(*[:twitter, :github])
end
it 'does not return ldap provider' do
allow(helper).to receive(:enabled_oauth_providers) { [:twitter, :ldapmain] }
expect(helper.additional_providers).to include(:twitter)
end
it 'returns empty array' do
allow(helper).to receive(:enabled_oauth_providers) { [] }
expect(helper.additional_providers).to eq([])
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment