diff --git a/LICENSE-ICONS-3RD-PARTY.json b/LICENSE-ICONS-3RD-PARTY.json
index 48d19536c..c36e26b64 100644
--- a/LICENSE-ICONS-3RD-PARTY.json
+++ b/LICENSE-ICONS-3RD-PARTY.json
@@ -688,5 +688,10 @@
"author": "Felix Niklas",
"url": "",
"license": "MIT"
+ },
+ "sso-button.svg": {
+ "author": "Tanu Doank",
+ "url": "https://thenounproject.com/term/key/1247931/",
+ "license": "CC 3.0 Attribution"
}
}
\ No newline at end of file
diff --git a/app/assets/javascripts/app/controllers/_profile/linked_accounts.coffee b/app/assets/javascripts/app/controllers/_profile/linked_accounts.coffee
index d8ee745ef..f3556ff27 100644
--- a/app/assets/javascripts/app/controllers/_profile/linked_accounts.coffee
+++ b/app/assets/javascripts/app/controllers/_profile/linked_accounts.coffee
@@ -111,4 +111,9 @@ App.Config.set('auth_provider_all', {
name: 'SAML'
config: 'auth_saml'
class: 'saml'
+ sso:
+ url: '/auth/sso'
+ name: 'SSO'
+ config: 'auth_sso'
+ class: 'sso'
})
diff --git a/app/assets/stylesheets/svg-dimensions.css b/app/assets/stylesheets/svg-dimensions.css
index 11bd7d184..10d16a36e 100644
--- a/app/assets/stylesheets/svg-dimensions.css
+++ b/app/assets/stylesheets/svg-dimensions.css
@@ -114,6 +114,7 @@
.icon-sms { width: 17px; height: 17px; }
.icon-spinner-small { width: 15px; height: 15px; }
.icon-split { width: 16px; height: 17px; }
+.icon-sso-button { width: 29px; height: 24px; }
.icon-status-modified-outer-circle { width: 16px; height: 16px; }
.icon-status { width: 16px; height: 16px; }
.icon-stopwatch { width: 77px; height: 83px; }
diff --git a/app/assets/stylesheets/zammad.scss b/app/assets/stylesheets/zammad.scss
index 47774006a..bae70f740 100644
--- a/app/assets/stylesheets/zammad.scss
+++ b/app/assets/stylesheets/zammad.scss
@@ -3199,6 +3199,10 @@ ol.tabs li {
background: hsl(0,0%,27%);
}
+ &.auth-provider--sso {
+ background: #454545;
+ }
+
.provider-name {
flex: 1;
}
@@ -3399,6 +3403,10 @@ ol.tabs li {
fill: white;
}
+.icon-sso-button {
+ fill: white;
+}
+
/*
* removed margin of forms to not break the layout with submit buttons within
area e. g. for modal dialogs
diff --git a/app/controllers/application_controller/authenticates.rb b/app/controllers/application_controller/authenticates.rb
index 5e3ac287b..3e1ae4378 100644
--- a/app/controllers/application_controller/authenticates.rb
+++ b/app/controllers/application_controller/authenticates.rb
@@ -141,21 +141,6 @@ module ApplicationController::Authenticates
authentication_check_prerequesits(user, 'session', {})
end
- def authenticate_with_sso
- user = begin
- login = request.env['REMOTE_USER'] ||
- request.env['HTTP_REMOTE_USER'] ||
- request.headers['X-Forwarded-User']
- User.lookup(login: login&.downcase)
- end
-
- raise Exceptions::NotAuthorized, 'Missing SSO ENV REMOTE_USER' if login.blank?
- raise Exceptions::NotAuthorized, "No such user #{login} from ENV REMOTE_USER" if !user
-
- session.delete(:switched_from_user_id)
- authentication_check_prerequesits(user, 'SSO', {})
- end
-
def authentication_check_prerequesits(user, auth_type, auth_param)
raise Exceptions::NotAuthorized, 'Maintenance mode enabled!' if in_maintenance_mode?(user)
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index d298f2b0e..4cca6b9b7 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -16,7 +16,21 @@ class SessionsController < ApplicationController
end
def create_sso
- authenticate_with_sso
+ raise Exceptions::NotAuthorized, 'SSO authentication disabled!' if !Setting.get('auth_sso')
+
+ user = begin
+ login = request.env['REMOTE_USER'] ||
+ request.env['HTTP_REMOTE_USER'] ||
+ request.headers['X-Forwarded-User']
+
+ User.lookup(login: login&.downcase)
+ end
+
+ raise Exceptions::NotAuthorized, 'Missing SSO ENV REMOTE_USER or X-Forwarded-User header' if login.blank?
+ raise Exceptions::NotAuthorized, "No such user '#{login}' found!" if user.blank?
+
+ session.delete(:switched_from_user_id)
+ authentication_check_prerequesits(user, 'SSO', {})
redirect_to '/#'
end
diff --git a/contrib/apache2/zammad.conf b/contrib/apache2/zammad.conf
index 03a26e095..347ae5a09 100644
--- a/contrib/apache2/zammad.conf
+++ b/contrib/apache2/zammad.conf
@@ -31,6 +31,9 @@
ProxyPass /ws ws://127.0.0.1:6042/
ProxyPass / http://127.0.0.1:3000/
+ # change this line in an SSO setup
+ RequestHeader unset X-Forwarded-User
+
DocumentRoot "/opt/zammad/public"
diff --git a/contrib/apache2/zammad_ssl.conf b/contrib/apache2/zammad_ssl.conf
index 24d482ef4..361acb0b4 100644
--- a/contrib/apache2/zammad_ssl.conf
+++ b/contrib/apache2/zammad_ssl.conf
@@ -54,6 +54,9 @@
ProxyPass /ws ws://127.0.0.1:6042/
ProxyPass / http://127.0.0.1:3000/
+ # change this line in an SSO setup
+ RequestHeader unset X-Forwarded-User
+
# Use settings below if proxying does not work and you receive HTTP-Errror 404
# if you use the settings below, make sure to comment out the above two options
# This may not apply to all systems, applies to openSuse
diff --git a/contrib/nginx/zammad.conf b/contrib/nginx/zammad.conf
index 836164574..e51198017 100644
--- a/contrib/nginx/zammad.conf
+++ b/contrib/nginx/zammad.conf
@@ -46,6 +46,10 @@ server {
proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
+
+ # Change this line in an SSO setup
+ proxy_set_header X-Forwarded-User "";
+
proxy_read_timeout 300;
proxy_pass http://zammad-railsserver;
diff --git a/contrib/nginx/zammad_ssl.conf b/contrib/nginx/zammad_ssl.conf
index 60349efb9..2e8e4bc54 100644
--- a/contrib/nginx/zammad_ssl.conf
+++ b/contrib/nginx/zammad_ssl.conf
@@ -100,6 +100,10 @@ server {
proxy_set_header Host $http_host;
proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ # change this line in an SSO setup
+ proxy_set_header X-Forwarded-User "";
+
proxy_read_timeout 180;
proxy_pass http://zammad-railsserver;
diff --git a/db/migrate/20200724130426_issue3128_add_sso.rb b/db/migrate/20200724130426_issue3128_add_sso.rb
new file mode 100644
index 000000000..00b7d8018
--- /dev/null
+++ b/db/migrate/20200724130426_issue3128_add_sso.rb
@@ -0,0 +1,38 @@
+class Issue3128AddSso < ActiveRecord::Migration[5.2]
+ def change
+
+ # return if it's a new setup
+ return if !Setting.exists?(name: 'system_init_done')
+
+ Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_sso',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables button for user authentication via %s. The button will redirect to /auth/sso on user interaction.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_sso',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: {},
+ title_i18n: ['SSO'],
+ description_i18n: ['SSO', 'Button for Single Sign On.'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+ )
+
+ end
+end
diff --git a/db/seeds/settings.rb b/db/seeds/settings.rb
index 9e8418c6d..03bc77e4f 100644
--- a/db/seeds/settings.rb
+++ b/db/seeds/settings.rb
@@ -4613,3 +4613,33 @@ Setting.create_if_not_exists(
},
frontend: true,
)
+
+Setting.create_if_not_exists(
+ title: 'Authentication via %s',
+ name: 'auth_sso',
+ area: 'Security::ThirdPartyAuthentication',
+ description: 'Enables button for user authentication via %s. The button will redirect to /auth/sso on user interaction.',
+ options: {
+ form: [
+ {
+ display: '',
+ null: true,
+ name: 'auth_sso',
+ tag: 'boolean',
+ options: {
+ true => 'yes',
+ false => 'no',
+ },
+ },
+ ],
+ },
+ preferences: {
+ controller: 'SettingsAreaSwitch',
+ sub: {},
+ title_i18n: ['SSO'],
+ description_i18n: ['SSO', 'Button for Single Sign On.'],
+ permission: ['admin.security'],
+ },
+ state: false,
+ frontend: true
+)
diff --git a/public/assets/images/icons.svg b/public/assets/images/icons.svg
index f117ee617..1f6d347f3 100644
--- a/public/assets/images/icons.svg
+++ b/public/assets/images/icons.svg
@@ -763,6 +763,9 @@
split
+
+
+
status-modified-outer-circle
diff --git a/public/assets/images/icons/sso-button.svg b/public/assets/images/icons/sso-button.svg
new file mode 100644
index 000000000..8d4869187
--- /dev/null
+++ b/public/assets/images/icons/sso-button.svg
@@ -0,0 +1,32 @@
+
+
+
diff --git a/spec/requests/session_spec.rb b/spec/requests/session_spec.rb
index aec5c6f97..c91958e0a 100644
--- a/spec/requests/session_spec.rb
+++ b/spec/requests/session_spec.rb
@@ -30,6 +30,27 @@ RSpec.describe 'Sessions endpoints', type: :request do
end
describe 'GET /auth/sso (single sign-on)' do
+
+ before do
+ Setting.set('auth_sso', true)
+ end
+
+ context 'when SSO is disabled' do
+
+ before do
+ Setting.set('auth_sso', false)
+ end
+
+ let(:headers) { { 'X-Forwarded-User' => login } }
+ let(:login) { User.last.login }
+
+ it 'returns a new user-session response' do
+ get '/auth/sso', as: :json, headers: headers
+
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
context 'with invalid user login' do
let(:login) { User.pluck(:login).max.next }