Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ApiStatistics.php 4.64 KiB
<?php

declare(strict_types=1);

namespace SimpleSAML\Module\proxystatistics\Auth\Process;

use SimpleSAML\Auth\ProcessingFilter;
use SimpleSAML\Configuration;
use SimpleSAML\Error\Exception;
use SimpleSAML\Logger;

class ApiStatistics extends ProcessingFilter
{
    private const STAGE = 'proxystatistics:ApiStatistics';

    private const DEBUG_PREFIX = self::STAGE . ' - ';

    public const API_URL = 'apiUrl';

    public const API_USERNAME = 'apiUsername';

    public const API_PASSWORD = 'apiPassword';

    public const USERNAME_ATTRIBUTE = 'usernameAttribute';

    public const IDP_IDENTIFIER_ATTRIBUTE = 'idpIdentifierAttribute';

    public const IDP_NAME_ATTRIBUTE = 'idpNameAttribute';

    private const USER_ID = 'userId';

    private const SERVICE_IDENTIFIER = 'serviceIdentifier';

    private const SERVICE_NAME = 'serviceName';

    private const IDP_IDENTIFIER = 'idpIdentifier';

    private const IDP_NAME = 'idpName';

    private $userIdAttribute;

    private $idpIdAttribute;

    private $idpNameAttribute;

    private $apiUrl;

    private $apiUsername;

    private $apiPassword;

    public function __construct($config, $reserved)
    {
        parent::__construct($config, $reserved);
        $configuration = Configuration::loadFromArray($config);
        $this->userIdAttribute = $configuration->getString(self::USERNAME_ATTRIBUTE);
        $this->idpIdAttribute = $configuration->getString(self::IDP_IDENTIFIER_ATTRIBUTE);
        $this->idpNameAttribute = $configuration->getString(self::IDP_NAME_ATTRIBUTE);
        $this->apiUrl = $configuration->getString(self::API_URL);
        $this->apiUsername = $configuration->getString(self::API_USERNAME);
        $this->apiPassword = $configuration->getString(self::API_PASSWORD);
    }

    public function process(&$request)
    {
        $attributes = $request['Attributes'];

        if (empty($attributes[$this->userIdAttribute][0])) {
            Logger::warning(
                self::DEBUG_PREFIX .
                "Cannot write to stats - Missing user ID in attribute " .
                $this->userIdAttribute
            );
            return;
        } elseif (empty($attributes[$this->idpIdAttribute][0])) {
            Logger::warning(
                self::DEBUG_PREFIX .
                "Cannot write to stats - Missing IdP ID in attribute " .
                $this->idpIdAttribute
            );
            return;
        } elseif (empty($attributes[$this->idpNameAttribute][0])) {
            Logger::warning(
                self::DEBUG_PREFIX .
                "Cannot write to stats - Missing IdP name in attribute " .
                $this->idpNameAttribute
            );
        }
        $userId = $attributes[$this->userIdAttribute][0];
        $idpId = $attributes[$this->idpIdAttribute][0];
        $idpName = $attributes[$this->idpNameAttribute][0];

        $spId = $request['Destination']['entityid'];
        $spName = $request['Destination']['UIInfo']['DisplayName']['en'] ?? '';
        if (empty($spName)) {
            $spName = $request['Destination']['name']['en'] ?? '';
        }

        if (empty($spId)) {
            Logger::warning(self::DEBUG_PREFIX . "Cannot write to stats - Missing SP ID");
            return;
        } elseif (empty($spName)) {
            Logger::warning(self::DEBUG_PREFIX . "Cannot write to stats - Missing SP name");
            return;
        }

        $body = json_encode([
            self::USER_ID => $userId,
            self::IDP_IDENTIFIER => $idpId,
            self::IDP_NAME => $idpName,
            self::SERVICE_IDENTIFIER => $spId,
            self::SERVICE_NAME => $spName
        ]);

        Logger::debug(self::DEBUG_PREFIX . "Calling stats API endpoint with data - " . $body);

        $ch = curl_init($this->apiUrl);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        curl_setopt($ch, CURLOPT_USERPWD, $this->apiUsername . ":" . $this->apiPassword);

        $response = curl_exec($ch);
        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($httpcode != 200) {
            Logger::warning(
                self::DEBUG_PREFIX
                . 'Calling API endpoint to write stats returned non-200 response code: ' . $httpcode
            );
            Logger::debug(self::DEBUG_PREFIX . "Response: " . $response);
        } else {
            Logger::info(self::DEBUG_PREFIX . 'Successfully written to statistics via API');
        }
    }
}