JwtCapability
in package
One capability carried in a JWT access token: proof of access to a single record.
It is neither a role nor an identity. It arises only for an anonymous advert editor who entered the advert password or opened the "Manage advert" link (AdvertAuthorizationFormTrait), and for a guest author of a discussion post who opened the "Manage post" link.
Fields:
scope: the domain (bazaar.advert.edit,comcat.advert.edit,discussion.message.edit); without it a Bazaar capability would authorize a company or a post with the sameid.id: the one record it applies to, never a blanket grant.expiration: unix time, a copy of the session token expiration.fingerprint:sha256of the password hash stored in the DB at issue time.
IMPORTANT: a capability never carries a foreign identity. The token has userId = 0
(guest, see PermissionResolver). Substituting the
advert owner's insertUserId would give an anonymous editor all rights of that account.
IMPORTANT: the fingerprint lets a password change by the owner revoke all open editing
sessions at once. The API side compares the token fingerprint with the fingerprint of the
password of the entity loaded from the DB (DB against token, never token against token).
With only [id, expiration] the capability would survive a password change until expiry.
NOTE: the token carries a fingerprint, not the bcrypt hash itself; any password change
changes it, and it is useless as a credential elsewhere. Compare it with hash_equals(),
not ===.
Table of Contents
Constants
- SCOPE_BAZAAR_ADVERT_EDIT : string = 'bazaar.advert.edit'
- Editing a Bazaar advert reached by an anonymous user through the advert password.
- SCOPE_COMCAT_ADVERT_EDIT : string = 'comcat.advert.edit'
- The same for the company catalog (Comcat); a separate scope keeps the `id` values apart.
- SCOPE_DISCUSSION_MESSAGE_EDIT : string = 'discussion.message.edit'
- Editing a discussion post reached by its guest author through the "Manage post" link from the insert e-mail; the fingerprint is taken from `Message::$password` (a random secret of a guest post).
Properties
- $expiration : int
- $fingerprint : string
- $id : int
- $scope : string
Methods
- __construct() : mixed
- fingerprint() : string
- Returns the fingerprint of the record password.
- fromValue() : self|null
- Tolerantly deserializes a capability, returning null for anything that lacks any of the four parts in a usable shape.
- getExpiration() : int
- getFingerprint() : string
- getId() : int
- getScope() : string
- grants() : bool
- Returns whether any of the capabilities applies to this record.
- matches() : bool
- Returns whether this capability applies to exactly this record right now.
- toArray() : array{scope: string, id: int, exp: int, fp: string}
Constants
SCOPE_BAZAAR_ADVERT_EDIT
Editing a Bazaar advert reached by an anonymous user through the advert password.
public
string
SCOPE_BAZAAR_ADVERT_EDIT
= 'bazaar.advert.edit'
SCOPE_COMCAT_ADVERT_EDIT
The same for the company catalog (Comcat); a separate scope keeps the `id` values apart.
public
string
SCOPE_COMCAT_ADVERT_EDIT
= 'comcat.advert.edit'
SCOPE_DISCUSSION_MESSAGE_EDIT
Editing a discussion post reached by its guest author through the "Manage post" link from the insert e-mail; the fingerprint is taken from `Message::$password` (a random secret of a guest post).
public
string
SCOPE_DISCUSSION_MESSAGE_EDIT
= 'discussion.message.edit'
Properties
$expiration read-only
private
int
$expiration
$fingerprint read-only
private
string
$fingerprint
$id read-only
private
int
$id
$scope read-only
private
string
$scope
Methods
__construct()
public
__construct(string $scope, int $id, int $expiration, string $fingerprint) : mixed
Parameters
- $scope : string
- $id : int
- $expiration : int
- $fingerprint : string
fingerprint()
Returns the fingerprint of the record password.
public
static fingerprint(string|null $passwordHash) : string
A null or empty hash gives an empty fingerprint that self::matches() never accepts, so a record without a password cannot be edited through a capability (fail-closed).
Parameters
- $passwordHash : string|null
Return values
stringfromValue()
Tolerantly deserializes a capability, returning null for anything that lacks any of the four parts in a usable shape.
public
static fromValue(mixed $value) : self|null
One broken capability must not discard the whole token (and log out a live session).
NOTE: the input may be a stdClass, because JwtManager::decodeToken() casts only the
top level with (array) $decoded->data and nested objects stay objects.
Parameters
- $value : mixed
Return values
self|nullgetExpiration()
public
getExpiration() : int
Return values
intgetFingerprint()
public
getFingerprint() : string
Return values
stringgetId()
public
getId() : int
Return values
intgetScope()
public
getScope() : string
Return values
stringgrants()
Returns whether any of the capabilities applies to this record.
public
static grants(array<int, self> $capabilities, string $scope, int $id, string $fingerprint[, int|null $now = null ]) : bool
The only place that walks the list, so the rule cannot diverge between Bazaar and Comcat.
Parameters
- $capabilities : array<int, self>
- $scope : string
- $id : int
- $fingerprint : string
- $now : int|null = null
Return values
boolmatches()
Returns whether this capability applies to exactly this record right now.
public
matches(string $scope, int $id, string $fingerprint[, int|null $now = null ]) : bool
Fail-closed on all four axes: scope, id, expiration, password fingerprint from the DB.
Parameters
- $scope : string
- $id : int
- $fingerprint : string
- $now : int|null = null
Return values
booltoArray()
public
toArray() : array{scope: string, id: int, exp: int, fp: string}