-
Pavel Břoušek authored
ignore only some rollout states
Pavel Břoušek authoredignore only some rollout states
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
GetMfaTokensPrivacyIDEA.php 6.60 KiB
<?php
declare(strict_types=1);
namespace SimpleSAML\Module\authswitcher\Auth\Process;
use SimpleSAML\Configuration;
use SimpleSAML\Logger;
use SimpleSAML\Module\authswitcher\AuthSwitcher;
use SimpleSAML\Store;
class GetMfaTokensPrivacyIDEA extends \SimpleSAML\Auth\ProcessingFilter
{
private const DEBUG_PREFIX = 'authswitcher:GetMfaTokensPrivacyIDEA: ';
private const AS_PI = 'as_pi';
private const AS_PI_AUTH_TOKEN = 'auth_token';
private const AS_PI_AUTH_TOKEN_ISSUED_AT = 'auth_token_issued_at';
private $connect_timeout = 0;
private $timeout;
private $tokens_attr = AuthSwitcher::MFA_TOKENS;
private $privacy_idea_username;
private $privacy_idea_passwd;
private $privacy_idea_realm;
private $privacy_idea_domain;
private $tokens_type = ['TOTP', 'WebAuthn'];
private $user_attribute = 'eduPersonPrincipalName';
private $token_type_attr = 'type';
private $enable_cache = false;
private $cache_expiration_seconds = 55 * 60;
public function __construct($config, $reserved)
{
parent::__construct($config, $reserved);
$config = Configuration::loadFromArray($config['config']);
$this->connect_timeout = $config->getInteger('connect_timeout', $this->connect_timeout);
$this->timeout = $config->getInteger('timeout', $this->timeout);
$this->tokens_attr = $config->getString('tokens_Attr', $this->tokens_attr);
$this->privacy_idea_username = $config->getString('privacy_idea_username');
$this->privacy_idea_passwd = $config->getString('privacy_idea_passwd');
$this->privacy_idea_realm = $config->getString('privacy_idea_realm', null);
$this->privacy_idea_domain = $config->getString('privacy_idea_domain');
$this->tokens_type = $config->getArray('tokens_type', $this->tokens_type);
$this->user_attribute = $config->getString('user_attribute', $this->user_attribute);
$this->token_type_attr = $config->getString('token_type_attr', $this->token_type_attr);
$this->enable_cache = $config->getBoolean('enable_cache', $this->enable_cache);
$this->cache_expiration_seconds = $config->getInteger(
'cache_expiration_seconds',
$this->cache_expiration_seconds
);
}
public function process(&$state)
{
$state[Authswitcher::PRIVACY_IDEA_FAIL] = false;
$admin_token = $this->getAdminToken();
if (empty($admin_token)) {
$state[AuthSwitcher::PRIVACY_IDEA_FAIL] = true;
return;
}
foreach ($this->tokens_type as $token_type) {
$tokens = self::getPrivacyIdeaTokensByType($state, strtolower($token_type), $admin_token);
$this->saveTokensToStateAttributes($state, $tokens);
}
}
private function getAdminToken()
{
if ($this->enable_cache) {
$store = Store::getInstance();
$issued_at = $store->get(self::AS_PI, self::AS_PI_AUTH_TOKEN_ISSUED_AT);
if ($issued_at && time() - $issued_at < $this->cache_expiration_seconds) {
$admin_token = $store->get(self::AS_PI, self::AS_PI_AUTH_TOKEN);
if ($admin_token) {
Logger::debug(self::DEBUG_PREFIX . 'Using auth token from cache');
return $admin_token;
}
}
}
$admin_token = $this->getAuthToken();
if ($this->enable_cache) {
$store->set(self::AS_PI, self::AS_PI_AUTH_TOKEN, $admin_token);
$store->set(self::AS_PI, self::AS_PI_AUTH_TOKEN_ISSUED_AT, time());
}
return $admin_token;
}
private function getAuthToken()
{
$data = [
'username' => $this->privacy_idea_username,
'password' => $this->privacy_idea_passwd,
];
if ($this->privacy_idea_realm !== null) {
$data['realm'] = $this->privacy_idea_realm;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
if ($this->timeout !== null) {
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
}
curl_setopt($ch, CURLOPT_URL, $this->privacy_idea_domain . '/auth');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$paramsJson = json_encode($data);
curl_setopt($ch, CURLOPT_POSTFIELDS, $paramsJson);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) {
Logger::warning(sprintf(self::DEBUG_PREFIX . 'getAuthToken Response from PrivacyIDEA API: %s', $response));
return null;
}
curl_close($ch);
$response = json_decode($response, true);
return $response['result']['value']['token'];
}
private function getPrivacyIdeaTokensByType(&$state, $type, $admin_token)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
if ($this->timeout !== null) {
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
}
curl_setopt($ch, CURLOPT_URL, $this->privacy_idea_domain . '/token/?user=' .
$state['Attributes'][$this->user_attribute][0] . '&active=True&type=' . $type);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization:' . $admin_token]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) {
Logger::warning(sprintf(self::DEBUG_PREFIX .
'getPrivacyIdeaTokens type: %s Response from PrivacyIDEA API: %s', $type, $response));
$state[AuthSwitcher::PRIVACY_IDEA_FAIL] = true;
return [];
}
$response = json_decode($response, true);
curl_close($ch);
return $response['result']['value']['tokens'];
}
private function saveTokensToStateAttributes(&$state, $tokens)
{
$types = [];
foreach ($tokens as $token) {
foreach ($this->tokens_type as $type) {
if (
$token['tokentype'] === strtolower($type)
&& !in_array($token['rollout_state'] ?? '', ['clientwait', 'verify'])
) {
$token[$this->token_type_attr] = $type;
$types[] = $token;
break;
}
}
}
if (!empty($types)) {
$state['Attributes'][$this->tokens_attr] = $types;
}
}
}