Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ vendor/
!/tests/integration/

.ackrc
tests/unit/.phpunit.result.cache
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The following providers are supported and tested at the moment:
* Any other provider that authenticates using the environment variable

While theoretically any other authentication provider implementing either one of those standards is compatible, we like to note that they are not part of any internal test matrix.]]></description>
<version>6.6.1</version>
<version>6.6.2</version>
<licence>agpl</licence>
<author>Lukas Reschke</author>
<namespace>User_SAML</namespace>
Expand Down
5 changes: 4 additions & 1 deletion lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use OCA\User_SAML\Middleware\OnlyLoggedInMiddleware;
use OCA\User_SAML\SAMLSettings;
use OCA\User_SAML\UserBackend;
use OCA\User_SAML\UserData;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
Expand Down Expand Up @@ -58,7 +59,9 @@ public function register(IRegistrationContext $context): void {
$c->get(ISession::class),
$c->get(IConfig::class),
$_SERVER,
$c->get(SAMLSettings::class)
$c->get(SAMLSettings::class),
$c->get(UserData::class),
$c->get(UserBackend::class),
);
});
}
Expand Down
1 change: 1 addition & 0 deletions lib/Command/ConfigCreate.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Command;

use OC\Core\Command\Base;
Expand Down
1 change: 1 addition & 0 deletions lib/Command/ConfigDelete.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Command;

use OC\Core\Command\Base;
Expand Down
1 change: 1 addition & 0 deletions lib/Command/ConfigGet.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Command;

use OC\Core\Command\Base;
Expand Down
1 change: 1 addition & 0 deletions lib/Command/ConfigSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Command;

use OC\Core\Command\Base;
Expand Down
1 change: 1 addition & 0 deletions lib/Command/GetMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Command;

use OCA\User_SAML\Helper\TXmlHelper;
Expand Down
1 change: 1 addition & 0 deletions lib/Command/GroupMigrationCopyIncomplete.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Command;

use OC\Core\Command\Base;
Expand Down
97 changes: 66 additions & 31 deletions lib/Controller/SAMLController.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
class SAMLController extends Controller {
use TXmlHelper;

/** libxml2 parsing is super-linear and runs before signature checks */
private const DEFAULT_MAX_MESSAGE_SIZE = 1024 * 1024;

public function __construct(
string $appName,
IRequest $request,
Expand Down Expand Up @@ -69,7 +72,7 @@ private function autoprovisionIfPossible(): void {
throw new NoUserFoundException('IDP parameter for the UID not found. Possible parameters are: ' . json_encode(array_keys($auth)));
}

$this->assertGroupMemberships();
$this->userBackend->assertGroupMemberships();

if ($this->userData->getOriginalUid() === '') {
$this->logger->error('Given UID is not valid, please check your attribute mapping', ['app' => $this->appName]);
Expand Down Expand Up @@ -106,34 +109,6 @@ private function autoprovisionIfPossible(): void {
}
}

/**
* @throws UserFilterViolationException
*/
protected function assertGroupMemberships(): void {
if (!$this->userBackend->autoprovisionAllowed()) {
// return early, when users are provided by a different backend
// - mappings are not available/configurable in that case
// - control is solely based on presence and enabled-state of the user
return;
}

$groups = $this->userData->getGroups();
$settings = $this->samlSettings->get($this->session->get('user_saml.Idp') ?? 1);

$rejectGroupsString = $settings['saml-user-filter-reject_groups'] ?? '';
$rejectGroups = array_map('trim', explode(',', $rejectGroupsString));

if (!empty(array_intersect($groups, $rejectGroups))) {
throw new UserFilterViolationException('User is member of a rejection group.');
}

$requireGroupsString = trim($settings['saml-user-filter-require_groups'] ?? '');
$requireGroups = array_map('trim', explode(',', $requireGroupsString));
if (!empty($requireGroupsString) && empty(array_intersect($groups, $requireGroups))) {
throw new UserFilterViolationException('User is not member of a required group.');
}
}

/**
* @PublicPage
* @UseSession
Expand Down Expand Up @@ -164,7 +139,6 @@ public function login(int $idp = 1): Http\RedirectResponse {
}
}


$returnUrl = $originalUrl ?: $this->urlGenerator->linkToRouteAbsolute('user_saml.SAML.login');
$ssoUrl = $auth->login($returnUrl, $passthroughValues, false, false, true);
$response = new Http\RedirectResponse($ssoUrl);
Expand Down Expand Up @@ -313,6 +287,12 @@ public function assertionConsumerService(): Http\RedirectResponse {
return new Http\RedirectResponse($this->urlGenerator->getAbsoluteURL('/'));
}

if (isset($_POST['SAMLResponse']) && !$this->isSamlMessageSizeAcceptable($_POST['SAMLResponse'], false)) {
$response = new Http\RedirectResponse($this->urlGenerator->linkToRouteAbsolute('user_saml.SAML.notProvisioned'));
$response->invalidateCookie('saml_data');
return $response;
}

$auth = new Auth($this->samlSettings->getOneLoginSettingsArray($idp));
// validator (called with processResponse()) needs an XML entity loader
$this->callWithXmlEntityLoader(function () use ($auth, $AuthNRequestID): void {
Expand Down Expand Up @@ -412,6 +392,12 @@ public function singleLogoutService(): Http\RedirectResponse {
$_GET['SAMLRequest'] = $_POST['SAMLRequest'];
}

foreach (['SAMLRequest', 'SAMLResponse'] as $parameter) {
if (isset($_GET[$parameter]) && !$this->isSamlMessageSizeAcceptable($_GET[$parameter], true)) {
return new Http\RedirectResponse($this->urlGenerator->getAbsoluteURL('/'));
}
}

$isFromIDP = !$isFromGS && !empty($_GET['SAMLRequest']);
$idp = null;
if ($isFromIDP) {
Expand Down Expand Up @@ -561,10 +547,59 @@ public function selectUserBackEnd(string $redirectUrl = ''): Http\TemplateRespon

$attributes['useCombobox'] = count($attributes['loginUrls']['ssoLogin']) > 4;


return new Http\TemplateResponse($this->appName, 'selectUserBackEnd', $attributes, 'guest');
}

private function isSamlMessageSizeAcceptable(mixed $encoded, bool $mayBeDeflated): bool {
if (!is_string($encoded)) {
$this->logger->warning('Rejected SAML message: unexpected parameter type');
return false;
}

$maxSize = (int)$this->config->getAppValue('user_saml', 'max_saml_message_size', (string)self::DEFAULT_MAX_MESSAGE_SIZE);
if ($maxSize <= 0) {
return true;
}

if (strlen($encoded) > (int)ceil($maxSize * 4 / 3) + 1024) {
$this->logger->warning('Rejected SAML message: encoded size exceeds limit of {limit} bytes. If this is a legitimate message from your IdP, raise the limit with: occ config:app:set user_saml max_saml_message_size --value=<bytes>', ['limit' => $maxSize]);
return false;
}

$decoded = base64_decode($encoded);
if (strlen($decoded) > $maxSize) {
$this->logger->warning('Rejected SAML message: decoded size exceeds limit of {limit} bytes. If this is a legitimate message from your IdP, raise the limit with: occ config:app:set user_saml max_saml_message_size --value=<bytes>', ['limit' => $maxSize]);
return false;
}

if ($mayBeDeflated && $this->getInflatedSize($decoded, $maxSize) > $maxSize) {
$this->logger->warning('Rejected SAML message: inflated size exceeds limit of {limit} bytes. If this is a legitimate message from your IdP, raise the limit with: occ config:app:set user_saml max_saml_message_size --value=<bytes>', ['limit' => $maxSize]);
return false;
}

return true;
}

/** Inflates incrementally, stopping once $maxSize is exceeded. Returns 0 if not deflated. */
private function getInflatedSize(string $data, int $maxSize): int {
$context = @inflate_init(ZLIB_ENCODING_RAW);
if ($context === false) {
return 0;
}
$size = 0;
foreach (str_split($data, 1024) as $chunk) {
$out = @inflate_add($context, $chunk, ZLIB_SYNC_FLUSH);
if ($out === false) {
return 0;
}
$size += strlen($out);
if ($size > $maxSize) {
return $size;
}
}
return $size;
}

/**
* get the IdPs showed at the login page
*/
Expand Down
9 changes: 9 additions & 0 deletions lib/DavPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace OCA\User_SAML;

use OCA\DAV\Connector\Sabre\Auth;
use OCA\User_SAML\Exceptions\UserFilterViolationException;
use OCP\IConfig;
use OCP\ISession;
use Sabre\DAV\Server;
Expand All @@ -24,6 +25,8 @@ public function __construct(
private IConfig $config,
private array $auth,
private SAMLSettings $samlSettings,
private UserData $userData,
private UserBackend $userBackend,
) {
}

Expand All @@ -40,6 +43,12 @@ public function beforeMethod(RequestInterface $request, ResponseInterface $respo
) {
$uidMapping = $this->samlSettings->get(1)['general-uid_mapping'];
if (isset($this->auth[$uidMapping])) {
$this->userData->setAttributes($this->auth);
try {
$this->userBackend->assertGroupMemberships();
} catch (UserFilterViolationException) {
return;
}
$this->session->set(Auth::DAV_AUTHENTICATED, $this->auth[$uidMapping]);
$this->session->set('user_saml.samlUserData', $this->auth);
}
Expand Down
1 change: 1 addition & 0 deletions lib/Db/ConfigurationsEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Db;

use OCP\AppFramework\Db\Entity;
Expand Down
1 change: 1 addition & 0 deletions lib/Db/ConfigurationsMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Db;

use OCP\AppFramework\Db\DoesNotExistException;
Expand Down
1 change: 1 addition & 0 deletions lib/Exceptions/GroupNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Exceptions;

class GroupNotFoundException extends \RuntimeException {
Expand Down
1 change: 1 addition & 0 deletions lib/Exceptions/NoUserFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Exceptions;

/**
Expand Down
1 change: 1 addition & 0 deletions lib/Exceptions/NonMigratableGroupException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Exceptions;

class NonMigratableGroupException extends \RuntimeException {
Expand Down
1 change: 1 addition & 0 deletions lib/Exceptions/UserFilterViolationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Exceptions;

class UserFilterViolationException extends \Exception {
Expand Down
1 change: 1 addition & 0 deletions lib/Helper/TXmlHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Helper;

trait TXmlHelper {
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/CleanupRemovedConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use OCP\IConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use OC\Group\Database;
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/TransferGroupMembers.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use OCA\User_SAML\Service\GroupMigration;
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/Version3001Date20200630193443.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use Closure;
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/Version5000Date20211025124248.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use Closure;
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/Version6000Date20220912152700.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use Closure;
Expand Down
1 change: 1 addition & 0 deletions lib/Migration/Version6001Date20240202183823.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Migration;

use Closure;
Expand Down
1 change: 1 addition & 0 deletions lib/Service/GroupMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\User_SAML\Service;

use OCA\User_SAML\GroupBackend;
Expand Down
Loading
Loading