From b2e5c8770e482918b1c0af4b77ac3ec4256e47f9 Mon Sep 17 00:00:00 2001 From: lukasmatusiewicz <77617779+lukasmatusiewicz@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:32:24 +0100 Subject: [PATCH] Update the code --- .../docs/privacyidea.md | 132 +++++++++++------- .../lib/Auth/Process/PrivacyideaAuthProc.php | 32 ++--- .../lib/Auth/Utils.php | 6 +- 3 files changed, 102 insertions(+), 68 deletions(-) diff --git a/simplesamlphp-module-privacyidea/docs/privacyidea.md b/simplesamlphp-module-privacyidea/docs/privacyidea.md index 8b886ce..49acde0 100644 --- a/simplesamlphp-module-privacyidea/docs/privacyidea.md +++ b/simplesamlphp-module-privacyidea/docs/privacyidea.md @@ -24,42 +24,54 @@ template configuration: 'privacyidea:PrivacyideaAuthSource', /** - * The URL of the privacyidea server. Required. + * The URL of the privacyidea server. + * Required. */ 'privacyideaServerURL' => 'https://your.server.com', /** - * Optionally disable SSL verification. This should always be enabled in a productive environment! - * Values should be 'true' or 'false'. Default is 'true'. + * Disable SSL verification. + * Values should be 'true' or 'false'. Default is 'true'. + * + * NOTE: This should always be enabled in a productive environment! + * + * Optional. */ 'sslVerifyHost' => 'true', 'sslVerifyPeer' => 'true', /** - * Optionally set the privacyidea realm. + * Set the privacyidea realm. + * Optional. */ 'realm' => '', /** * Specify the username and password of your service account from privacyIDEA server. - * Only required if 'authSourceMode' => 'triggerChallenge'. + * Required by the 'triggerChallenge' authentication flow. */ - 'serviceAccount' => 'service', - 'servicePass' => 'service', + 'serviceAccount' => '', + 'servicePass' => '', /** - * Optionally set the realm for your service account. + * Specify the realm for your service account. + * Optional (by the 'triggerChallenge' authentication flow). */ - 'serviceRealm' => '', + 'serviceRealm' => '', /** - * Required. Set one of the following authentication flows: + * Choose one of the following authentication flows: + * * 'sendPassword' - (default) Login interface will contain the username input and a single password/OTP input. + * * 'triggerChallenge' - Login interface will contain only the username input. This mode triggers * challenges prior to the login using the configured service account (required). + * * 'separateOTP' - Login interface will contain 3 inputs for username, password and OTP. + * + * Required. */ - 'authenticationFlow' => 'sendPassword', + 'authenticationFlow' => 'sendPassword', /** * Set custom hints for the OTP and password fields. @@ -72,6 +84,7 @@ template configuration: * All information required for SSO will be saved in the session. * After logging out, the SSO data will be removed from the session. * The value has to be 'true' or 'false', default is 'false'. + * * Optional. */ 'SSO' => 'false', @@ -82,12 +95,14 @@ template configuration: * without having to press the button for the type. * Possible values are: 'otp', 'push', 'webauthn' or 'u2f'. Default is 'otp'. * - * NOTE: If the 'preferred_client_mode' is set on the server side, this option will be ignored. + * NOTE: If the 'preferred client mode' is set on the server side, this option will be ignored. + * + * Optional. */ 'preferredTokenType' => '', /** - * Translation from privacyIDEA attribute names to the SAML attribute names. + * Translation from privacyIDEA attribute names to the SAML attribute names. * Required. */ 'attributemap' => array( @@ -159,101 +174,116 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. 'authproc' => array( /** - * Configuration for the privacyIDEA server. + * Configuration for the privacyIDEA. */ 20 => array( 'class' => 'privacyidea:PrivacyideaAuthProc', - /** - * The URL of the privacyidea server. Required. - */ + /** + * The URL of the privacyidea server. + * Required. + */ 'privacyideaServerURL' => 'https://your.privacyidea.server', - /** - * Optionally set the privacyidea realm. - */ + /** + * Set the privacyidea realm. + * Optional. + */ 'realm' => '', /** * The uidKey is the username's attribute key. * You can choose a single one or multiple ones. The first set will be used. * Example: 'uidKey' => array('uid', 'userName', 'uName'). + * * Required. */ 'uidKey' => 'uid', /** - * Optionally disable SSL verification. This should always be enabled in a productive environment! - * Values should be 'true' or 'false'. Default is 'true'. + * Disable SSL verification. + * Values should be 'true' or 'false'. Default is 'true'. + * NOTE: This should always be enabled in a productive environment! + * + * Optional. */ 'sslVerifyHost' => 'true', 'sslVerifyPeer' => 'true', - + /** - * Choose one of the authentication flows: - * 'default' - Default authentication flow. - * 'triggerChallenge' - Before the login interface is shown, the filter will attempt to trigger challenge-response - * token with the specified serviceAccount - * Required. + * Specify the static password for the 'sendStaticPass' authentication flow. + * Required by the 'sendStaticPass' authentication flow. */ - 'authenticationFlow' => 'default', + 'staticPass' => '', /** * Specify the username and password of your service account from privacyIDEA server. - * Only required if 'authSourceMode' => 'triggerChallenge'. + * Required by the 'triggerChallenge' authentication flow. */ - 'serviceAccount' => 'service', - 'servicePass' => 'service', + 'serviceAccount' => '', + 'servicePass' => '', /** - * Optionally set the realm for your service account. + * Choose one of the following authentication flows: + * + * 'default' - Default authentication flow. + * + * 'sendStaticPass' - If you want to use the passOnNoToken or passOnNoUser policy in privacyidea, + * you can use this flow, and specify a static pass which will be sent before the actual + * authentication to trigger the policies in privacyidea. + * NOTE: This 'sendStaticPass' isn't combinable with 'doEnrollToken' option. + * NOTE: This won't be processed if the user has a challenge-response token that were triggered before. + * + * 'triggerChallenge' - Before the login interface is shown, the filter will attempt to trigger challenge-response + * token with the specified serviceAccount. + * + * Required. */ - 'serviceRealm' => '', + 'authenticationFlow' => 'default', /** - * If you want to use the passOnNoToken or passOnNoUser policy in privacyidea, you can set this to 'true' and specify - * a static pass which will be sent before the actual authentication to trigger the policies in privacyidea. - * NOTE: Not compatible it with 'doEnrollToken'. - * NOTE: This won't be processed if the user has challenge-response token that were triggered before. - * Optional. + * Set the realm for your service account. + * Optional (by the 'triggerChallenge' authentication flow). */ - 'tryFirstAuthentication' => 'false', - 'tryFirstAuthPass' => 'secret', + 'serviceRealm' => '', /** * Set this to 'true' if you want to use single sign on. * All information required for SSO will be saved in the session. * After logging out, the SSO data will be removed from the session. + * * Optional. */ 'SSO' => 'false', /** - * Optionally set a preferred token type. + * Set a preferred token type. * If the chosen token is triggered, it will be used to authenticate directly * without having to press the button for the type. * Possible values are: 'otp', 'push', 'webauthn' or 'u2f'. Default is 'otp'. - * - * NOTE: If the 'preferred_client_mode' is set on the server side, this option will be ignored. + * NOTE: If the 'preferred client mode' is set on the server side, this option will be ignored. + * + * Optional. */ 'preferredTokenType' => '', /** * Custom hint for the OTP field. */ - 'otpFieldHint' => 'OTP', + 'otpFieldHint' => 'Please enter the OTP!', /** * Enable this if a token should be enrolled for users that do not have one. * The value has to be 'true' or 'false'. - * Possible token types are 'hotp', 'totp' or 'u2f' - * Optional. + * Possible token types are 'hotp', 'totp' or 'u2f'. * * NOTE: Up from privacyIDEA v3.8.1, we recommend using the 'enroll via challenge' * policy instead of this feature. + * + * Optional. */ 'doEnrollToken' => 'false', - 'tokenType' => 'totp', + 'typeOfTokenToEnroll' => 'totp', /** * Other authproc filters can disable this filter. @@ -261,6 +291,7 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. * The value of this key has to be set by a previous auth proc filter. * privacyIDEA will only be disabled, if the value of the key is set to false, * in any other situation (e.g. the key is not set or does not exist), privacyIDEA will be enabled. + * * Optional. */ 'enabledPath' => '', @@ -270,6 +301,7 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. * You can exclude clients with specified ip addresses. * Enter a range like "10.0.0.0-10.2.0.0" or a single ip like "192.168.178.2" * The selected ip addresses do not need 2FA. + * * Optional. */ 'excludeClientIPs' => array("10.0.0.0-10.2.0.0", "192.168.178.2"), @@ -279,6 +311,7 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. * If you want to selectively disable the privacyIDEA authentication using * the entityID and/or SAML attributes, you may enable this. * Value has to be a 'true' or 'false'. + * * Optional. */ 'checkEntityID' => 'true', @@ -288,6 +321,7 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. * $state[$setPath][$setPath] to true or false. * To selectively enable or disable privacyIDEA, make sure that you specify setPath and setKey such * that they equal enabledPath and enabledKey from privacyidea:privacyidea. + * * Optional. */ 'setPath' => 'privacyIDEA', @@ -297,6 +331,7 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. * The requesting SAML provider's entityID will be tested against this list of regular expressions. * If there is a match, the filter will set the specified state variable to false and thereby disables * privacyIDEA for this entityID The first matching expression will take precedence. + * * Optional. */ 'excludeEntityIDs' => array( @@ -311,6 +346,7 @@ e.g. `simplesaml/metadata/saml20-idp-hosted.php`. * due to the matching entityID. This may be used to enable 2FA at this entityID only for privileged * accounts. * The key in includeAttributes must be identical to a value in excludeEntityIDs to have an effect! + * * Optional. */ 'includeAttributes' => array( diff --git a/simplesamlphp-module-privacyidea/lib/Auth/Process/PrivacyideaAuthProc.php b/simplesamlphp-module-privacyidea/lib/Auth/Process/PrivacyideaAuthProc.php index 2f9c28f..58e6bab 100644 --- a/simplesamlphp-module-privacyidea/lib/Auth/Process/PrivacyideaAuthProc.php +++ b/simplesamlphp-module-privacyidea/lib/Auth/Process/PrivacyideaAuthProc.php @@ -127,24 +127,12 @@ public function process(&$state) } } } - else - { - SimpleSAML_Logger::error("privacyidea: Authentication flow is not set in config. Processing default one..."); - } - - // Check if it should be controlled that user has no tokens and a new token should be enrolled. - if (!$triggered && !empty($this->authProcConfig['doEnrollToken']) && $this->authProcConfig['doEnrollToken'] === 'true') - { - $stateId = $this->enrollToken($stateId, $username); - } - - // Check if call with a static pass to /validate/check should be done - if (!$triggered && !empty($this->authProcConfig['tryFirstAuthentication']) - && $this->authProcConfig['tryFirstAuthentication'] === 'true') + elseif ($this->authProcConfig['authenticationFlow'] === 'sendStaticPass') { // Call /validate/check with a static pass from the configuration - // This could already end the authentication with the "passOnNoToken" policy, or it could trigger challenges - $response = sspmod_privacyidea_Auth_Utils::authenticatePI($state, array('otp' => $this->authProcConfig['tryFirstAuthPass'])); + // This could already end up the authentication if the "passOnNoToken" policy is set. + // Otherwise, it triggers the challenges. + $response = sspmod_privacyidea_Auth_Utils::authenticatePI($state, array('otp' => $this->authProcConfig['staticPass'])); if (empty($response->multiChallenge) && $response->value) { SimpleSAML_Auth_ProcessingChain::resumeProcessing($state); @@ -154,6 +142,16 @@ public function process(&$state) $stateId = sspmod_privacyidea_Auth_Utils::processPIResponse($stateId, $response); } } + else + { + SimpleSAML_Logger::error("privacyidea: Authentication flow is not set in the config. Fallback to default..."); + } + + // Check if it should be controlled that user has no tokens and a new token should be enrolled. + if (!$triggered && !empty($this->authProcConfig['doEnrollToken']) && $this->authProcConfig['doEnrollToken'] === 'true') + { + $stateId = $this->enrollToken($stateId, $username); + } $state = SimpleSAML_Auth_State::loadState($stateId, 'privacyidea:privacyidea'); @@ -191,7 +189,7 @@ private function enrollToken($stateId, $username) else { $genkey = "1"; - $type = $this->authProcConfig['tokenType']; + $type = $this->authProcConfig['typeOfTokenToEnroll']; $description = "Enrolled with simpleSAMLphp"; $response = $this->pi->enrollToken($username, $genkey, $type, $description); diff --git a/simplesamlphp-module-privacyidea/lib/Auth/Utils.php b/simplesamlphp-module-privacyidea/lib/Auth/Utils.php index 4de7447..7ba3c5f 100644 --- a/simplesamlphp-module-privacyidea/lib/Auth/Utils.php +++ b/simplesamlphp-module-privacyidea/lib/Auth/Utils.php @@ -322,10 +322,10 @@ public static function processPIResponse($stateId, PIResponse $response) SimpleSAML_Logger::debug("privacyIDEA: Preferred token type - illegal value. Fallback to default: " . $state['privacyidea:privacyidea:ui']['mode']); } } - - $state['privacyidea:privacyidea:ui']['pushAvailable'] = in_array("push", $triggeredToken); + + $state['privacyidea:privacyidea:ui']['pushAvailable'] = in_array("push", $triggeredTokens); $state['privacyidea:privacyidea:ui']['otpAvailable'] = true; - + $state['privacyidea:privacyidea:ui']['message'] = $response->messages; if (in_array("webauthn", $triggeredTokens))