Merge pull request #214 from nextcloud/multiple-accounts

Allow to configure multiple providers
This commit is contained in:
Björn Schiessle 2018-08-06 11:04:56 +02:00 committed by GitHub
commit b581b66047
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 672 additions and 124 deletions

View file

@ -33,10 +33,12 @@ $l = \OC::$server->getL10N('user_saml');
$config = \OC::$server->getConfig();
$request = \OC::$server->getRequest();
$userSession = \OC::$server->getUserSession();
$session = \OC::$server->getSession();
$samlSettings = new \OCA\User_SAML\SAMLSettings(
$urlGenerator,
$config,
$request
$request,
$session
);
$userBackend = new \OCA\User_SAML\UserBackend(
@ -45,7 +47,8 @@ $userBackend = new \OCA\User_SAML\UserBackend(
\OC::$server->getSession(),
\OC::$server->getDatabaseConnection(),
\OC::$server->getUserManager(),
\OC::$server->getGroupManager()
\OC::$server->getGroupManager(),
$samlSettings
);
$userBackend->registerBackends(\OC::$server->getUserManager()->getBackends());
OC_User::useBackend($userBackend);
@ -57,7 +60,7 @@ $type = '';
switch($config->getAppValue('user_saml', 'type')) {
case 'saml':
try {
$oneLoginSettings = new \OneLogin_Saml2_Settings($samlSettings->getOneLoginSettingsArray());
$oneLoginSettings = new \OneLogin_Saml2_Settings($samlSettings->getOneLoginSettingsArray(1));
} catch (OneLogin_Saml2_Error $e) {
$returnScript = true;
}
@ -119,9 +122,11 @@ if($useSamlForDesktopClients === '1') {
}
}
$multipleUserBackEnds = $config->getAppValue('user_saml', 'general-allow_multiple_user_back_ends', '0');
$multipleUserBackEnds = $samlSettings->allowMultipleUserBackEnds();
$configuredIdps = $samlSettings->getListOfIdps();
$showLoginOptions = $multipleUserBackEnds || count($configuredIdps) > 1;
if ($redirectSituation === true && $multipleUserBackEnds === '1') {
if ($redirectSituation === true && $showLoginOptions) {
$params = $request->getParams();
$redirectUrl = '';
if(isset($params['redirect_url'])) {
@ -152,6 +157,7 @@ if($redirectSituation === true) {
[
'requesttoken' => $csrfToken->getEncryptedValue(),
'originalUrl' => $originalUrl,
'idp' => 1,
]
);
header('Location: '.$targetUrl);

View file

@ -58,5 +58,21 @@ return [
'url' => '/saml/selectUserBackEnd',
'verb' => 'GET',
],
[
'name' => 'Settings#getSamlProviderSettings',
'url' => '/settings/providerSettings/{providerId}',
'verb' => 'GET',
'defaults' => [
'providerId' => '1'
]
],
[
'name' => 'Settings#deleteSamlProviderSettings',
'url' => '/settings/providerSettings/{providerId}',
'verb' => 'DELETE',
'defaults' => [
'providerId' => '1'
]
],
],
];

View file

@ -8,6 +8,12 @@
cursor: pointer;
}
#user-saml h3 .icon-delete {
display: inline-block;
padding: 5px;
margin-bottom: -6px;
}
#user-saml h4 {
font-size: 14px;
font-weight: 300;
@ -26,6 +32,25 @@
clear: both;
padding: 7px 0;
cursor: pointer;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
opacity: .5;
}
#user-saml .account-list {
margin: 10px 0 10px 0;
overflow:hidden;
padding: 10px 0 10px 0;
}
#user-saml .account-list li {
float: left;
}
#user-saml .account-list li a:not(.button) {
padding: 7px;
}
#user-saml .account-list li a.button {
margin-left: 20px;
}
#user-saml .account-list li.active a {
border-bottom: 1px solid #333;
font-weight: bold;
}

View file

@ -5,6 +5,24 @@
* @namespace OCA.User_SAML.Admin
*/
OCA.User_SAML.Admin = {
currentConfig: '1',
providerIds: '1',
_getAppConfig: function (key) {
return $.ajax({
type: 'GET',
url: OC.linkToOCS('apps/provisioning_api/api/v1', 2) + 'config/apps' + '/user_saml/' + key + '?format=json'
});
},
init: function(callback) {
this._getAppConfig('providerIds').done(function (data){
if (data.ocs.data.data !== '') {
OCA.User_SAML.Admin.providerIds = data.ocs.data.data;
OCA.User_SAML.Admin.currentConfig = OCA.User_SAML.Admin.providerIds.split(',').sort()[0];
}
callback();
});
},
chooseEnv: function() {
if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.chooseEnv, this));
@ -23,37 +41,106 @@
OCP.AppConfig.setValue('user_saml', 'type', 'saml', {success: function() {location.reload();}});
},
setSamlConfigValue: function(category, setting, value) {
getConfigIdentifier: function() {
if (this.currentConfig === '1') {
return '';
}
return this.currentConfig + '-';
},
/**
* Add a new provider
* @returns {number} id of the provider
*/
addProvider: function(callback) {
var providerIds = OCA.User_SAML.Admin.providerIds.split(',');
var nextId = 1;
if (providerIds.indexOf('1') >= 0) {
nextId = 2;
while ($.inArray('' + nextId, providerIds) >= 0) {
nextId++;
}
}
OCP.AppConfig.setValue('user_saml', 'providerIds', OCA.User_SAML.Admin.providerIds + ',' + nextId, {
success: function () {
OCA.User_SAML.Admin.providerIds += ',' + nextId;
callback(nextId)
}
});
},
removeProvider: function(callback) {
var providerIds = OCA.User_SAML.Admin.providerIds.split(',');
if (providerIds.length > 1) {
var index = providerIds.indexOf(this.currentConfig);
if (index > -1) {
providerIds.splice(index, 1);
}
var config = this.currentConfig;
$.ajax({ url: OC.generateUrl('/apps/user_saml/settings/providerSettings/' + this.currentConfig), type: 'DELETE'})
.done(function(data) {
OCP.AppConfig.setValue('user_saml', 'providerIds', providerIds.join(','), {
success: function () {
OCA.User_SAML.Admin.providerIds = providerIds.join(',');
callback(config);
}
});
});
}
},
setSamlConfigValue: function(category, setting, value, global) {
if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.setSamlConfigValue, this, category, setting, value));
return;
}
// store global config flags without idp prefix
var configIdentifier = this.getConfigIdentifier();
if (global === true) {
configIdentifier = '';
}
OC.msg.startSaving('#user-saml-save-indicator');
OC.AppConfig.setValue('user_saml', category+'-'+setting, value);
OCP.AppConfig.setValue('user_saml', configIdentifier + category + '-' + setting, value);
OC.msg.finishedSaving('#user-saml-save-indicator', {status: 'success', data: {message: t('user_saml', 'Saved')}});
}
}
})(OCA);
$(function() {
// Hide depending on the setup state
var type = $('#user-saml').data('type');
if(type !== '') {
$('#user-saml-choose-type').addClass('hidden');
$('#user-saml-warning-admin-user').removeClass('hidden');
} else {
$('#user-saml div:gt(2)').addClass('hidden');
$('#user-saml-settings .button').addClass('hidden');
}
if(type === 'environment-variable') {
$('#user-saml div:gt(4)').addClass('hidden');
$('#user-saml-settings .button').addClass('hidden');
}
if($('#user-saml-general-require_provisioned_account').val() === '0' && type !== '') {
$('#user-saml-attribute-mapping').toggleClass('hidden');
}
var type = $('#user-saml').data('type');
OCA.User_SAML.Admin.init(function() {
$('.account-list li[data-id="' + OCA.User_SAML.Admin.currentConfig + '"]').addClass('active');
if (OCA.User_SAML.Admin.providerIds.split(',').length <= 1) {
$('[data-js="remove-idp"]').addClass('hidden');
}
// Hide depending on the setup state
if(type !== 'environment-variable' && type !== 'saml') {
$('#user-saml-choose-type').removeClass('hidden');
} else {
$('#user-saml-global').removeClass('hidden');
$('#user-saml-warning-admin-user').removeClass('hidden');
$('#user-saml-settings').removeClass('hidden');
}
if(type === 'environment-variable') {
// we need the settings div to be visible for require_providioned_account
$('#user-saml-settings div').addClass('hidden');
$('#user-saml-settings .button').addClass('hidden');
$('#user-saml-general').removeClass('hidden');
}
if (type === 'saml') {
$('#user-saml .account-list').removeClass('hidden');
$('#user-saml-general').removeClass('hidden');
}
if($('#user-saml-general-require_provisioned_account').val() === '0' && type !== '') {
$('#user-saml-attribute-mapping').removeClass('hidden');
} else {
$('#user-saml-attribute-mapping').addClass('hidden');
}
});
$('#user-saml-choose-saml').click(function(e) {
e.preventDefault();
@ -68,6 +155,66 @@ $(function() {
}
});
var switchProvider = function(providerId) {
$('.account-list li').removeClass('active');
$('.account-list li[data-id="' + providerId + '"]').addClass('active');
OCA.User_SAML.Admin.currentConfig = '' + providerId;
$.get(OC.generateUrl('/apps/user_saml/settings/providerSettings/' + providerId)).done(function(data) {
Object.keys(data).forEach(function(category, index){
var entries = data[category];
Object.keys(entries).forEach(function (configKey) {
var element = $('#user-saml-settings *[data-key="' + configKey + '"]');
if ($('#user-saml-settings #user-saml-' + category + ' #user-saml-' + configKey).length) {
element = $('#user-saml-' + category + ' #user-saml-' + configKey);
}
if ($('#user-saml-settings #user-saml-' + category + ' [name="' + configKey + '"]').length) {
element = $('#user-saml-' + category + ' [name="' + configKey + '"]');
}
if(element.is('input') && element.prop('type') === 'text') {
element.val(entries[configKey])
}
else if(element.is('textarea')) {
element.val(entries[configKey]);
}
else if(element.prop('type') === 'checkbox') {
var value = entries[configKey] === '1' ? '1' : '0';
element.val(value);
} else {
console.log('unable to find element for ' + configKey);
}
});
});
$('input:checkbox[value="1"]').attr('checked', true);
$('input:checkbox[value="0"]').attr('checked', false);
var xmlDownloadButton = $('#get-metadata');
var url = xmlDownloadButton.data('base') + '?idp=' + providerId;
xmlDownloadButton.attr('href', url);
});
};
$('.account-list').on('click', 'li:not(.add-provider):not(.remove-provider)', function() {
var providerId = '' + $(this).data('id');
switchProvider(providerId);
});
$('.account-list .add-provider').on('click', function() {
OCA.User_SAML.Admin.addProvider(function (nextId) {
$('<li data-id="' + nextId + '"><a>' + t('user_saml', 'Provider') + ' ' + nextId + '</a></li>').insertBefore('.account-list .remove-provider');
switchProvider(nextId);
$('[data-js="remove-idp"]').removeClass('hidden');
});
});
$('[data-js="remove-idp"]').on('click', function() {
OCA.User_SAML.Admin.removeProvider(function(currentConfig) {
$('.account-list li[data-id="' + currentConfig + '"]').remove();
switchProvider(OCA.User_SAML.Admin.providerIds.split(',')[0]);
if (OCA.User_SAML.Admin.providerIds.split(',').length <= 1) {
$('[data-js="remove-idp"]').addClass('hidden');
}
});
});
// Enable tabs
$('input:checkbox[value="1"]').attr('checked', true);
@ -105,9 +252,16 @@ $(function() {
var key = $(this).attr('name');
OCA.User_SAML.Admin.setSamlConfigValue('general', key, $(this).val());
}
if(el.data('key') === 'idp0_display_name') {
if ($(this).val() !== '') {
$('.account-list li[data-id=' + OCA.User_SAML.Admin.currentConfig + '] a').text($(this).val())
} else {
$('.account-list li[data-id=' + OCA.User_SAML.Admin.currentConfig + '] a').text(t('user_saml', 'Provider') + ' ' + OCA.User_SAML.Admin.currentConfig);
}
}
});
$('#user-saml-general input[type="checkbox"]').change(function(e) {
$('#user-saml-global input[type="checkbox"]').change(function(e) {
var el = $(this);
$.when(el.focusout()).then(function() {
var key = $(this).attr('name');
@ -119,6 +273,19 @@ $(function() {
if(key === 'require_provisioned_account') {
$('#user-saml-attribute-mapping').toggleClass('hidden');
}
OCA.User_SAML.Admin.setSamlConfigValue('general', key, $(this).val(), true);
});
});
$('#user-saml-general input[type="checkbox"]').change(function(e) {
var el = $(this);
$.when(el.focusout()).then(function() {
var key = $(this).attr('name');
if($(this).val() === "0") {
$(this).val("1");
} else {
$(this).val("0");
}
OCA.User_SAML.Admin.setSamlConfigValue('general', key, $(this).val());
});
});

View file

@ -97,7 +97,8 @@ class SAMLController extends Controller {
* @throws NoUserFoundException
*/
private function autoprovisionIfPossible(array $auth) {
$uidMapping = $this->config->getAppValue('user_saml', 'general-uid_mapping');
$prefix = $this->SAMLSettings->getPrefix();
$uidMapping = $this->config->getAppValue('user_saml', $prefix . 'general-uid_mapping');
if(isset($auth[$uidMapping])) {
if(is_array($auth[$uidMapping])) {
$uid = $auth[$uidMapping][0];
@ -144,17 +145,19 @@ class SAMLController extends Controller {
* @UseSession
* @OnlyUnauthenticatedUsers
*
* @param int $idp id of the idp
* @return Http\RedirectResponse
* @throws \Exception
*/
public function login() {
public function login($idp) {
$type = $this->config->getAppValue($this->appName, 'type');
switch($type) {
case 'saml':
$auth = new \OneLogin_Saml2_Auth($this->SAMLSettings->getOneLoginSettingsArray());
$auth = new \OneLogin_Saml2_Auth($this->SAMLSettings->getOneLoginSettingsArray($idp));
$ssoUrl = $auth->login(null, [], false, false, true);
$this->session->set('user_saml.AuthNRequestID', $auth->getLastRequestID());
$this->session->set('user_saml.OriginalUrl', $this->request->getParam('originalUrl', ''));
$this->session->set('user_saml.Idp', $idp);
break;
case 'environment-variable':
$ssoUrl = $this->urlGenerator->getAbsoluteURL('/');
@ -185,9 +188,12 @@ class SAMLController extends Controller {
/**
* @PublicPage
* @NoCSRFRequired
* @param int $idp
* @return Http\DataDownloadResponse
* @throws \OneLogin_Saml2_Error
*/
public function getMetadata() {
$settings = new \OneLogin_Saml2_Settings($this->SAMLSettings->getOneLoginSettingsArray());
public function getMetadata($idp) {
$settings = new \OneLogin_Saml2_Settings($this->SAMLSettings->getOneLoginSettingsArray($idp));
$metadata = $settings->getSPMetadata();
$errors = $settings->validateMetadata($metadata);
if (empty($errors)) {
@ -211,11 +217,12 @@ class SAMLController extends Controller {
*/
public function assertionConsumerService() {
$AuthNRequestID = $this->session->get('user_saml.AuthNRequestID');
if(is_null($AuthNRequestID) || $AuthNRequestID === '') {
$idp = $this->session->get('user_saml.Idp');
if(is_null($AuthNRequestID) || $AuthNRequestID === '' || is_null($idp)) {
return;
}
$auth = new \OneLogin_Saml2_Auth($this->SAMLSettings->getOneLoginSettingsArray());
$auth = new \OneLogin_Saml2_Auth($this->SAMLSettings->getOneLoginSettingsArray($idp));
$auth->processResponse($AuthNRequestID);
$errors = $auth->getErrors();
@ -279,7 +286,8 @@ class SAMLController extends Controller {
*/
public function singleLogoutService() {
if($this->request->passesCSRFCheck()) {
$auth = new \OneLogin_Saml2_Auth($this->SAMLSettings->getOneLoginSettingsArray());
$idp = $this->session->get('user_saml.Idp');
$auth = new \OneLogin_Saml2_Auth($this->SAMLSettings->getOneLoginSettingsArray($idp));
$returnTo = null;
$parameters = array();
$nameId = $this->session->get('user_saml.samlNameId');
@ -325,26 +333,48 @@ class SAMLController extends Controller {
* @return Http\TemplateResponse
*/
public function selectUserBackEnd($redirectUrl) {
$loginUrls = [
'directLogin' => [
'url' => $this->getDirectLoginUrl($redirectUrl),
$loginUrls = [];
if ($this->SAMLSettings->allowMultipleUserBackEnds()) {
$loginUrls['directLogin'] = [
'url' => $this->getDirectLoginUrl(),
'display-name' => $this->l->t('Direct log in')
],
'ssoLogin' => [
'url' => $this->getSSOUrl($redirectUrl),
'display-name' => $this->getSSODisplayName(),
]
];
];
}
$loginUrls['ssoLogin'] = $this->getIdps($redirectUrl);
return new Http\TemplateResponse($this->appName, 'selectUserBackEnd', $loginUrls, 'guest');
}
/**
* get the IdPs showed at the login page
*
* @param $redirectUrl
* @return array
*/
private function getIdps($redirectUrl) {
$result = [];
$idps = $this->SAMLSettings->getListOfIdps();
foreach ($idps as $idpId => $displayName) {
$result[] = [
'url' => $this->getSSOUrl($redirectUrl, $idpId),
'display-name' => $this->getSSODisplayName($displayName),
];
}
return $result;
}
/**
* get SSO URL
*
* @param $redirectUrl
* @param idp identifier
* @return string
*/
private function getSSOUrl($redirectUrl) {
private function getSSOUrl($redirectUrl, $idp) {
$originalUrl = '';
if(!empty($redirectUrl)) {
@ -358,6 +388,7 @@ class SAMLController extends Controller {
[
'requesttoken' => $csrfToken->getEncryptedValue(),
'originalUrl' => $originalUrl,
'idp' => $idp
]
);
@ -368,10 +399,10 @@ class SAMLController extends Controller {
/**
* return the display name of the SSO identity provider
*
* @param $displayName
* @return string
*/
protected function getSSODisplayName() {
$displayName = $this->config->getAppValue('user_saml', 'general-idp0_display_name');
protected function getSSODisplayName($displayName) {
if (empty($displayName)) {
$displayName = $this->l->t('SSO & SAML log in');
}

View file

@ -0,0 +1,118 @@
<?php
/**
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\User_SAML\Controller;
use OCA\User_SAML\Settings\Admin;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
use OCP\IConfig;
use OCP\IRequest;
class SettingsController extends Controller {
/** @var IConfig */
private $config;
/** @var Admin */
private $admin;
public function __construct($appName,
IRequest $request,
IConfig $config,
Admin $admin) {
parent::__construct($appName, $request);
$this->config = $config;
$this->admin = $admin;
}
/**
* @param $providerId
* @return array of categories containing entries for each config parameter with their value
*/
public function getSamlProviderSettings($providerId) {
/**
* This uses the list of available config parameters from the admin section
* and extends it with fields that are not coming from \OCA\User_SAML\Settings\Admin
*/
$params = $this->admin->getForm()->getParams();
$params['idp'] = [
'singleLogoutService.url' => ['required' => false],
'singleSignOnService.url' => ['required' => false],
'entityId' => ['required' => false],
'x509cert' => ['required' => false],
];
/* Fetch all config values for the given providerId */
$settings = [];
foreach ($params as $category => $content) {
if (empty($content) || $category === 'providers' || $category === 'type') {
continue;
}
foreach ($content as $setting => $details) {
$prefix = $providerId === '1' ? '' : $providerId . '-';
/* use security as category instead of security-* */
if (strpos($category, 'security-') === 0) {
$category = 'security';
}
// make sure we properly fetch the attribute mapping
// as this is the only category that has the saml- prefix on config keys
if (strpos($category, 'attribute-mapping') === 0) {
$category = 'attribute-mapping';
$key = $prefix . 'saml-attribute-mapping' . '-' . $setting;
} else {
$key = $prefix . $category . '-' . $setting;
}
$settings[$category][$setting] = $this->config->getAppValue('user_saml', $key, '');
}
}
return $settings;
}
public function deleteSamlProviderSettings($providerId) {
$params = $this->admin->getForm()->getParams();
$params['idp'] = [
'singleLogoutService.url' => null,
'singleSignOnService.url' => null,
'idp-entityId' => null,
];
/* Fetch all config values for the given providerId */
foreach ($params as $category => $content) {
if (empty($content) || $category === 'providers') {
continue;
}
foreach ($content as $setting => $details) {
if ($details['global']) {
continue;
}
$prefix = $providerId === '1' ? '' : $providerId . '-';
$key = $prefix . $category . '-' . $setting;
/* use security as category instead of security-* */
if (strpos($category, 'security-') === 0) {
$category = 'security';
}
$this->config->deleteAppValue('user_saml', $key);
}
}
return new Response();
}
}

View file

@ -24,6 +24,7 @@ namespace OCA\User_SAML;
use OCP\AppFramework\Http;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
class SAMLSettings {
@ -33,39 +34,87 @@ class SAMLSettings {
private $config;
/** @var IRequest */
private $request;
/** @var ISession */
private $session;
/** @var array list of global settings which are valid for every idp */
private $globalSettings = ['general-require_provisioned_account', 'general-allow_multiple_user_back_ends', 'general-use_saml_auth_for_desktop'];
/**
* @param IURLGenerator $urlGenerator
* @param IConfig $config
* @param IRequest $request
* @param ISession $session
*/
public function __construct(IURLGenerator $urlGenerator,
IConfig $config,
IRequest $request) {
IRequest $request,
ISession $session) {
$this->urlGenerator = $urlGenerator;
$this->config = $config;
$this->request = $request;
$this->session = $session;
}
public function getOneLoginSettingsArray() {
/**
* get list of the configured IDPs
*
* @return array
*/
public function getListOfIdps() {
$result = [];
$providerIds = explode(',', $this->config->getAppValue('user_saml', 'providerIds', '1'));
natsort($providerIds);
foreach ($providerIds as $id) {
$prefix = $id === '1' ? '' : $id .'-';
$result[$id] = $this->config->getAppValue('user_saml', $prefix . 'general-idp0_display_name', '');
}
return $result;
}
/**
* check if multiple user back ends are allowed
*
* @return bool
*/
public function allowMultipleUserBackEnds() {
$setting = $this->config->getAppValue('user_saml', 'general-allow_multiple_user_back_ends', '0');
return $setting === '1';
}
/**
* get config for given IDP
*
* @param int $idp
* @return array
*/
public function getOneLoginSettingsArray($idp) {
$prefix = '';
if ($idp > 1) {
$prefix = $idp . '-';
}
$settings = [
'strict' => true,
'debug' => $this->config->getSystemValue('debug', false),
'baseurl' => $this->request->getServerProtocol() . '://' . $this->request->getServerHost(),
'security' => [
'nameIdEncrypted' => ($this->config->getAppValue('user_saml', 'security-nameIdEncrypted', '0') === '1') ? true : false,
'authnRequestsSigned' => ($this->config->getAppValue('user_saml', 'security-authnRequestsSigned', '0') === '1') ? true : false,
'logoutRequestSigned' => ($this->config->getAppValue('user_saml', 'security-logoutRequestSigned', '0') === '1') ? true : false,
'logoutResponseSigned' => ($this->config->getAppValue('user_saml', 'security-logoutResponseSigned', '0') === '1') ? true : false,
'signMetadata' => ($this->config->getAppValue('user_saml', 'security-signMetadata', '0') === '1') ? true : false,
'wantMessagesSigned' => ($this->config->getAppValue('user_saml', 'security-wantMessagesSigned', '0') === '1') ? true : false,
'wantAssertionsSigned' => ($this->config->getAppValue('user_saml', 'security-wantAssertionsSigned', '0') === '1') ? true : false,
'wantAssertionsEncrypted' => ($this->config->getAppValue('user_saml', 'security-wantAssertionsEncrypted', '0') === '1') ? true : false,
'wantNameId' => ($this->config->getAppValue('user_saml', 'security-wantNameId', '0') === '1') ? true : false,
'wantNameIdEncrypted' => ($this->config->getAppValue('user_saml', 'security-wantNameIdEncrypted', '0') === '1') ? true : false,
'wantXMLValidation' => ($this->config->getAppValue('user_saml', 'security-wantXMLValidation', '0') === '1') ? true : false,
'nameIdEncrypted' => ($this->config->getAppValue('user_saml', $prefix . 'security-nameIdEncrypted', '0') === '1') ? true : false,
'authnRequestsSigned' => ($this->config->getAppValue('user_saml', $prefix . 'security-authnRequestsSigned', '0') === '1') ? true : false,
'logoutRequestSigned' => ($this->config->getAppValue('user_saml', $prefix . 'security-logoutRequestSigned', '0') === '1') ? true : false,
'logoutResponseSigned' => ($this->config->getAppValue('user_saml', $prefix . 'security-logoutResponseSigned', '0') === '1') ? true : false,
'signMetadata' => ($this->config->getAppValue('user_saml', $prefix . 'security-signMetadata', '0') === '1') ? true : false,
'wantMessagesSigned' => ($this->config->getAppValue('user_saml', $prefix . 'security-wantMessagesSigned', '0') === '1') ? true : false,
'wantAssertionsSigned' => ($this->config->getAppValue('user_saml', $prefix . 'security-wantAssertionsSigned', '0') === '1') ? true : false,
'wantAssertionsEncrypted' => ($this->config->getAppValue('user_saml', $prefix . 'security-wantAssertionsEncrypted', '0') === '1') ? true : false,
'wantNameId' => ($this->config->getAppValue('user_saml', $prefix . 'security-wantNameId', '0') === '1') ? true : false,
'wantNameIdEncrypted' => ($this->config->getAppValue('user_saml', $prefix . 'security-wantNameIdEncrypted', '0') === '1') ? true : false,
'wantXMLValidation' => ($this->config->getAppValue('user_saml', $prefix . 'security-wantXMLValidation', '0') === '1') ? true : false,
'requestedAuthnContext' => false,
'lowercaseUrlencoding' => ($this->config->getAppValue('user_saml', 'security-lowercaseUrlencoding', '0') === '1') ? true : false,
'lowercaseUrlencoding' => ($this->config->getAppValue('user_saml', $prefix . 'security-lowercaseUrlencoding', '0') === '1') ? true : false,
],
'sp' => [
'entityId' => $this->urlGenerator->linkToRouteAbsolute('user_saml.SAML.getMetadata'),
@ -74,15 +123,15 @@ class SAMLSettings {
],
],
'idp' => [
'entityId' => $this->config->getAppValue('user_saml', 'idp-entityId', ''),
'entityId' => $this->config->getAppValue('user_saml', $prefix . 'idp-entityId', ''),
'singleSignOnService' => [
'url' => $this->config->getAppValue('user_saml', 'idp-singleSignOnService.url', ''),
'url' => $this->config->getAppValue('user_saml', $prefix . 'idp-singleSignOnService.url', ''),
],
],
];
$spx509cert = $this->config->getAppValue('user_saml', 'sp-x509cert', '');
$spxprivateKey = $this->config->getAppValue('user_saml', 'sp-privateKey', '');
$spx509cert = $this->config->getAppValue('user_saml', $prefix . 'sp-x509cert', '');
$spxprivateKey = $this->config->getAppValue('user_saml', $prefix . 'sp-privateKey', '');
if($spx509cert !== '') {
$settings['sp']['x509cert'] = $spx509cert;
}
@ -90,15 +139,15 @@ class SAMLSettings {
$settings['sp']['privateKey'] = $spxprivateKey;
}
$idpx509cert = $this->config->getAppValue('user_saml', 'idp-x509cert', '');
$idpx509cert = $this->config->getAppValue('user_saml', $prefix . 'idp-x509cert', '');
if($idpx509cert !== '') {
$settings['idp']['x509cert'] = $idpx509cert;
}
$slo = $this->config->getAppValue('user_saml', 'idp-singleLogoutService.url', '');
$slo = $this->config->getAppValue('user_saml', $prefix . 'idp-singleLogoutService.url', '');
if($slo !== '') {
$settings['idp']['singleLogoutService'] = [
'url' => $this->config->getAppValue('user_saml', 'idp-singleLogoutService.url', ''),
'url' => $this->config->getAppValue('user_saml', $prefix . 'idp-singleLogoutService.url', ''),
];
$settings['sp']['singleLogoutService'] = [
'url' => $this->urlGenerator->linkToRouteAbsolute('user_saml.SAML.singleLogoutService'),
@ -107,5 +156,26 @@ class SAMLSettings {
return $settings;
}
}
/**
* calculate prefix for config values
*
* @param string name of the setting
* @return string
*/
public function getPrefix($setting = '') {
$prefix = '';
if (!empty($setting) && in_array($setting, $this->globalSettings)) {
return $prefix;
}
$idp = $this->session->get('user_saml.Idp');
if ((int)$idp > 1) {
$prefix = $idp . '-';
}
return $prefix;
}
}

View file

@ -54,6 +54,17 @@ class Admin implements ISettings {
* @return TemplateResponse
*/
public function getForm() {
$providerIds = explode(',', $this->config->getAppValue('user_saml', 'providerIds', '1'));
natsort($providerIds);
$providers = [];
foreach ($providerIds as $id) {
$prefix = $id === '1' ? '' : $id .'-';
$name = $this->config->getAppValue('user_saml', $prefix . 'general-idp0_display_name', '');
$providers[] = [
'id' => $id,
'name' => $name === '' ? $this->l10n->t('Provider ') . $id : $name
];
}
$serviceProviderFields = [
'x509cert' => $this->l10n->t('X.509 certificate of the Service Provider'),
'privateKey' => $this->l10n->t('Private key of the Service Provider'),
@ -90,10 +101,13 @@ class Admin implements ISettings {
'require_provisioned_account' => [
'text' => $this->l10n->t('Only allow authentication if an account exists on some other backend. (e.g. LDAP)'),
'type' => 'checkbox',
'global' => true,
],
'allow_multiple_user_back_ends' => [
'text' => $this->l10n->t('Allow the use of multiple user back-ends (e.g. LDAP)'),
'type' => 'checkbox',
'hideForEnv' => true,
'global' => true,
],
];
$attributeMappingSettings = [
@ -124,6 +138,7 @@ class Admin implements ISettings {
$generalSettings['use_saml_auth_for_desktop'] = [
'text' => $this->l10n->t('Use SAML auth for the %s desktop clients (requires user re-authentication)', [$this->defaults->getName()]),
'type' => 'checkbox',
'global' => true,
];
}
@ -133,8 +148,9 @@ class Admin implements ISettings {
'security-required' => $securityRequiredFields,
'security-general' => $securityGeneral,
'general' => $generalSettings,
'attributeMappings' => $attributeMappingSettings,
'attribute-mapping' => $attributeMappingSettings,
'type' => $type,
'providers' => $providers
];
return new TemplateResponse('user_saml', 'admin', $params);

View file

@ -48,6 +48,8 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
private $groupManager;
/** @var \OCP\UserInterface[] */
private static $backends = [];
/** @var SAMLSettings */
private $settings;
/**
* @param IConfig $config
@ -56,19 +58,22 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
* @param IDBConnection $db
* @param IUserManager $userManager
* @param IGroupManager $groupManager
* @param SAMLSettings $settings
*/
public function __construct(IConfig $config,
IURLGenerator $urlGenerator,
ISession $session,
IDBConnection $db,
IUserManager $userManager,
IGroupManager $groupManager) {
IGroupManager $groupManager,
SAMLSettings $settings) {
$this->config = $config;
$this->urlGenerator = $urlGenerator;
$this->session = $session;
$this->db = $db;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->settings = $settings;
}
/**
@ -344,7 +349,8 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
* {@inheritdoc}
*/
public function getLogoutUrl() {
$slo = $this->config->getAppValue('user_saml', 'idp-singleLogoutService.url', '');
$prefix = $this->settings->getPrefix();
$slo = $this->config->getAppValue('user_saml', $prefix . 'idp-singleLogoutService.url', '');
if($slo === '') {
return '';
}
@ -373,7 +379,8 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
*/
public function getCurrentUserId() {
$samlData = $this->session->get('user_saml.samlUserData');
$uidMapping = $this->config->getAppValue('user_saml', 'general-uid_mapping', '');
$prefix = $this->settings->getPrefix();
$uidMapping = $this->config->getAppValue('user_saml', $prefix . 'general-uid_mapping', '');
if($uidMapping !== '' && isset($samlData[$uidMapping])) {
if(is_array($samlData[$uidMapping])) {
@ -437,7 +444,8 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
private function getAttributeKeys($name)
{
$keys = explode(' ', $this->config->getAppValue('user_saml', $name, ''));
$prefix = $this->settings->getPrefix($name);
$keys = explode(' ', $this->config->getAppValue('user_saml', $prefix . $name, ''));
if (count($keys) === 1 && $keys[0] === '') {
throw new \InvalidArgumentException('Attribute is not configured');

View file

@ -10,40 +10,71 @@ style('user_saml', 'admin');
title="<?php p($l->t('Open documentation'));?>"
href="<?php p(link_to_docs('admin-sso')); ?>"></a>
<div id="user-saml-save-indicator" class="msg success inlineblock" style="display: none;">Saved</div>
<div id="user-saml-save-indicator" class="msg success inlineblock" style="display: none;"><?php p($l->t('Saved')); ?></div>
<div id="user-saml-settings">
<div id="user-saml-choose-type">
<?php p($l->t('Please choose whether you want to authenticate using the SAML provider built-in in Nextcloud or whether you want to authenticate against an environment variable.')) ?>
<br/>
<button id="user-saml-choose-saml"><?php p($l->t('Use built-in SAML authentication')) ?></button>
<button id="user-saml-choose-env"><?php p($l->t('Use environment variable')) ?></button>
</div>
<div class="warning hidden" id="user-saml-warning-admin-user">
<?php p(
$l->t(
'Make sure to configure an administrative user that can access the instance via SSO. Logging-in with your regular %s account won\'t be possible anymore, unless you enabled "%s"',
[
$theme->getEntity(),
$_['general']['allow_multiple_user_back_ends']['text']
]
)
<div class="warning hidden" id="user-saml-warning-admin-user">
<?php p(
$l->t(
'Make sure to configure an administrative user that can access the instance via SSO. Logging-in with your regular %s account won\'t be possible anymore, unless you enabled "%s"',
[
$theme->getEntity(),
$_['general']['allow_multiple_user_back_ends']['text']
]
)
?>
</div>
)
?>
</div>
<div id="user-saml-general">
<h3><?php p($l->t('General')) ?></h3>
<div id="user-saml-choose-type" class="hidden">
<?php p($l->t('Please choose whether you want to authenticate using the SAML provider built-in in Nextcloud or whether you want to authenticate against an environment variable.')) ?>
<br/>
<button id="user-saml-choose-saml"><?php p($l->t('Use built-in SAML authentication')) ?></button>
<button id="user-saml-choose-env"><?php p($l->t('Use environment variable')) ?></button>
</div>
<div id="user-saml-global" class="hidden">
<h3><?php p($l->t('Global settings')) ?></h3>
<?php foreach($_['general'] as $key => $attribute): ?>
<?php if($attribute['type'] === 'checkbox' && $attribute['global']): ?>
<p>
<input type="checkbox" data-key="<?php p($key)?>" id="user-saml-general-<?php p($key)?>" name="<?php p($key)?>" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'general-'.$key, '0')) ?>">
<label for="user-saml-general-<?php p($key)?>"><?php p($attribute['text']) ?></label><br/>
</p>
<?php elseif($attribute['type'] === 'line' && $attribute['global']): ?>
<p>
<input data-key="<?php p($key)?>" name="<?php p($key) ?>" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'general-'.$key, '')) ?>" type="text" <?php if(isset($attribute['required']) && $attribute['required'] === true): ?>class="required"<?php endif;?> placeholder="<?php p($attribute['text']) ?>"/>
</p>
<?php endif; ?>
<?php endforeach; ?>
</div>
<ul class="account-list hidden">
<?php foreach ($_['providers'] as $provider) { ?>
<li data-id="<?php p($provider['id']); ?>">
<a href="#"><?php p($provider['name']); ?></a>
</li>
<?php } ?>
<li class="remove-provider"><a data-js="remove-idp" class="icon-delete"><span class="hidden-visually"><?php p($l->t('Remove identity provider')); ?></span></a></li>
<li class="add-provider"><a href="#" class="button"><span class="icon-add"></span> <?php p($l->t('Add identity provider')); ?></a></li>
</ul>
<div id="user-saml-settings" class="hidden">
<div id="user-saml-general" class="hidden">
<h3>
<?php p($l->t('General')) ?>
</h3>
<?php foreach($_['general'] as $key => $attribute): ?>
<?php if($attribute['type'] === 'checkbox'): ?>
<?php if($attribute['type'] === 'checkbox' && !$attribute['global']): ?>
<p>
<input type="checkbox" id="user-saml-general-<?php p($key)?>" name="<?php p($key)?>" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'general-'.$key, '0')) ?>">
<input type="checkbox" data-key="<?php p($key)?>" id="user-saml-general-<?php p($key)?>" name="<?php p($key)?>" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'general-'.$key, '0')) ?>">
<label for="user-saml-general-<?php p($key)?>"><?php p($attribute['text']) ?></label><br/>
</p>
<?php elseif($attribute['type'] === 'line'): ?>
<?php elseif($attribute['type'] === 'line' && !$attribute['global']): ?>
<p>
<input name="<?php p($key) ?>" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'general-'.$key, '')) ?>" type="text" <?php if(isset($attribute['required']) && $attribute['required'] === true): ?>class="required"<?php endif;?> placeholder="<?php p($attribute['text']) ?>"/>
<input data-key="<?php p($key)?>" name="<?php p($key) ?>" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'general-'.$key, '')) ?>" type="text" <?php if(isset($attribute['required']) && $attribute['required'] === true): ?>class="required"<?php endif;?> placeholder="<?php p($attribute['text']) ?>"/>
</p>
<?php endif; ?>
<?php endforeach; ?>
@ -72,7 +103,7 @@ style('user_saml', 'admin');
<?php print_unescaped($l->t('Configure your IdP settings here.')) ?>
</p>
<p><input name="entityId" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'idp-entityId', '')) ?>" type="text" class="required" placeholder="<?php p($l->t('Identifier of the IdP entity (must be a URI)')) ?>"/></p>
<p><input data-key="idp-entityId" name="entityId" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'idp-entityId', '')) ?>" type="text" class="required" placeholder="<?php p($l->t('Identifier of the IdP entity (must be a URI)')) ?>"/></p>
<p><input name="singleSignOnService.url" value="<?php p(\OC::$server->getConfig()->getAppValue('user_saml', 'idp-singleSignOnService.url', '')) ?>" type="text" class="required" placeholder="<?php p($l->t('URL Target of the IdP where the SP will send the Authentication Request Message')) ?>"/></p>
<p><span class="toggle"><?php p($l->t('Show optional Identity Provider settings…')) ?></span></p>
<div class="hidden">
@ -89,7 +120,7 @@ style('user_saml', 'admin');
</p>
<div class="hidden">
<?php foreach($_['attributeMappings'] as $key => $attribute): ?>
<?php foreach($_['attribute-mapping'] as $key => $attribute): ?>
<?php
if($attribute['type'] === 'line'): ?>
<p>
@ -131,7 +162,10 @@ style('user_saml', 'admin');
</div>
</div>
<a href="<?php p(\OC::$server->getURLGenerator()->linkToRoute('user_saml.SAML.getMetadata')) ?>" class="button"><?php p($l->t('Download metadata XML')) ?></a>
<a id="get-metadata" data-base="<?php p(\OC::$server->getURLGenerator()->linkToRoute('user_saml.SAML.getMetadata')); ?>"
href="<?php p(\OC::$server->getURLGenerator()->linkToRoute('user_saml.SAML.getMetadata', ['idp' => $_['providers'][0]['id']])) ?>" class="button">
<?php p($l->t('Download metadata XML')) ?>
</a>
<span class="warning hidden" id="user-saml-settings-incomplete"><?php p($l->t('Metadata invalid')) ?></span>
<span class="success hidden" id="user-saml-settings-complete"><?php p($l->t('Metadata valid')) ?></span>
</div>

View file

@ -9,12 +9,16 @@ style('user_saml', 'selectUserBackEnd');
<h1>Choose login option:</h1>
<?php if(isset($_['directLogin'])) : ?>
<div class="login-option">
<a href="<?php p($_['directLogin']['url']); ?>"><?php p($_['directLogin']['display-name']); ?></a>
</div>
<?php endif; ?>
<?php foreach ($_['ssoLogin'] as $idp) { ?>
<div class="login-option">
<a href="<?php p($_['ssoLogin']['url']); ?>"><?php p($_['ssoLogin']['display-name']); ?></a>
<a href="<?php p($idp['url']); ?>"><?php p($idp['display-name']); ?></a>
</div>
<?php } ?>
</div>

View file

@ -105,6 +105,7 @@ class FeatureContext implements Context {
'headers' => [
'Accept' => 'text/html',
],
'query' => ['idp' => 1],
]
);
}

View file

@ -64,6 +64,22 @@ class Test extends TestCase {
'url' => '/saml/selectUserBackEnd',
'verb' => 'GET',
],
[
'name' => 'Settings#getSamlProviderSettings',
'url' => '/settings/providerSettings/{providerId}',
'verb' => 'GET',
'defaults' => [
'providerId' => '1'
]
],
[
'name' => 'Settings#deleteSamlProviderSettings',
'url' => '/settings/providerSettings/{providerId}',
'verb' => 'DELETE',
'defaults' => [
'providerId' => '1'
]
],
],
];
$this->assertSame($expected, $routes);

View file

@ -106,7 +106,7 @@ class SAMLControllerTest extends TestCase {
->method('getAppValue')
->with('user_saml', 'type')
->willReturn('UnknownValue');
$this->samlController->login();
$this->samlController->login(1);
}
public function testLoginWithEnvVariableAndNotExistingUidInSettingsArray() {
@ -135,7 +135,7 @@ class SAMLControllerTest extends TestCase {
->willReturn('https://nextcloud.com/notProvisioned/');
$expected = new RedirectResponse('https://nextcloud.com/notProvisioned/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
@ -185,7 +185,7 @@ class SAMLControllerTest extends TestCase {
->method('updateLastLoginTimestamp');
$expected = new RedirectResponse('https://nextcloud.com/absolute/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
public function testLoginWithEnvVariableAndExistingUserAndArray() {
@ -234,7 +234,7 @@ class SAMLControllerTest extends TestCase {
->willReturn('https://nextcloud.com/absolute/');
$expected = new RedirectResponse('https://nextcloud.com/absolute/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
public function testLoginWithEnvVariableAndNotExistingUserWithProvisioning() {
@ -291,7 +291,7 @@ class SAMLControllerTest extends TestCase {
->method('updateLastLoginTimestamp');
$expected = new RedirectResponse('https://nextcloud.com/absolute/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
public function testLoginWithEnvVariableAndNotExistingUserWithMalfunctioningBackend() {
@ -343,7 +343,7 @@ class SAMLControllerTest extends TestCase {
->willReturn(null);
$expected = new RedirectResponse('https://nextcloud.com/notprovisioned/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
public function testLoginWithEnvVariableAndNotExistingUserWithoutProvisioning() {
@ -382,7 +382,7 @@ class SAMLControllerTest extends TestCase {
->willReturn(false);
$expected = new RedirectResponse('https://nextcloud.com/notprovisioned/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
public function testLoginWithEnvVariableAndNotYetMappedUserWithoutProvisioning() {
@ -433,7 +433,7 @@ class SAMLControllerTest extends TestCase {
->willReturn('MyUid');
$expected = new RedirectResponse('https://nextcloud.com/absolute/');
$this->assertEquals($expected, $this->samlController->login());
$this->assertEquals($expected, $this->samlController->login(1));
}
public function testNotProvisioned() {
@ -466,11 +466,7 @@ class SAMLControllerTest extends TestCase {
* @param string $expected
*/
public function testGetSSODisplayName($configuredDisplayName, $expected) {
$this->config->expects($this->any())->method('getAppValue')
->with('user_saml', 'general-idp0_display_name')
->willReturn($configuredDisplayName);
$result = $this->invokePrivate($this->samlController, 'getSSODisplayName');
$result = $this->invokePrivate($this->samlController, 'getSSODisplayName', [$configuredDisplayName]);
$this->assertSame($expected, $result);
}

View file

@ -94,14 +94,18 @@ class AdminTest extends \Test\TestCase {
'require_provisioned_account' => [
'text' => 'Only allow authentication if an account exists on some other backend. (e.g. LDAP)',
'type' => 'checkbox',
'global' => true,
],
'use_saml_auth_for_desktop' => [
'text' => 'Use SAML auth for the Nextcloud desktop clients (requires user re-authentication)',
'type' => 'checkbox',
'global' => true,
],
'allow_multiple_user_back_ends' => [
'text' => $this->l10n->t('Allow the use of multiple user back-ends (e.g. LDAP)'),
'type' => 'checkbox',
'global' => true,
'hideForEnv' => true,
],
];
$attributeMappingSettings = [
@ -133,7 +137,11 @@ class AdminTest extends \Test\TestCase {
'security-required' => $securityRequiredFields,
'security-general' => $securityGeneral,
'general' => $generalSettings,
'attributeMappings' => $attributeMappingSettings,
'attribute-mapping' => $attributeMappingSettings,
'providers' => [
['id' => 1, 'name' => 'Provider 1'],
['id' => 2, 'name' => 'Provider 2']
],
];
return $params;
@ -141,7 +149,20 @@ class AdminTest extends \Test\TestCase {
public function testGetFormWithoutType() {
$this->config
->expects($this->once())
->expects($this->at(0))
->method('getAppValue')
->with('user_saml', 'providerIds')
->willReturn('1,2');
$this->config
->expects($this->at(1))
->method('getAppValue')
->willReturn('Provider 1');
$this->config
->expects($this->at(2))
->method('getAppValue')
->willReturn('Provider 2');
$this->config
->expects($this->at(3))
->method('getAppValue')
->with('user_saml', 'type')
->willReturn('');
@ -155,15 +176,28 @@ class AdminTest extends \Test\TestCase {
}
public function testGetFormWithSaml() {
$this->config
->expects($this->at(0))
->method('getAppValue')
->with('user_saml', 'providerIds')
->willReturn('1,2');
$this->config
->expects($this->at(1))
->method('getAppValue')
->willReturn('Provider 1');
$this->config
->expects($this->at(2))
->method('getAppValue')
->willReturn('Provider 2');
$this->config
->expects($this->at(3))
->method('getAppValue')
->with('user_saml', 'type')
->willReturn('saml');
$this->defaults
->expects($this->once())
->method('getName')
->willReturn('Nextcloud');
$this->config
->expects($this->once())
->method('getAppValue')
->with('user_saml', 'type')
->willReturn('saml');
$params = $this->formDataProvider();
$params['type'] = 'saml';

View file

@ -21,6 +21,7 @@
namespace OCA\User_SAML\Tests\Settings;
use OCA\User_SAML\SAMLSettings;
use OCA\User_SAML\UserBackend;
use OCP\IConfig;
use OCP\IDBConnection;
@ -47,6 +48,8 @@ class UserBackendTest extends TestCase {
private $groupManager;
/** @var UserBackend|\PHPUnit_Framework_MockObject_MockObject */
private $userBackend;
/** @var \PHPUnit_Framework_MockObject_MockObject|SAMLSettings */
private $SAMLSettings;
public function setUp() {
parent::setUp();
@ -57,6 +60,7 @@ class UserBackendTest extends TestCase {
$this->db = $this->createMock(IDBConnection::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->groupManager = $this->createMock(IGroupManager::class);
$this->SAMLSettings = $this->getMockBuilder(SAMLSettings::class)->disableOriginalConstructor()->getMock();
}
public function getMockedBuilder(array $mockedFunctions = []) {
@ -68,7 +72,8 @@ class UserBackendTest extends TestCase {
$this->session,
$this->db,
$this->userManager,
$this->groupManager
$this->groupManager,
$this->SAMLSettings
])
->setMethods($mockedFunctions)
->getMock();
@ -79,7 +84,8 @@ class UserBackendTest extends TestCase {
$this->session,
$this->db,
$this->userManager,
$this->groupManager
$this->groupManager,
$this->SAMLSettings
);
}
}