Skip to content
Open
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
level: 7
level: 9
paths:
- ./src
- ./test
27 changes: 22 additions & 5 deletions src/PluginSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ public function __construct(
// delete the instance if the special sub is in the token data
// exits the request
if ($sso && $remoteCallHandler && $sso->isDeleteInstanceCall()) {
$this->deleteInstance($sso->getInstanceId(), $remoteCallHandler);
$instanceId = $sso->getInstanceId() ?: throw new SSOException('Instance id is required for deleteInstance');
$this->deleteInstance($instanceId, $remoteCallHandler);
}

// starts the session
Expand Down Expand Up @@ -153,12 +154,28 @@ private function updateSSOInformation(string $jwt, string $appSecret, int $leewa
*/
private function validateParams(): ?string
{
$pid = $_REQUEST[self::QUERY_PARAM_PID] ?? null;
$jwt = $_REQUEST[self::QUERY_PARAM_JWT] ?? null;
$sid = $_REQUEST[self::QUERY_PARAM_SID] ?? null;
$rawPid = $_REQUEST[self::QUERY_PARAM_PID] ?? null;
$rawJwt = $_REQUEST[self::QUERY_PARAM_JWT] ?? null;
$rawSid = $_REQUEST[self::QUERY_PARAM_SID] ?? null;

// Normalize values to string|null while avoiding casting arrays/objects to string
$pid = null;
if (is_string($rawPid)) {
$pid = $rawPid;
}

$jwt = null;
if (is_string($rawJwt)) {
$jwt = $rawJwt;
}

$sid = null;
if (is_string($rawSid)) {
$sid = $rawSid;
}

// lets hint to bad class usage, as these cases should never happen.
if ($pid && $jwt) {
if ($pid !== null && $jwt !== null) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ($pid !== null && $jwt !== null) {
if ($pid && $jwt) {

throw new SSOAuthenticationException('Tried to initialize the session with both PID and JWT provided.');
}

Expand Down
2 changes: 1 addition & 1 deletion src/RemoteCall/DeleteInstanceTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected function exitRemoteCall(): void
exit;
}

private function deleteInstance(string $instanceId, RemoteCallInterface $remoteCallHandler): void
private function deleteInstance(string $instanceId, RemoteCallInterface $remoteCallHandler): never
Comment thread
Ninerian marked this conversation as resolved.
Outdated
{
if ($remoteCallHandler instanceof DeleteInstanceCallHandlerInterface) {
$result = $remoteCallHandler->deleteInstance($instanceId);
Expand Down
6 changes: 4 additions & 2 deletions src/SSOData/ClaimAccessTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ abstract protected function getAllClaims(): array;
*/
protected function getClaimSafe(string $name)
{

if ($this->hasClaim($name)) {
return $this->getClaim($name);
$value = $this->getClaim($name);

// Return the value as-is. Type safety is handled by individual getters.
return $value;
}

return null;
Expand Down
53 changes: 35 additions & 18 deletions src/SSOData/SSODataTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ trait SSODataTrait
*/
public function getBranchId(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_BRANCH_ID);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_BRANCH_ID);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -42,7 +43,8 @@ public function getBranchId(): ?string
*/
public function getBranchSlug(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_BRANCH_SLUG);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_BRANCH_SLUG);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -52,7 +54,8 @@ public function getBranchSlug(): ?string
*/
public function getSessionId(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_SESSION_ID);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_SESSION_ID);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -64,7 +67,8 @@ public function getSessionId(): ?string
*/
public function getInstanceId(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_INSTANCE_ID);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_INSTANCE_ID);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -74,7 +78,8 @@ public function getInstanceId(): ?string
*/
public function getInstanceName(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_INSTANCE_NAME);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_INSTANCE_NAME);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -84,7 +89,8 @@ public function getInstanceName(): ?string
*/
public function getUserId(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_ID);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_ID);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -97,7 +103,8 @@ public function getUserId(): ?string
*/
public function getUserExternalId(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_EXTERNAL_ID);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_EXTERNAL_ID);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -107,7 +114,8 @@ public function getUserExternalId(): ?string
*/
public function getUserUsername(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_USERNAME);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_USERNAME);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -117,7 +125,8 @@ public function getUserUsername(): ?string
*/
public function getUserPrimaryEmailAddress(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_PRIMARY_EMAIL_ADDRESS);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_PRIMARY_EMAIL_ADDRESS);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -127,7 +136,8 @@ public function getUserPrimaryEmailAddress(): ?string
*/
public function getFullName(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_FULL_NAME);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_FULL_NAME);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -137,7 +147,8 @@ public function getFullName(): ?string
*/
public function getFirstName(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_FIRST_NAME);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_FIRST_NAME);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -147,20 +158,22 @@ public function getFirstName(): ?string
*/
public function getLastName(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_LAST_NAME);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_LAST_NAME);
return is_string($value) ? $value : null;
}


/**
* Get the type of the token.
*
* The type of the accessing entity can be either a user or a token.
* The type of the accessing entity can be either a "user" or a "token".
*
* @return null|string
*/
public function getType(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_ENTITY_TYPE);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_ENTITY_TYPE);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -172,7 +185,8 @@ public function getType(): ?string
*/
public function getThemeTextColor(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_THEME_TEXT_COLOR);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_THEME_TEXT_COLOR);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -184,7 +198,8 @@ public function getThemeTextColor(): ?string
*/
public function getThemeBackgroundColor(): ?string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_THEME_BACKGROUND_COLOR);
$value = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_THEME_BACKGROUND_COLOR);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -194,7 +209,8 @@ public function getThemeBackgroundColor(): ?string
*/
public function getLocale(): string
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_LOCALE);
$val = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_LOCALE);
return is_string($val) ? $val : '';
Comment thread
Ninerian marked this conversation as resolved.
Outdated
}

/**
Expand All @@ -204,6 +220,7 @@ public function getLocale(): string
*/
public function getTags(): ?array
{
return $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_TAGS);
$val = $this->getClaimSafe(SSODataClaimsInterface::CLAIM_USER_TAGS);
return is_array($val) ? $val : null;
Comment thread
Ninerian marked this conversation as resolved.
Outdated
}
}
25 changes: 16 additions & 9 deletions src/SSOData/SharedDataTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ public function getAudience(): ?string
*/
public function getExpireAtTime(): ?DateTimeImmutable
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_EXPIRE_AT);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_EXPIRE_AT);
return $value instanceof DateTimeImmutable ? $value : null;
}

/**
Expand All @@ -69,7 +70,8 @@ public function getExpireAtTime(): ?DateTimeImmutable
*/
public function getNotBeforeTime(): ?DateTimeImmutable
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_NOT_BEFORE);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_NOT_BEFORE);
return $value instanceof DateTimeImmutable ? $value : null;
}

/**
Expand All @@ -79,7 +81,8 @@ public function getNotBeforeTime(): ?DateTimeImmutable
*/
public function getIssuedAtTime(): ?DateTimeImmutable
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_ISSUED_AT);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_ISSUED_AT);
return $value instanceof DateTimeImmutable ? $value : null;
}

/**
Expand All @@ -89,7 +92,8 @@ public function getIssuedAtTime(): ?DateTimeImmutable
*/
public function getIssuer(): ?string
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_ISSUER);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_ISSUER);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -99,7 +103,8 @@ public function getIssuer(): ?string
*/
public function getId(): ?string
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_JWT_ID);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_JWT_ID);
return is_string($value) ? $value : null;
}

/**
Expand All @@ -109,21 +114,23 @@ public function getId(): ?string
*/
public function getSubject(): ?string
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_SUBJECT);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_SUBJECT);
return is_string($value) ? $value : null;
}

/**
* Get the role of the accessing user.
*
* If this is set to editor, the requesting user may manage the contents
* If this is set to "editor", the requesting user may manage the contents
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

* of the plugin instance, i.e. she has administration rights.
* The type of the accessing entity can be either a user or a editor.
* The type of the accessing entity can be either a "user" or a "editor".
*
* @return null|string
*/
public function getRole(): ?string
{
return $this->getClaimSafe(SharedClaimsInterface::CLAIM_USER_ROLE);
$value = $this->getClaimSafe(SharedClaimsInterface::CLAIM_USER_ROLE);
return is_string($value) ? $value : null;
}

/**
Expand Down
44 changes: 37 additions & 7 deletions src/SSOTokenGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,52 @@ public static function createSignedTokenFromData(string $privateKey, array $toke
private static function buildToken(Configuration $config, array $tokenData): Token
{
$builder = $config->builder();
// Validate and coerce required registered claims to the expected types
$audience = $tokenData[SSOData\SharedClaimsInterface::CLAIM_AUDIENCE] ?? '';
if (!is_string($audience) || $audience === '') {
throw new \InvalidArgumentException('aud claim must be a non-empty string for token generation');
}
Comment thread
Ninerian marked this conversation as resolved.

$issuedAt = $tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUED_AT] ?? null;
if (!($issuedAt instanceof \DateTimeImmutable)) {
throw new \InvalidArgumentException('iat claim must be a DateTimeImmutable for token generation');
}

$notBefore = $tokenData[SSOData\SharedClaimsInterface::CLAIM_NOT_BEFORE] ?? null;
if (!($notBefore instanceof \DateTimeImmutable)) {
throw new \InvalidArgumentException('nbf claim must be a DateTimeImmutable for token generation');
}

$expiresAt = $tokenData[SSOData\SharedClaimsInterface::CLAIM_EXPIRE_AT] ?? null;
if (!($expiresAt instanceof \DateTimeImmutable)) {
throw new \InvalidArgumentException('exp claim must be a DateTimeImmutable for token generation');
}

$token = $builder
->permittedFor($tokenData[SSOData\SharedClaimsInterface::CLAIM_AUDIENCE])
->issuedAt($tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUED_AT])
->canOnlyBeUsedAfter($tokenData[SSOData\SharedClaimsInterface::CLAIM_NOT_BEFORE])
->expiresAt($tokenData[SSOData\SharedClaimsInterface::CLAIM_EXPIRE_AT]);
->permittedFor($audience)
->issuedAt($issuedAt)
->canOnlyBeUsedAfter($notBefore)
->expiresAt($expiresAt);

if (isset($tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUER])) {
$token = $token->issuedBy($tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUER]);
$issuer = $tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUER];
if (is_string($issuer) && $issuer !== '') {
$token = $token->issuedBy($issuer);
}
}

if (isset($tokenData[SSOData\SSODataClaimsInterface::CLAIM_USER_ID])) {
$token = $token->relatedTo($tokenData[SSOData\SSODataClaimsInterface::CLAIM_USER_ID]);
$subject = $tokenData[SSOData\SSODataClaimsInterface::CLAIM_USER_ID];
if (is_string($subject) && $subject !== '') {
$token = $token->relatedTo($subject);
}
}

if (isset($tokenData[SSOData\SharedClaimsInterface::CLAIM_JWT_ID])) {
$token = $token->identifiedBy($tokenData[SSOData\SharedClaimsInterface::CLAIM_JWT_ID]);
$jwtId = $tokenData[SSOData\SharedClaimsInterface::CLAIM_JWT_ID];
if (is_string($jwtId) && $jwtId !== '') {
$token = $token->identifiedBy($jwtId);
}
}

// Remove all set keys as they throw an exception when used with withClaim
Expand Down
Loading