Skip to content
Merged
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
2 changes: 2 additions & 0 deletions js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,12 @@ $(function() {
} else {
$(this).val("0");
}

if(key === 'require_provisioned_account') {
$('#user-saml-attribute-mapping').toggleClass('hidden');
$('#user-saml-filtering').toggleClass('hidden');
}

OCA.User_SAML.Admin.setSamlConfigValue('general', key, $(this).val(), true);
});
});
Expand Down
62 changes: 50 additions & 12 deletions lib/Controller/SAMLController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace OCA\User_SAML\Controller;

use Exception;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use OC\Core\Controller\ClientFlowLoginController;
Expand Down Expand Up @@ -34,6 +35,8 @@
use OneLogin\Saml2\Error;
use OneLogin\Saml2\Settings;
use OneLogin\Saml2\ValidationError;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;

class SAMLController extends Controller {
Expand Down Expand Up @@ -140,9 +143,9 @@ protected function assertGroupMemberships(): void {
* @OnlyUnauthenticatedUsers
* @NoCSRFRequired
*
* @throws \Exception
* @throws Exception
*/
public function login(int $idp = 1): Http\RedirectResponse {
public function login(int $idp = 1): Http\RedirectResponse|Http\TemplateResponse {
$originalUrl = (string)$this->request->getParam('originalUrl', '');
if (!$this->trustedDomainHelper->isTrustedUrl($originalUrl)) {
$originalUrl = '';
Expand All @@ -167,7 +170,34 @@ 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);
$settings = $this->samlSettings->get($idp);
$isSAMLRequestUsingPost = isset($settings['general-is_saml_request_using_post']) && $settings['general-is_saml_request_using_post'] === '1';

if ($isSAMLRequestUsingPost) {
$query = parse_url($ssoUrl, PHP_URL_QUERY);
parse_str($query, $params);

$samlRequest = $params['SAMLRequest'];
$relayState = $params['RelayState'] ?? '';
$sigAlg = $params['SigAlg'] ?? '';
$signature = $params['Signature'] ?? '';
$ssoUrl = explode('?', $ssoUrl)[0];

$nonce = base64_encode(random_bytes(16));

$response = new Http\TemplateResponse($this->appName, 'login_post', [
'ssoUrl' => $ssoUrl,
'samlRequest' => $samlRequest,
'relayState' => $relayState,
'sigAlg' => $sigAlg,
'signature' => $signature,
'nonce' => $nonce,
], 'guest');

$response->addHeader('Content-Security-Policy', "script-src 'self' 'nonce-$nonce' 'strict-dynamic' 'unsafe-eval';");
} else {
$response = new Http\RedirectResponse($ssoUrl);
}

// Small hack to make user_saml work with the loginflows
$flowData = [];
Expand Down Expand Up @@ -232,7 +262,7 @@ public function login(int $idp = 1): Http\RedirectResponse {
}
break;
default:
throw new \Exception(
throw new Exception(
sprintf(
'Type of "%s" is not supported for user_saml',
$type
Expand Down Expand Up @@ -289,7 +319,7 @@ public function assertionConsumerService(): Http\RedirectResponse {
// Decrypt and deserialize
try {
$cookie = $this->crypto->decrypt($cookie);
} catch (\Exception) {
} catch (Exception) {
$this->logger->debug('Could not decrypt SAML cookie', ['app' => 'user_saml']);
return new Http\RedirectResponse($this->urlGenerator->getAbsoluteURL('/'));
}
Expand Down Expand Up @@ -371,7 +401,7 @@ public function assertionConsumerService(): Http\RedirectResponse {
}
} catch (NoUserFoundException) {
throw new \InvalidArgumentException('User "' . $this->userBackend->getCurrentUserId() . '" is not valid');
} catch (\Exception $e) {
} catch (Exception $e) {
$this->logger->critical($e->getMessage(), ['exception' => $e, 'app' => $this->appName]);
$response = new Http\RedirectResponse($this->urlGenerator->linkToRouteAbsolute('user_saml.SAML.notProvisioned'));
$response->invalidateCookie('saml_data');
Expand Down Expand Up @@ -417,7 +447,7 @@ public function singleLogoutService(): Http\RedirectResponse {
if ($isFromIDP) {
// requests comes from the IDP so let it manage the logout
// (or raise Error if request is invalid)
$pass = true ;
$pass = true;
} elseif ($isFromGS) {
// Request is from master GlobalScale
$jwt = $this->request->getParam('jwt', '');
Expand All @@ -428,7 +458,7 @@ public function singleLogoutService(): Http\RedirectResponse {

$idp = $decoded['idp'] ?? null;
$pass = true;
} catch (\Exception) {
} catch (Exception) {
}
} else {
// standard request : need read CRSF check
Expand Down Expand Up @@ -581,6 +611,11 @@ private function getIdps(string $redirectUrl): array {
return $result;
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \OCP\DB\Exception
*/
private function getSSOUrl(string $redirectUrl, string $idp): string {
$originalUrl = '';
if (!empty($redirectUrl)) {
Expand All @@ -590,16 +625,19 @@ private function getSSOUrl(string $redirectUrl, string $idp): string {
/** @var CsrfTokenManager $csrfTokenManager */
$csrfTokenManager = Server::get(CsrfTokenManager::class);
$csrfToken = $csrfTokenManager->getToken();
$ssoUrl = $this->urlGenerator->linkToRouteAbsolute(

$settings = $this->samlSettings->get((int)$idp);
$method = $settings['general-is_saml_request_using_post'] ?? 'get';

return $this->urlGenerator->linkToRouteAbsolute(
'user_saml.SAML.login',
[
'requesttoken' => $csrfToken->getEncryptedValue(),
'originalUrl' => $originalUrl,
'idp' => $idp
'idp' => $idp,
'method' => $method,
]
);

return $ssoUrl;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/SAMLSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class SAMLSettings {
public const IDP_CONFIG_KEYS = [
'general-idp0_display_name',
'general-uid_mapping',
'general-is_saml_request_using_post',
'general-saml_request_method',
'idp-entityId',
'idp-singleLogoutService.responseUrl',
'idp-singleLogoutService.url',
Expand Down
7 changes: 6 additions & 1 deletion lib/Settings/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function getForm() {
'text' => $this->l10n->t('Only allow authentication if an account exists on some other backend (e.g. LDAP).'),
'type' => 'checkbox',
'global' => true,
]
],
];
$attributeMappingSettings = [
'displayName_mapping' => [
Expand Down Expand Up @@ -202,6 +202,11 @@ public function getForm() {
'type' => 'line',
'required' => false,
];
$generalSettings['is_saml_request_using_post'] = [
'text' => $this->l10n->t('Use POST method for SAML request (default: GET)'),
'type' => 'checkbox',
'required' => false,
];
$generalSettings['allow_multiple_user_back_ends'] = [
'text' => $this->l10n->t('Allow the use of multiple user back-ends (e.g. LDAP)'),
'type' => 'checkbox',
Expand Down
5 changes: 4 additions & 1 deletion templates/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@
<?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($_['config']['general-' . $key] ?? '0') ?>">
<label for="user-saml-general-<?php p($key)?>"><?php p($attribute['text']) ?></label><br/>
<label for="user-saml-general-<?php p($key)?>"><?php p($attribute['text']) ?></label>
<?php if ($key === 'is_saml_request_using_post'): ?>
<div class="warning"><?php p($l->t('This feature might not work with all identity providers. Use only if your IdP specifically requires POST binding for SAML requests.')) ?></div>
<?php endif; ?>
</p>
<?php elseif ($attribute['type'] === 'line' && !isset($attribute['global'])): ?>
<p>
Expand Down
34 changes: 34 additions & 0 deletions templates/login_post.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

/**
* @var array $_
* @var IL10N $l
*
*/

use OCP\IL10N;

p($l->t('Please wait while you are redirected to the SSO server.'));
?>

<form action="<?= $_['ssoUrl'] ?>" method="post">
<input type="hidden" name="SAMLRequest" value="<?= $_['samlRequest'] ?>" />
<input type="hidden" name="RelayState" value="<?= $_['relayState'] ?>" />
<input type="hidden" name="SigAlg" value="<?= $_['sigAlg'] ?>" />
<input type="hidden" name="Signature" value="<?= $_['signature'] ?>" />
<noscript>
<p>
<?php p($l->t('JavaScript is disabled in your browser. Please enable it to continue.')) ?>
</p>
<input type="submit" value="Continue" />
</noscript>
</form>
<script nonce="<?= $_['nonce'] ?>">
document.addEventListener('DOMContentLoaded', function() {
document.forms[0].submit()
})
</script>
18 changes: 18 additions & 0 deletions tests/integration/features/Shibboleth.feature
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
Feature: Shibboleth

Scenario: Authenticating using Shibboleth with SAML and POST binding and no check if user exists on backend
Given The setting "type" is set to "saml"
And The setting "general-uid_mapping" is set to "urn:oid:0.9.2342.19200300.100.1.1"
And The setting "general-is_saml_request_using_post" is set to "1"
And The setting "idp-entityId" is set to "https://shibboleth-integration-nextcloud.localdomain/idp/shibboleth"
And The setting "idp-singleSignOnService.url" is set to "https://localhost:4443/idp/profile/SAML2/Redirect/SSO"
And The setting "idp-x509cert" is set to "MIIDnTCCAoWgAwIBAgIUGPx9uPjCu7c172IUgV84Tm94pBcwDQYJKoZIhvcNAQEL BQAwNzE1MDMGA1UEAwwsc2hpYmJvbGV0aC1pbnRlZ3JhdGlvbi1uZXh0Y2xvdWQu bG9jYWxkb21haW4wHhcNMTcwMTA0MTAxMTI3WhcNMzcwMTA0MTAxMTI3WjA3MTUw MwYDVQQDDCxzaGliYm9sZXRoLWludGVncmF0aW9uLW5leHRjbG91ZC5sb2NhbGRv bWFpbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKH+bPu45tk8/JRk XOxkyfbxocWZlY4mRumEUxscd3fn0oVzOrdWbHH7lCZV4bus4KxvJljc0Nm2K+Zr LoiRUUnf/LQ4LlehWVm5Kbc4kRgOXS0iGZN3SslAWPKyIg0tywg+TLOBPoS6EtST 1WuYg1JPMFxPfeFDWQ0dQYPlXIJWBFh6F2JMTb0FLECqA5l/ryYE13QisX5l+Mqo 6y3Dh7qIgaH0IJNobXoAcEWza7Kb2RnfhZRh9e0qjZIwBqTJUFM/6I86RYXn829s INUvYQQbez6VkGTdUQJ/GuXb/dD5sMQfOyK8hrRY5MozOmK32cz3JaAzSXpiSRS9 NxFwvicCAwEAAaOBoDCBnTAdBgNVHQ4EFgQUKn8+TV0WXSDeavvF0M8mWn1o8ukw fAYDVR0RBHUwc4Isc2hpYmJvbGV0aC1pbnRlZ3JhdGlvbi1uZXh0Y2xvdWQubG9j YWxkb21haW6GQ2h0dHBzOi8vc2hpYmJvbGV0aC1pbnRlZ3JhdGlvbi1uZXh0Y2xv dWQubG9jYWxkb21haW4vaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQELBQADggEB ABI6uzoIeLZT9Az2KTlLxIc6jZ4MDmhaVja4ZuBxTXEb7BFLfeASEJmQm1wgIMOn pJId3Kh3njW+3tOBWKm7lj8JxVVpAu4yMFSoQGPaVUgYB1AVm+pmAyPLzfJ/XGhf esCU2F/b0eHWcaIb3x+BZFX089Cd/PBtP84MNXdo+TccibxC8N39sr45qJM/7SC7 TfDYU0L4q2WZHJr4S7+0F+F4KaxLx9NzCvN4h6XaoWofZWir2iHO4NzbrVQGC0ei QybS/neBfni4A2g1lyzCb6xFB58JBvNCn7AAnDJULOE7S5XWUKsDAQVQrxTNkUq7 pnhlCQqZDwUdgmIXd1KB1So="
And The setting "security-authnRequestsSigned" is set to "1"
And The setting "security-wantAssertionsEncrypted" is set to "1"
And The setting "sp-x509cert" is set to "-----BEGIN CERTIFICATE-----MIIC+zCCAeOgAwIBAgIJAIgZuvWDBIrdMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzAxMDQxMTM5MjFaFw0yNzAxMDIxMTM5MjFaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN3ESWaDH1JiJTy9yRJQV7kahPOxgBkIH2xwcYDL1k9deKNhSKLx7aGfxE244+HBcC6WLHKVUnOm0ld2qxQ4bMYiJXzZuqL67r07L5wxGAssv12lO92qohGmlHy3+VzRYUBmovu6upqOv3R2F8HBbo7Jc7Hvt7hOEJn/jPuFuF/fHit3mqU8l6IkrIZjpaW8T9fIWOXRq98U4+hkgWpqEZWsqlfE8BxAs9DeIMZab0GxO9stHLp+GYKx10uE4ezFcaDS8W+g2C8enCTt1HXGvcnj4o5zkC1lITGvcFTsiFqfIWyXeSufcxdc0W7HoG6J3ks0WJyK38sfFn0t2Ao6kX0CAwEAAaNQME4wHQYDVR0OBBYEFAoJzX6TVYAwC1GSPe6nObBG54zaMB8GA1UdIwQYMBaAFAoJzX6TVYAwC1GSPe6nObBG54zaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJia9R70uXdUZtgujUPjLas4+sVajzlBFmqhBqpLAo934vljf9HISsHrPtdBcbS0d0rucqXwabDf0MlR18ksnT/NYpsTwMbMx76CrXi4zYEEW5lISKEO65aIkzVTcqKWSuhjtSnRdB6iOLsFiKmNMWXaIKMR5T0+AbR9wdQgn08W+3EEeHGvafVQfE3STVsSgNb1ft7DvcSUnfPXGU7KzvmTpZa0Hfmc7uY4vpdEEhLAdRhgLReS7USZskov7ooiPSoD+JRFi2gM4klBxTemHdNUa9oFnHMXuYKOkLbkgFvHxyy+QlLq2ELQTga5e7I83ZyOfGctyf8Ul6vGw10vbQ=-----END CERTIFICATE-----"
And The setting "sp-privateKey" is set to "-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEA3cRJZoMfUmIlPL3JElBXuRqE87GAGQgfbHBxgMvWT114o2FIovHtoZ/ETbjj4cFwLpYscpVSc6bSV3arFDhsxiIlfNm6ovruvTsvnDEYCyy/XaU73aqiEaaUfLf5XNFhQGai+7q6mo6/dHYXwcFujslzse+3uE4Qmf+M+4W4X98eK3eapTyXoiSshmOlpbxP18hY5dGr3xTj6GSBamoRlayqV8TwHECz0N4gxlpvQbE72y0cun4ZgrHXS4Th7MVxoNLxb6DYLx6cJO3Udca9yePijnOQLWUhMa9wVOyIWp8hbJd5K59zF1zRbsegboneSzRYnIrfyx8WfS3YCjqRfQIDAQABAoIBAQC5CQAdcqZ9vLpJNilBCJxJLCFmm+HAAREHD8MErg9A5UK1P4S1wJp/0qieGPi68wXBOTgY2xKSwMycgb04/+NyZidVRu388takOW/+KNBg8pMxdZ6/05GqnI0kivSbR3CXpYuz8hekwhpo9+fWmKjApsHL47ItK6WaeKmPbAFsq1YJGzfp/DXg7LIvh9GA3C1LWWGV7SuCGOyX/2Moi8xRa7qBtH4hDo/0NRhTx7zjYjlBgNEr330pJUopc3+AtHE40R+xMr2zkGvq9RsCZxYxD2VWbLwQW0yNjWmQ2OTuMgJJvk2+N73QLHcB+tea82ZTszsNzRS9DLtc6qbsKEPZAoGBAO78U3vEuRyY56f/1hpo0xuCDwOkWGzgBQWkjJl6dlyVz/zKkhXBHpEYImyt8XRN0W3iGZYpZ2hCFJGTcDp32R6UiEyGLz0Uc8R/tva/TiRVW1FdNczzSHcB24b9OMK4vE9JLs8mA8Rp8YBgtLr5DDuMfYt/a/rZJbg/HIfIN98nAoGBAO2OInCX93t2I6zzRPIqKtI6q6FYNp64VIQjvw9Y8l0x3IdJZRP9H5C8ZhCeYPsgEqTXcXa4j5hL4rQzoUtxfxflBUUH60bcnd4LGaTCMYLS14G011E3GZlIP0sJi5OjEhy8fq3zt6jVzS9V/lPHB8i+w1D7CbPrMpW7B3k32vC7AoGAX/HvdkYhZyjAAEOG6m1hK68IZhbp5TP+8CgCxm9S65K9wKh3A8LXibrdvzIKOP4w8WOPkCipOkMlTNibeu24vj01hztr5aK7Y40+oEtnjNCz67N3MQQO+LBHOSeaTRqrh01DPKjvZECAU2D/zfzEe3fIw2Nxr3DUYub7hkvMmosCgYAzxbVVypjiLGYsDDyrdmsstCKxoDMPNmcdAVljc+QmUXaZeXJw/8qAVb78wjeqo1vM1zNgR2rsKyW2VkZB1fN39q7GU6qAIBa7zLmDAduegmr7VrlSduq6UFeS9/qWa4TIBICrUqFlR2tXdKtgANF+e6y/mmaL8qdsoH1JetXZfwKBgQC1vscRpdAXivjOOZAh+mzJWzS4BUl4CTJLYYIuOEXikmN5g0EdV2fhUEdkewmyKnXHsd0x83167bYgpTDNs71jUxDHy5NXlg2qIjLkf09X9wr19gBzDApfWzfh3vUqttyMZuQMLVNepGCWM2vjlY9KGl5OvZqY6d+7yO0mLV9GmQ==-----END RSA PRIVATE KEY-----"
And The setting "security-wantAssertionsSigned" is set to "1"
When I send a GET request to "http://localhost:8080/index.php/login"
Then I should be redirected to "http://localhost:8080/index.php/apps/user_saml/saml/login"
And The response should contain the form with action "https://localhost:4443/idp/profile/SAML2/Redirect/SSO"
And The form method should be POST
And The form should contain input fields "SAMLRequest,RelayState,SigAlg,Signature"

Scenario: Authenticating using Shibboleth with SAML and no check if user exists on backend
Given The setting "type" is set to "saml"
And The setting "general-uid_mapping" is set to "urn:oid:0.9.2342.19200300.100.1.1"
Expand Down
95 changes: 95 additions & 0 deletions tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\TableNode;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;

class FeatureContext implements Context {
/** @var \GuzzleHttp\Message\Response */
Expand Down Expand Up @@ -771,4 +773,97 @@ public function iExpectNoBackgroundJobForClassOCAUser_SAMLJobsMigrateGroups(stri
throw new UnexpectedValueException('Background job axctuaslly was enqueued!');
}
}

/**
* @Then The form method should be POST
*/
public function theFormMethodShouldBePost() {
$responseBody = (string)$this->response->getBody();
$domDocument = new DOMDocument();
@$domDocument->loadHTML($responseBody);
$xpath = new DOMXpath($domDocument);
$formElements = $xpath->query("//form[@method='post' or @method='POST']");
if ($formElements->length === 0) {
throw new \Exception("Expected form method 'POST' not found in response");
}
}

/**
* @Then The response should contain the form with action :action
*/
public function theResponseShouldContainTheFormWithAction($action) {
$responseBody = (string)$this->response->getBody();
if (strpos($responseBody, 'action="' . $action . '"') === false) {
throw new \Exception("Expected form action '$action' not found in response");
}
}

/**
* @Then The form should contain input fields :fields
*/
public function theFormShouldContainInputFields($fields) {
$responseBody = (string)$this->response->getBody();
$domDocument = new DOMDocument();
@$domDocument->loadHTML($responseBody);
$xpath = new DOMXpath($domDocument);
$fieldsArray = explode(',', $fields);
foreach ($fieldsArray as $field) {
$inputElements = $xpath->query("//input[@name='" . trim($field) . "']");
if ($inputElements->length === 0) {
throw new \Exception("Expected input field '$field' not found in response");
}
}
}

/**
* @When I submit the SAML form
*/
public function iSubmitTheSAMLForm() {
$responseBody = (string)$this->response->getBody();
$domDocument = new DOMDocument();
@$domDocument->loadHTML($responseBody);
$xpath = new DOMXpath($domDocument);

// Find the form action
$formAction = $xpath->query('//form')->item(0)->getAttribute('action');

// Get the specified hidden input fields
$fields = ['SAMLRequest', 'RelayState', 'SigAlg', 'Signature'];
$postData = [];
foreach ($fields as $field) {
$inputElement = $xpath->query("//input[@type='hidden' and @name='" . $field . "']");
if ($inputElement->length === 0) {
throw new \Exception("Expected hidden input field '$field' not found in response");
}
$postData[$field] = $inputElement->item(0)->getAttribute('value');
}

// Send the POST request with the hidden input data
try {
$this->response = $this->client->request(
'POST',
$formAction,
[
'form_params' => $postData,
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
],
'cookies' => $this->cookieJar,
]
);
} catch (RequestException $e) {
echo 'RequestException: ' . $e->getMessage() . "\n";
if ($e->hasResponse()) {
$response = $e->getResponse();
echo 'Status Code: ' . $response->getStatusCode() . "\n";
echo 'Headers: ' . json_encode($response->getHeaders()) . "\n";
echo 'Body: ' . $response->getBody() . "\n";
echo 'Request Headers: ' . json_encode($e->getRequest()->getHeaders()) . "\n";
echo 'Request Body: ' . $e->getRequest()->getBody() . "\n";
}
} catch (GuzzleException $e) {
echo 'GuzzleException: ' . $e->getMessage() . "\n";
}
}
}
12 changes: 10 additions & 2 deletions tests/unit/Command/GetMetadataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public function testGetMetadata() {
$inputInterface = $this->createMock(InputInterface::class);
$outputInterface = $this->createMock(OutputInterface::class);

$inputInterface->expects($this->any())
->method('getArgument')
->with('idp')
->willReturn('1');

$this->samlSettings->expects($this->any())
->method('getOneLoginSettingsArray')
->willReturn([
Expand All @@ -47,9 +52,12 @@ public function testGetMetadata() {
]
]);

$outputInterface->expects($this->once())->method('writeln')
$outputInterface->expects($this->once())
->method('writeln')
->with($this->stringContains('md:EntityDescriptor'));

$this->invokePrivate($this->GetMetadata, 'execute', [$inputInterface, $outputInterface]);
$result = $this->invokePrivate($this->GetMetadata, 'execute', [$inputInterface, $outputInterface]);

$this->assertEquals(0, $result);
}
}
Loading
Loading