157 lines
4.3 KiB
PHP
157 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXF\Security\Authentication;
|
|
|
|
/**
|
|
* Provider Result
|
|
*
|
|
* Result returned from authentication providers.
|
|
* Separates client-facing data from session persistence data.
|
|
*/
|
|
readonly class ProviderResult
|
|
{
|
|
// Status constants
|
|
public const SUCCESS = 'success';
|
|
public const FAILED = 'failed';
|
|
public const CHALLENGE = 'challenge';
|
|
public const REDIRECT = 'redirect';
|
|
|
|
// Error codes
|
|
public const ERROR_INVALID_CREDENTIALS = 'invalid_credentials';
|
|
public const ERROR_INVALID_PROVIDER = 'invalid_provider';
|
|
public const ERROR_INVALID_FACTOR = 'invalid_factor';
|
|
public const ERROR_FACTOR_FAILED = 'factor_failed';
|
|
public const ERROR_NOT_ENROLLED = 'not_enrolled';
|
|
public const ERROR_RATE_LIMITED = 'rate_limited';
|
|
public const ERROR_INTERNAL = 'internal_error';
|
|
|
|
public function __construct(
|
|
/** Result status */
|
|
public string $status,
|
|
|
|
/** Error code for failures */
|
|
public ?string $errorCode = null,
|
|
|
|
/** Human-readable error message */
|
|
public ?string $errorMessage = null,
|
|
|
|
/** Verified identity claims (user_id, provider, etc.) */
|
|
public array $identity = [],
|
|
|
|
/** Data to send to client (challenge info, redirect URL, etc.) */
|
|
public array $clientData = [],
|
|
|
|
/** Data to persist in session for subsequent calls */
|
|
public array $sessionData = [],
|
|
) {}
|
|
|
|
// =========================================================================
|
|
// Factory Methods
|
|
// =========================================================================
|
|
|
|
/**
|
|
* Create a success result
|
|
*/
|
|
public static function success(array $identity = [], array $clientData = [], array $sessionData = []): self
|
|
{
|
|
return new self(
|
|
status: self::SUCCESS,
|
|
identity: $identity,
|
|
clientData: $clientData,
|
|
sessionData: $sessionData,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create a failed result
|
|
*/
|
|
public static function failed(
|
|
string $errorCode = self::ERROR_INVALID_CREDENTIALS,
|
|
?string $errorMessage = null
|
|
): self {
|
|
return new self(
|
|
status: self::FAILED,
|
|
errorCode: $errorCode,
|
|
errorMessage: $errorMessage,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create a challenge result (for challenge-based auth)
|
|
*/
|
|
public static function challenge(array $challengeInfo, array $sessionData = []): self
|
|
{
|
|
return new self(
|
|
status: self::CHALLENGE,
|
|
clientData: ['challenge' => $challengeInfo],
|
|
sessionData: $sessionData,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create a redirect result (for OIDC/SAML)
|
|
*/
|
|
public static function redirect(string $url, array $sessionData): self
|
|
{
|
|
return new self(
|
|
status: self::REDIRECT,
|
|
clientData: ['redirect_url' => $url],
|
|
sessionData: $sessionData,
|
|
);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Status Checks
|
|
// =========================================================================
|
|
|
|
public function isSuccess(): bool
|
|
{
|
|
return $this->status === self::SUCCESS;
|
|
}
|
|
|
|
public function isFailed(): bool
|
|
{
|
|
return $this->status === self::FAILED;
|
|
}
|
|
|
|
public function isChallenge(): bool
|
|
{
|
|
return $this->status === self::CHALLENGE;
|
|
}
|
|
|
|
public function isRedirect(): bool
|
|
{
|
|
return $this->status === self::REDIRECT;
|
|
}
|
|
|
|
// =========================================================================
|
|
// Data Access
|
|
// =========================================================================
|
|
|
|
/**
|
|
* Get identity claim
|
|
*/
|
|
public function getIdentity(string $key, mixed $default = null): mixed
|
|
{
|
|
return $this->identity[$key] ?? $default;
|
|
}
|
|
|
|
/**
|
|
* Get client data value
|
|
*/
|
|
public function getClientData(string $key, mixed $default = null): mixed
|
|
{
|
|
return $this->clientData[$key] ?? $default;
|
|
}
|
|
|
|
/**
|
|
* Get session data value
|
|
*/
|
|
public function getSessionData(string $key, mixed $default = null): mixed
|
|
{
|
|
return $this->sessionData[$key] ?? $default;
|
|
}
|
|
}
|