Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logout via Query Params #3

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions Classes/Authentication/OpenIdConnectProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,11 @@ public function authenticate(TokenInterface $authenticationToken): void
if (!isset($this->options['accountIdentifierTokenValueName'])) {
$this->options['accountIdentifierTokenValueName'] = 'sub';
}
if (!isset($this->options['jwtCookieName'])) {
$this->options['jwtCookieName'] = 'flownative_oidc_jwt';
}
$serviceName = $this->options['serviceName'];
$jwtCookieName = $serviceName . '-jwt';
try {
$jwks = (new OpenIdConnectClient($this->options['serviceName']))->getJwks();
$identityToken = $authenticationToken->extractIdentityTokenFromRequest($this->options['jwtCookieName']);
$jwks = (new OpenIdConnectClient($serviceName))->getJwks();
$identityToken = $authenticationToken->extractIdentityTokenFromRequest($jwtCookieName);
if (!$identityToken->hasValidSignature($jwks)) {
throw new SecurityException(sprintf('Open ID Connect: The identity token provided by the OIDC provider had an invalid signature'), 1561479176);
}
Expand Down
36 changes: 36 additions & 0 deletions Classes/Http/SetJwtCookieComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Neos\Flow\Http\Cookie;
use Neos\Flow\Log\Utility\LogEnvironment;
use Neos\Flow\Security\Context as SecurityContext;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;

final class SetJwtCookieComponent implements ComponentInterface
Expand Down Expand Up @@ -59,6 +60,10 @@ public function initializeObject()
*/
public function handle(ComponentContext $componentContext): void
{
if ($this->isLogoutRequest($componentContext)) {
$this->handleLogout($componentContext);
return;
}
if (!$this->securityContext->isInitialized() && !$this->securityContext->canBeInitialized()) {
$this->logger->debug('OpenID Connect: Cannot send JWT cookie because the security context could not be initialized.', LogEnvironment::fromMethodName(__METHOD__));
return;
Expand All @@ -70,6 +75,7 @@ public function handle(ComponentContext $componentContext): void
if ($account === null) {
$this->logger->debug(sprintf('OpenID Connect: No account is authenticated using the provider %s, removing JWT cookie "%s" if it exists.', $this->options['authenticationProviderName'], $this->options['cookie']['name']), LogEnvironment::fromMethodName(__METHOD__));
$this->removeJwtCookie($componentContext);
$this->logger->info(sprintf('OpenID Connect Client: (%s) Logout requested (via query parameter) removing JWT cookie for service "%s".', get_class($this), $this->options['serviceName']));
return;
}

Expand All @@ -95,6 +101,31 @@ private function isOpenIdConnectAuthentication(): bool
return false;
}

/**
* @param ComponentContext $componentContext
* @return bool
*/
private function isLogoutRequest(ComponentContext $componentContext): bool
{
$httpRequest = $componentContext->getHttpRequest();
if (!$httpRequest instanceof ServerRequestInterface) {
return false;
}
$queryParams = $httpRequest->getQueryParams();
return isset($queryParams['logout']) && $queryParams['logout'] === $this->options['serviceName'];
}

/**
* @param ComponentContext $componentContext
* @return void
*/
private function handleLogout(ComponentContext $componentContext): void
{
$this->removeJwtCookie($componentContext);
$this->logger->info(sprintf('OpenID Connect Client: (%s) Logout requested (via query parameter) removing JWT cookie for service "%s".', get_class($this), $this->options['serviceName']));
$componentContext->replaceHttpResponse($componentContext->getHttpResponse()->withHeader('Location', (string)$componentContext->getHttpRequest()->getUri()->withQuery('')));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This part is a bit magic.. It redirects to the current URI without query params. If other params are required they would be missing. I think we have to revise this part, but without the redirect the account is already authenticated

Copy link
Member

Choose a reason for hiding this comment

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

What about a defined "afterLogout" URL?

}

/**
* @param ComponentContext $componentContext
* @param string $jwt
Expand All @@ -113,4 +144,9 @@ private function removeJwtCookie(ComponentContext $componentContext): void
$emptyJwtCookie = new Cookie($this->options['cookie']['name'], '', 1, null, null, '/', $this->options['cookie']['secure'], false, $this->options['cookie']['sameSite']);
$componentContext->replaceHttpResponse($componentContext->getHttpResponse()->withAddedHeader('Set-Cookie', (string)$emptyJwtCookie));
}

private function jwtCookieName(): string
{
return $this->options['serviceName'] . '-jwt';
}
}
4 changes: 2 additions & 2 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Flownative:
# chain:
# 'Flownative.OpenIdConnect.Client:setJwtCookie':
# componentOptions:
# cookieName: 'your-own-cookie-name-jwt'
# # Use the same service name as below - the corresponding JWT will be stored in a cookie named "<serviceName>-jwt"
# serviceName: 'exampleService'

# security:
# authentication:
Expand All @@ -27,7 +28,6 @@ Flownative:
# providerOptions:
# roles: ['Acme.MyPackage:User']
# accountIdentifierTokenValueName: 'inum'
# jwtCookieName: 'your-own-cookie-name-jwt'
# serviceName: 'exampleService'
# token: 'Flownative\OpenIdConnect\Client\Authentication\OpenIdConnectToken'
# requestPatterns:
Expand Down