Skip to content

Commit 23ae631

Browse files
committed
Merge branch 'v2'
# Conflicts: # README.md
2 parents 348f3f3 + 4aaa117 commit 23ae631

File tree

4 files changed

+143
-7
lines changed

4 files changed

+143
-7
lines changed

Classes/Authorization.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ class Authorization
7777
*/
7878
protected $encryptedSerializedAccessToken;
7979

80+
/**
81+
* @var string
82+
* @ORM\Column(nullable = true, type = "text")
83+
*/
84+
protected $metadata;
85+
8086
/**
8187
* @Flow\Transient
8288
* @var EncryptionService
@@ -293,4 +299,14 @@ public function setExpires(\DateTimeImmutable $expires): void
293299
{
294300
$this->expires = $expires;
295301
}
302+
303+
public function getMetadata(): ?string
304+
{
305+
return $this->metadata;
306+
}
307+
308+
public function setMetadata(string $metadata): void
309+
{
310+
$this->metadata = $metadata;
311+
}
296312
}

Classes/OAuthClient.php

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
declare(strict_types=1);
23

34
namespace Flownative\OAuth2\Client;
45

@@ -253,6 +254,18 @@ public function requestAccessToken(string $serviceName, string $clientId, string
253254
$this->entityManager->flush();
254255
}
255256

257+
/**
258+
* Returns an authorization id taking the service type and service name into account.
259+
*
260+
* @param string $clientId
261+
* @return string
262+
* @throws OAuthClientException
263+
*/
264+
public function generateAuthorizationIdForAuthorizationCodeGrant(string $clientId): string
265+
{
266+
return Authorization::generateAuthorizationIdForAuthorizationCodeGrant($this->getServiceType(), $this->getServiceName(), $clientId);
267+
}
268+
256269
/**
257270
* Start OAuth authorization with the Authorization Code flow
258271
*
@@ -265,7 +278,30 @@ public function requestAccessToken(string $serviceName, string $clientId, string
265278
*/
266279
public function startAuthorization(string $clientId, string $clientSecret, UriInterface $returnToUri, string $scope): UriInterface
267280
{
268-
$authorizationId = Authorization::generateAuthorizationIdForAuthorizationCodeGrant($this->getServiceType(), $this->getServiceName(), $clientId);
281+
$authorizationId = $this->generateAuthorizationIdForAuthorizationCodeGrant($clientId);
282+
return $this->startAuthorizationWithId($authorizationId, $clientId, $clientSecret, $returnToUri, $scope);
283+
}
284+
285+
/**
286+
* Start OAuth authorization with the Authorization Code flow
287+
* based on a specified authorization identifier.
288+
*
289+
* Note that, if you use this method, it is your responsibility to provide a
290+
* meaningful authorization id. You might weaken the security of your
291+
* application if you use an id which is deterministic or can be guessed by
292+
* an attacker.
293+
*
294+
* If in doubt, always use startAuthorization() instead.
295+
*
296+
* @param string $clientId The client id, as provided by the OAuth server
297+
* @param string $clientSecret The client secret, provided by the OAuth server
298+
* @param UriInterface $returnToUri URI to return to when authorization is finished
299+
* @param string $scope Scope to request for authorization. Must be scope ids separated by space, e.g. "openid profile email"
300+
* @return UriInterface The URL the browser should redirect to, asking the user to authorize
301+
* @throws OAuthClientException
302+
*/
303+
public function startAuthorizationWithId(string $authorizationId, string $clientId, string $clientSecret, UriInterface $returnToUri, string $scope): UriInterface
304+
{
269305
$authorization = new Authorization($authorizationId, $this->getServiceType(), $clientId, Authorization::GRANT_AUTHORIZATION_CODE, $scope);
270306
if ($this->defaultTokenLifetime !== null) {
271307
$authorization->setExpires(new \DateTimeImmutable('+ ' . $this->defaultTokenLifetime . ' seconds'));
@@ -502,16 +538,36 @@ public function renderFinishAuthorizationUri(): string
502538
$this->uriBuilder->setCreateAbsoluteUri(true);
503539

504540
try {
505-
$uri = $this->uriBuilder->
506-
reset()->
507-
setCreateAbsoluteUri(true)->
508-
uriFor('finishAuthorization', ['serviceType' => $this->getServiceType(), 'serviceName' => $this->getServiceName()], 'OAuth', 'Flownative.OAuth2.Client');
541+
$uri = $this->uriBuilder
542+
->reset()
543+
->setCreateAbsoluteUri(true)
544+
->uriFor('finishAuthorization', ['serviceType' => $this->getServiceType(), 'serviceName' => $this->getServiceName()], 'OAuth', 'Flownative.OAuth2.Client');
509545
return $uri;
510546
} catch (MissingActionNameException $e) {
511547
return '';
512548
}
513549
}
514550

551+
/**
552+
* Helper method to set metadata on an Authorization instance. Changes are
553+
* persisted immediately.
554+
*
555+
* @param string $authorizationId
556+
* @param string $metadata
557+
* @return void
558+
*/
559+
public function setAuthorizationMetadata(string $authorizationId, string $metadata): void
560+
{
561+
$authorization = $this->getAuthorization($authorizationId);
562+
if ($authorization === null) {
563+
throw new \RuntimeException(sprintf('Failed setting authorization metadata: authorization %s was not found', $authorizationId), 1631821719);
564+
}
565+
$authorization->setMetadata($metadata);
566+
567+
$this->entityManager->persist($authorization);
568+
$this->entityManager->flush();
569+
}
570+
515571
/**
516572
* @param string $clientId
517573
* @param string $clientSecret
@@ -557,13 +613,13 @@ protected function removeExpiredAuthorizations(): void
557613
*/
558614
public function shutdownObject(): void
559615
{
560-
$decimals = (integer)strlen(strrchr($this->garbageCollectionProbability, '.')) - 1;
616+
$garbageCollectionProbability = (string)$this->garbageCollectionProbability;
617+
$decimals = strlen(strrchr($garbageCollectionProbability, '.') ?: '') - 1;
561618
$factor = ($decimals > -1) ? $decimals * 10 : 1;
562619
try {
563620
if (random_int(1, 100 * $factor) <= ($this->garbageCollectionProbability * $factor)) {
564621
$this->removeExpiredAuthorizations();
565622
}
566-
} catch (InvalidQueryException $e) {
567623
} catch (\Exception $e) {
568624
}
569625
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Neos\Flow\Persistence\Doctrine\Migrations;
5+
6+
use Doctrine\DBAL\Schema\Schema;
7+
use Doctrine\Migrations\AbstractMigration;
8+
9+
/**
10+
* Add metedata column on Authorization table
11+
*/
12+
final class Version20210916194112 extends AbstractMigration
13+
{
14+
public function getDescription(): string
15+
{
16+
return 'Add metedata column on Authorization table';
17+
}
18+
19+
public function up(Schema $schema): void
20+
{
21+
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
22+
23+
$this->addSql('ALTER TABLE flownative_oauth2_client_authorization ADD metadata LONGTEXT DEFAULT NULL');
24+
}
25+
26+
public function down(Schema $schema): void
27+
{
28+
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
29+
30+
$this->addSql('ALTER TABLE flownative_oauth2_client_authorization DROP metadata');
31+
}
32+
}

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,38 @@ Flownative:
5757
Note: By setting the `defaultLifetime` to `null`, new tokens won't expire
5858
by default.
5959

60+
### Authorization metadata
61+
62+
Authorizations also may contain developer-provided metadata. For
63+
example, you may attach an account identifier to an authorization when
64+
an authorization process starts and use that information when
65+
authorization finishes to make sure that the authorization is only used
66+
for a specific account (or customer number, or participant id).
67+
68+
To set metadata, you need to know the authorization id when starting the
69+
authorization code flow. This code could be used in an overloaded
70+
`startAuthorizationAction()`:
71+
72+
```php
73+
$authorizationId = $oAuthClient->generateAuthorizationIdForAuthorizationCodeGrant($this->appId);
74+
$loginUri = $oAuthClient->startAuthorizationWithId(
75+
$authorizationId,
76+
$this->appId,
77+
$this->appSecret,
78+
$returnToUri,
79+
$scope
80+
);
81+
$oAuthClient->setAuthorizationMetadata($authorizationId, json_encode($metadata));
82+
```
83+
84+
And later, in `finishAuthorization()`, you may retrieve the metadata as
85+
follows:
86+
87+
```php
88+
$authorization = $this->getAuthorization($authorizationId);
89+
$metadata = json_decode($authorization->getMetadata());
90+
```
91+
6092
## Encryption
6193

6294
By default, access tokens are serialized and stored unencrypted in the

0 commit comments

Comments
 (0)