Fixes issue #2741: Authenticate users via SAML.
This commit is contained in:
parent
128e8dea72
commit
a93250e210
8 changed files with 125 additions and 2 deletions
1
Gemfile
1
Gemfile
|
@ -74,6 +74,7 @@ gem 'omniauth-google-oauth2'
|
|||
gem 'omniauth-linkedin-oauth2'
|
||||
gem 'omniauth-microsoft-office365'
|
||||
gem 'omniauth-oauth2'
|
||||
gem 'omniauth-saml'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-weibo-oauth2'
|
||||
|
||||
|
|
|
@ -345,6 +345,9 @@ GEM
|
|||
omniauth-rails_csrf_protection (0.1.2)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (>= 1.3.1)
|
||||
omniauth-saml (1.10.1)
|
||||
omniauth (~> 1.3, >= 1.3.2)
|
||||
ruby-saml (~> 1.7)
|
||||
omniauth-twitter (1.4.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
|
@ -456,6 +459,8 @@ GEM
|
|||
rubocop-rspec (1.33.0)
|
||||
rubocop (>= 0.60.0)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-saml (1.10.2)
|
||||
nokogiri (>= 1.5.10)
|
||||
ruby_dep (1.5.0)
|
||||
rubyzip (1.2.2)
|
||||
safe_yaml (1.0.5)
|
||||
|
@ -610,6 +615,7 @@ DEPENDENCIES
|
|||
omniauth-microsoft-office365
|
||||
omniauth-oauth2
|
||||
omniauth-rails_csrf_protection
|
||||
omniauth-saml
|
||||
omniauth-twitter
|
||||
omniauth-weibo-oauth2
|
||||
pg (= 0.21.0)
|
||||
|
|
|
@ -106,4 +106,9 @@ App.Config.set('auth_provider_all', {
|
|||
name: 'Weibo'
|
||||
config: 'auth_weibo'
|
||||
class: 'weibo'
|
||||
saml:
|
||||
url: '/auth/saml'
|
||||
name: 'SAML'
|
||||
config: 'auth_saml'
|
||||
class: 'saml'
|
||||
})
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
<th>Icon</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
<% for icon in ['archived-modifier','arrow-down','arrow-left','arrow-right','arrow-up','bold','chain','chat','checkbox-checked','checkbox-indeterminate','checkbox','checkmark','clipboard','clock','cloud','cog','crown','danger','dashboard','diagonal-cross','document','download','draft-modifier','draggable','dropdown-list','email-button','email','external','eye','eyedropper','facebook-button','facebook','file-archive','file-code','file-email','file-excel','file-pdf','file-powerpoint','file-text','file-unknown','file-word','form','forward','full-logo','github-button','gitlab-button','google-button','group','help','horizontal-rule','important','in-process','inactive-organization','inactive-user','info','internal-modifier','italic','knowledge-base-answer','knowledge-base','line-left-arrow','line-right-arrow','linkedin-button','list','loading','lock-open','lock','logo','logotype','long-arrow-down','long-arrow-right','low-priority','magnifier','marker','message','minus-small','minus','mood-bad','mood-good','mood-ok','mood-sad','mood-superbad','mood-supergood','mute','note','oauth2-button','office365-button','one-ticket','organization','outbound-calls','overflow-button','overviews','package','paperclip','pen','person','phone','plus-small','plus','printer','radio-checked','radio','rearange','received-calls','reload','reopening','reply-all','reply','report','searchdetail','signout','small-dot','sms','spinner-small','split','status-modified-outer-circle','status','stopwatch','strikethrough','switchView','task-state','team','telegram','templates','tools','total-tickets','trash','twitter-button','twitter','underline','unmute','unordered-list','user','web','weibo-button','zoom-in','zoom-out']: %>
|
||||
<% for icon in ['archived-modifier','arrow-down','arrow-left','arrow-right','arrow-up','bold','chain','chat','checkbox-checked','checkbox-indeterminate','checkbox','checkmark','clipboard','clock','cloud','cog','crown','danger','dashboard','diagonal-cross','document','download','draft-modifier','draggable','dropdown-list','email-button','email','external','eye','eyedropper','facebook-button','facebook','file-archive','file-code','file-email','file-excel','file-pdf','file-powerpoint','file-text','file-unknown','file-word','form','forward','full-logo','github-button','gitlab-button','google-button','group','help','horizontal-rule','important','in-process','inactive-organization','inactive-user','info','internal-modifier','italic','knowledge-base-answer','knowledge-base','line-left-arrow','line-right-arrow','linkedin-button','list','loading','lock-open','lock','logo','logotype','long-arrow-down','long-arrow-right','low-priority','magnifier','marker','message','minus-small','minus','mood-bad','mood-good','mood-ok','mood-sad','mood-superbad','mood-supergood','mute','note','oauth2-button','office365-button','one-ticket','organization','outbound-calls','overflow-button','overviews','package','paperclip','pen','person','phone','plus-small','plus','printer','radio-checked','radio','rearange','received-calls','reload','reopening','reply-all','reply','report','saml-button','searchdetail','signout','small-dot','sms','spinner-small','split','status-modified-outer-circle','status','stopwatch','strikethrough','switchView','task-state','team','telegram','templates','tools','total-tickets','trash','twitter-button','twitter','underline','unmute','unordered-list','user','web','saml-button','zoom-in','zoom-out']: %>
|
||||
<tr>
|
||||
<td>
|
||||
<%- @Icon( "#{icon}") %>
|
||||
|
|
|
@ -3081,6 +3081,10 @@ ol.tabs li {
|
|||
background: hsl(0,0%,27%);
|
||||
}
|
||||
|
||||
&.auth-provider--saml {
|
||||
background: hsl(0,0%,27%);
|
||||
}
|
||||
|
||||
.provider-name {
|
||||
flex: 1;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ Rails.application.config.middleware.use OmniAuth::Builder do
|
|||
# weibo database connect
|
||||
provider :weibo_database, 'not_change_will_be_set_by_database', 'not_change_will_be_set_by_database'
|
||||
|
||||
# SAML database connect
|
||||
provider :saml_database
|
||||
end
|
||||
|
||||
# This fixes issue #1642 and is required for setups in which Zammad is used
|
||||
|
|
79
db/migrate/20190715141227_saml_auth.rb
Normal file
79
db/migrate/20190715141227_saml_auth.rb
Normal file
|
@ -0,0 +1,79 @@
|
|||
class SamlAuth < ActiveRecord::Migration[5.2]
|
||||
def up
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Authentication via %s',
|
||||
name: 'auth_saml',
|
||||
area: 'Security::ThirdPartyAuthentication',
|
||||
description: 'Enables user authentication via %s.',
|
||||
options: {
|
||||
form: [
|
||||
{
|
||||
display: '',
|
||||
null: true,
|
||||
name: 'auth_saml',
|
||||
tag: 'boolean',
|
||||
options: {
|
||||
true => 'yes',
|
||||
false => 'no',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
preferences: {
|
||||
controller: 'SettingsAreaSwitch',
|
||||
sub: ['auth_saml_credentials'],
|
||||
title_i18n: ['SAML'],
|
||||
description_i18n: ['SAML'],
|
||||
permission: ['admin.security'],
|
||||
},
|
||||
state: false,
|
||||
frontend: true
|
||||
)
|
||||
Setting.create_if_not_exists(
|
||||
title: 'SAML App Credentials',
|
||||
name: 'auth_saml_credentials',
|
||||
area: 'Security::ThirdPartyAuthentication::SAML',
|
||||
description: 'Enables user authentication via SAML.',
|
||||
options: {
|
||||
form: [
|
||||
{
|
||||
display: 'IDP SSO target URL',
|
||||
null: true,
|
||||
name: 'idp_sso_target_url',
|
||||
tag: 'input',
|
||||
placeholder: 'https://capriza.github.io/samling/samling.html',
|
||||
},
|
||||
{
|
||||
display: 'IDP certificate',
|
||||
null: true,
|
||||
name: 'idp_cert',
|
||||
tag: 'input',
|
||||
placeholder: '-----BEGIN CERTIFICATE-----\n...-----END CERTIFICATE-----',
|
||||
},
|
||||
{
|
||||
display: 'IDP certificate fingerprint',
|
||||
null: true,
|
||||
name: 'idp_cert_fingerprint',
|
||||
tag: 'input',
|
||||
placeholder: 'E7:91:B2:E1:...',
|
||||
},
|
||||
{
|
||||
display: 'Name Identifier Format',
|
||||
null: true,
|
||||
name: 'name_identifier_format',
|
||||
tag: 'input',
|
||||
placeholder: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
|
||||
},
|
||||
],
|
||||
},
|
||||
state: {},
|
||||
preferences: {
|
||||
permission: ['admin.security'],
|
||||
},
|
||||
frontend: false
|
||||
)
|
||||
end
|
||||
end
|
26
vendor/lib/saml_database.rb
vendored
Normal file
26
vendor/lib/saml_database.rb
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
class SamlDatabase < OmniAuth::Strategies::SAML
|
||||
option :name, 'saml'
|
||||
|
||||
def initialize(app, *args, &block)
|
||||
|
||||
http_type = Setting.get('http_type')
|
||||
fqdn = Setting.get('fqdn')
|
||||
|
||||
# Use meta URL as entity id/issues as it is best practice.
|
||||
# See: https://community.zammad.org/t/saml-oidc-third-party-authentication/2533/13
|
||||
entity_id = "#{http_type}://#{fqdn}/auth/saml/metadata"
|
||||
assertion_consumer_service_url = "#{http_type}://#{fqdn}/auth/saml/callback"
|
||||
|
||||
config = Setting.get('auth_saml_credentials') || {}
|
||||
options = config.reject { |k,v| v.blank? }
|
||||
.merge(
|
||||
:assertion_consumer_service_url => assertion_consumer_service_url,
|
||||
:issuer => entity_id,
|
||||
)
|
||||
|
||||
args[0] = options
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue