drenso / symfony-oidc Goto Github PK
View Code? Open in Web Editor NEWThis project contains the Symfony OIDC bundle, which is directly based on https://github.com/jumbojett/OpenID-Connect-PHP
License: Apache License 2.0
This project contains the Symfony OIDC bundle, which is directly based on https://github.com/jumbojett/OpenID-Connect-PHP
License: Apache License 2.0
Hi i am currently integrating a third party openid connect api for our logins.
I ran into a problem where the token response did not include an id_token
parameter. You referenced the RFC but this does not mention a id_token
. Only access_token
, token_type
and state
are required. In fact i can't find a reference to id_token
in the whole RFC.
So what is going on here? Am i just misunderstanding something?
symfony-oidc/src/Model/OidcTokens.php
Lines 24 to 25 in 5d85d50
Edit: Hold on i have accidentally removed the openid
scope. That might be the issue
First of all, pardon my ignorance on this subject. Any pointers in the right direction would be appreciated.
The scenario is that I have an existing Symfony (6.2) application that has a working authentication mechanism using the now native User Entity that talks to a self-hosted database. The application is a single instance that spans multiple domains (say A.com
and B.com
), which is handled by routing. The form_login
resides on one of said domains (say A.com/login
). So far so good.
Now what I want to achieve is that if a user has successfully authenticated with the form on A.com/login
, and then after visits B.com
, they should automatically be authenticated on B.com
. I figured I should be able to do this by introducing OpenID Connect, and that is how I stumbled upon this bundle, but perhaps that was misguided?
I installed and configured the bundle, including a custom UserProvider
and a controller with a checkLogin
. This appears to work as intended, because when I visit B.com/login_oidc
, it redirects me to A.com/login
, and there the user can authenticate. What I fail to understand, however, is how I get B.com
to automatically check the authentication status with A.com
, and then authenticate the user on B.com
accordingly.
I’m sure I’m missing a step, but I’m not sure of the magnitude of this step, ranging from just missing a configuration/setting, to having entirely missed the point of this bundle. Would anyone be so kind as to indicate if this bundle at all helps with what I’m trying to archive, and in any event point me in the right direction? Thanks in advance, as this would be greatly appreciated.
Some OIDC providers like Microsoft accept additional auth params like login_hint
and domain_hint
.1
It would be cool if there was an easy way to pass these parameters when generating the authorization request. Currently, it's only possible by modifying the redirect response.2
This can be currently made in the Jumbojett's implementation by using the field authParams
.3
Maybe we could do this here with an additional parameter at \Drenso\OidcBundle\OidcClient::generateAuthorizationRedirect
(e.g. array $additionalParameters = []
)?
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#send-the-sign-in-request ↩
For instance:
$response = $oidcClient->generateAuthorizationRedirect();
$targetUrl = $response->getTargetUrl();
$targetUrl .= '&' . http_build_query(['domain_hint' => 'example.com']);
return new RedirectResponse($targetUrl);
↩
See https://github.com/jumbojett/OpenID-Connect-PHP/blob/6aae75b1c7b58d8d64a6d14877f77b8a13ab90f6/src/OpenIDConnectClient.php#L594 and https://github.com/jumbojett/OpenID-Connect-PHP/blob/6aae75b1c7b58d8d64a6d14877f77b8a13ab90f6/src/OpenIDConnectClient.php#L797 ↩
In the OidcUserProviderInterface
there is a function ensureUserExists
where the user is either resolved or created. If I use multiple OIDC providers, I am not sure how to save the provider that the user used in this function (e.g. Google, Twitter, ...). Is it possible to access that value in this function or in another place?
These are the identifiers which I would need to access:
drenso_oidc:
clients:
google:
...
twitter:
...
Hello,
is there an example project that uses symfony-oidc?
Hello There,
Can someone have an exemple of his :
Security.yaml
Drenso_oidc.yaml
LoginController.php
Userprovider.php
I can't find a way to get OIDC working, i think i am missing things.
Thinks !
Hello,
thank you for this library.
I'm seeking a way to retrieve the user roles during the authentication in the function ensureUserExists
of the user provider. I noticed that retrieveUserInfo()
does not return the field that contains roles. But I also noticed that the tokens returned by authenticate()
contain these roles.
This is my question: Am I wrong trying to read tokens in the ensureUserExists()
function ?
If I'm not, here is the solution I've in mind:
// vendor/drenso/symfony-oidc-bundle/src/Security/OidcAuthenticator.php
public function authenticate(Request $request): Passport
//...
$authData = $this->oidcClient->authenticate($request);
$userData = $this->oidcClient->retrieveUserInfo($authData);
//...
$this->oidcUserProvider->ensureUserExists($userIdentifier, $userData, $authData);
// INSTEAD OF
$this->oidcUserProvider->ensureUserExists($userIdentifier, $userData);
It's about one single parameter. Will you accept a Pull Request to add this parameter ? If not, could you please suggest me a way to get user roles the right way ?
Thanks in advance
Hi,
I didn't found information for this, so my question is if OpenID Back-Channel Logout is supported out-of-the-box.
Thx
Tobi
Hello,
I'm calling an Open ID Connect which does not provide "nonce" into JWT claims inside the token.
Warning: Undefined property: stdClass::$nonce
This does give me an error inside OidcJwtHelper::verifyJwtClaims
method as it's called through OidcClient::authenticate
method without the possibility of specifying parameter verifyNonce
to set it to false
.
// Request and verify the tokens return $this->verifyTokens( $this->requestTokens('authorization_code', $code, $this->getRedirectUrl()) );
So I dag a little bit and tried to create my own client but was not able to make it replace the default one.
I must say that I'm not particularly familiar with security stuffs into Symfony.
Can you please tell me what I'm doing wrong ?
Thanks.
Benjamin.
PS : Please find attached my configuration files.
drenso_oidc.yaml.txt
security.yaml.txt
Hi,
Thanks for this bundle which is veru usefull !
I get an exception when trying to set up a second client.
drenso_oidc.yaml :
drenso_oidc:
#default_client: default # The default client, will be aliased to OidcClientInterface
clients:
default: # The client name, each client will be aliased to its name (for example, $defaultOidcClient)
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: '%env(OIDC_CLIENT_ID)%'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
# Extra configuration options
redirect_route: '/oidc/login_check'
#custom_client_headers: []
# Add any extra client
another_client: # Will be accessible using $linkOidcClient
well_known_url: 'http://localhost:8080/realms/my-realm/.well-known/openid-configuration'
client_id: 'another_client'
client_secret: 'hA5OUlkzEFX63Qhmf5jFVdfmT9vDgZkX'
When i am connecting with the "default" client it works. But when i'm working with "another_client" i get an exception :
[2023-03-08T16:26:01.252978+01:00] security.INFO: Authenticator failed. {"exception":"[object] (Drenso\\OidcBundle\\Security\\Exception\\OidcAuthenticationException(code: 0): Invalid session state at /var/www/html/fizyou/vendor/drenso/symfony-oidc-bundle/src/OidcClient.php:90)","authenticator":"Drenso\\OidcBundle\\Security\\OidcAuthenticator"} []
[2023-03-08T16:26:01.253267+01:00] security.DEBUG: Authentication failure, redirect triggered. {"failure_path":"/login"} []
Here is my config :
security:
#enable_authenticator_manager: true
providers:
#app_user_provider:
#entity: {class: App\Entity\User, property: email}
oidc_provider:
id: App\Security\OpenIdConnectUserProvider
password_hashers:
App\Entity\User:
algorithm: auto
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: oidc_provider
custom_authenticators:
- App\Security\LoginFormAuthenticator
user_checker: App\Security\UserChecker
form_login: ~
oidc:
user_identifier_property: email
check_path: /oidc/login_check
entry_point: form_login
logout:
path: app_logout
# where to redirect after logout
target: app_login
# configure the maximum login attempts in a custom period of time
login_throttling:
max_attempts: 3
interval: '15 minutes'
remember_me:
secret: '%kernel.secret%'
lifetime: 2592000 # 30 days in seconds
path: /
secure: true
remember_me_parameter: _remember_me`
My controller :
#[Route('/oidc/login/{entityId}', name: 'oidc_login')]
#[IsGranted('PUBLIC_ACCESS')]
public function surfconext(OidcClientLocator $clientLocator, OidcClientInterface $oidcClient, Request $request, string $entityId): RedirectResponse
{
// Redirect to authorization @ OIDC provider
//return $oidcClient->generateAuthorizationRedirect();
return $clientLocator->getClient($entityId)->generateAuthorizationRedirect();
}
#[Route('/oidc/login_check', name: 'oidc_login_check')]
#[IsGranted('PUBLIC_ACCESS')]
public function checkLogin(OidcClientInterface $oidcClient, Request $request, string $code, string $state): RedirectResponse
{
}
Do you have any idea how to fix this issue ?
Thank you !
Hi, i need the authentication token in ensureUserExists to access a profile endpoint to retrieve data to populate a new profile.
On v1 I used loadUserByToken(OidcToken $token)
but this changed to ensureUserExists(string $userIdentifier, OidcUserData $userData)
where i only have the OidcUserData
object.
How can i do this in v2? Do i have to overwrite the OidcClient
class for a custom retrieveUserInfo
?
I noticed this project doesn't have a license file.
The project appears to be licensed with the Apache 2.0 license in the composer.json
1, but this doesn't fulfill the license requirements about the recipients receiving a copy of the license (related StackExchange thread).
SURFconext Test IdP gives as user data:
We would like to use the uid as user identification, however, using an array (with only 1 value) as userIdentifier not supported right now. Is there a way to still use this? Or is there a way to alter the userIdentifier to get a value from this array before using it?
Thanks in advance
Do we have a provision to pass custom headers to curl calls through fetchUrl() of OidcUrlFetcher class?
Hi,
Is there any example how to secure an API with this bundle ?
I've tried to setup the configuration as described in the documentation but when I call the controller I got this error:
No route found for "GET http://localhost/login"
Below the use case:
Our API must be secured with JWT supplied from our third party IDP
The API is being called from an Angular application, actually I'm testing with Postman, I've a public account in our IDP that I'm using
The JWT contains a unique identifier (sub) which is the email's user
I've created a class implementing OidcUserProviderInterface to load the user from our User table which contains ROLES for every user in the system
below my configuration:
//drenso config:
#default_client: default # The default client, will be aliased to OidcClientInterface
clients:
default: # The client name, each client will be aliased to its name (for example, $defaultOidcClient)
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: '%env(OIDC_CLIENT_ID)%'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
well_known_cache_time: 1800 # Time in seconds, will only be used when symfony/cache is available
//security.yml
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_VIEWER, ROLE_APPROVER]
ROLE_APPROVER: [ROLE_USER, ROLE_VIEWER]
ROLE_VIEWER: [ROLE_USER]
providers:
oidc_user_provider:
id: App\Security\OidcUserProvider
enable_authenticator_manager: true
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/
# pattern: ^/api/(v|V)[0-9]+/.*
stateless: true
provider: oidc_user_provider
oidc:
user_identifier_from_idtoken: true
user_identifier_property: "%env(USER_IDENTITY_FIELD)%"
main:
provider: oidc_user_provider
pattern: ^/
oidc: ~
lazy: true
stateless: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/api/(v|V)[0-9]+/.*, roles: [ROLE_USER] }
- { path: ^/api/(v|V)[0-9]+/admin/.*, roles: ROLE_ADMIN }
//controller
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\User\UserInterface;
use Drenso\OidcBundle\OidcClientInterface;
#[Route('/api/v1', name:'lucky')]
class LuckyController extends AbstractController {
#[Route('/lucky/number', name:'lucky_number')]
// public function number(UserInterface $user): JsonResponse
public function number(OidcClientInterface $user): JsonResponse
{
try {
$number = random_int(0, 100);
$data = [
'username' => $user->getFirstName() . ' '.$user->getLastName(),
'random_number' => $number
];
// Return a JSON response with the data
return $this->json($data);
}
catch(BadCredentialsException){
return $this->json(['error' => $e->getMessage()], 401);
}
catch(Exception){
return $this->json(['error' => $e->getMessage()], 500);
}
}
}
We are unable to pass additional parameter idP adapter (pfidpadapterid) details as the constructor accepts only $wellKnownUrl, $clientId, $clientSecret parameters. Is there a possibility to pass the idP adapter details to the oidcclient?
Hello,
please could you explain, how to use more clients with their check_paths in one firewall? I would like to distinguish what "response" is from where and so what to do in code.
Thank you, J.
Heya, I was trying to set up your bundle in a Symfony 6.1 project and pointing it at Facebook for OIDC connectivity (using their configuration endpoint as specified on https://developers.facebook.com/docs/facebook-login/limited-login/token/)
However, authentication seems to fail, after some digging around and adding some dumps to the OidcClient
, I figured out that it fails inside of the getConfigurationValue(string $key)
method, as it is looking for the key token_endpoint_auth_methods_supported
in the configuration, but this key isn't present. See the screenshot below for the dumped config object.
Any clue how to proceed and/or combat this? :) If there's anything I can do to help out, provide more info, etc, let me know :)
Hi,
First of all, I'd like to warn that I'm very new to OpenID implementations, and as such, I might have failed to properly understand how it works and this issue could be a pebkac in this instance. If it is, my apologies.
That being said : I am having an issue with the library when using the openid
scope, specifically within the OidcAuthenticator and the OidcClient. I'm running version 3.1.0.
Here is theOidcClient::retrieveUserInfo
method.
public function retrieveUserInfo(OidcTokens $tokens): OidcUserData
{
// Set the authorization header
$headers = ["Authorization: Bearer {$tokens->getAccessToken()}"];
// Retrieve the user information and convert the encoding to UTF-8 to harden for surfconext UTF-8 bug
$jsonData = $this->urlFetcher->fetchUrl($this->getUserinfoEndpoint(), null, $headers);
$jsonData = mb_convert_encoding($jsonData, 'UTF-8');
// Read the data
$data = json_decode($jsonData, true);
// Check data due
if (!is_array($data)) {
throw new OidcException('Error retrieving the user info from the endpoint.');
}
return new OidcUserData($data);
}
As you can see, the method expects the returned data to be available immediately, and tries to json_decode it. However, as per the OpenID specs of the UserInfo response, this data might actually be encoded within a JWT as well. If it is, the json_decode will return null
(because we are passing it the encoded JWT, and not actual json data), which will then trigger the throw, and making the whole auth fail despite my provider sending back the correct data (I've decoded the response manually for debug purposes).
I thought that maybe I was missing something and that the user_identifier_from_idtoken
config value had to be set to true
when using encoded openid
, but even so, given how the OidcAuthenticator::authenticate
method is implemented, the OidcClient::retrieveUserInfo
will be called regardless and will fail anyway.
public function authenticate(Request $request): Passport
{
try {
// Try to authenticate the request
$authData = $this->oidcClient->authenticate($request);
// Retrieve the user data with the authentication data
$userData = $this->oidcClient->retrieveUserInfo($authData);
// Look for the user identifier in either the id_token or the userinfo endpoint
if ($this->userIdentifierFromIdToken) {
$userIdentifier = OidcJwtHelper::parseToken($authData->getIdToken())
->claims()
->get($this->userIdentifierProperty);
} else {
$userIdentifier = $userData->getUserDataString($this->userIdentifierProperty);
}
[Rest of the code, irrelevent to my current issue]
return $passport;
} catch (OidcException $e) {
throw new OidcAuthenticationException('OIDC authentication failed', $e);
}
}
So, ultimately, the issue I'm raising is : shouldn't the OidcClient::retrieveUserInfo
method handle having an JWT-encoded response ?
I am seeing really slow response times for the /login_check
endpoint.
It is ~4 seconds in the dev
environment - I see in the profiler that TraceableFirewallListener
is taking almost all of this time.
Then I compared this to the time for the /login_check
endpoint in my prod
environment and it's roughly the same 4 seconds, so I don't think it's any debugging / profiling overhead particularly.
Any ideas what could be causing the endpoint to take so long to return a response?
Thanks!
I am currently in the process of configuring my Symfony App to connect with Casdoor.
The Casdoor OIDC discovery is missing the token_endpoint_auth_methods_supported
(https://casdoor.org/fr/docs/how-to-connect/oidc-client/), which leads to an OidcConfigurationException
in the bundle.
From https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3
token_endpoint_auth_methods_supported
OPTIONAL. JSON array containing a list of Client Authentication methods supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 9 of OpenID Connect Core 1.0 [OpenID.Core]. Other authentication methods MAY be defined by extensions. If omitted, the default is client_secret_basic -- the HTTP Basic Authentication Scheme specified in Section 2.3.1 of OAuth 2.0 [RFC6749].
It seems to me that the token_endpoint_auth_methods_supported key should be optional and the parser should default to ['client_secret_basic'] if it is missing ?
I get in my Symfony No route found for "POST https://my.domain/login_check" (from "https://identity-provider.domain/")
if my identity-provider redirects back to the redirect_uri (https://my.domain/login_check) including a code parameter. It is OpenID Connect Code Flow step 5.
Symfony: 6.3
drenso/symfony-oidc-bundle: 2.12.0
my security.yaml:
security:
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
providers:
oidc_user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
oidc: ~
lazy: true
provider: oidc_user_provider
access_control:
my drenso_oidc.yaml :
drenso_oidc:
#default_client: default # The default client, will be aliased to OidcClientInterface
clients:
default: # The client name, each client will be aliased to its name (for example, $defaultOidcClient)
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: '%env(OIDC_CLIENT_ID)%'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
my LoginController.php:
class LoginController extends AbstractController
{
/**
* This controller forwards the user to the OIDC login
* @throws OidcException
*/
#[Route('/login_oidc', name: 'login_oidc')]
#[IsGranted('PUBLIC_ACCESS')]
public function loginOidc(OidcClientInterface $oidcClient): RedirectResponse
{
// Redirect to authorization @ OIDC provider
return $oidcClient->generateAuthorizationRedirect('login', ['openid'], false, ['response_mode' => 'form_post']);
}
}
Hi, I couldn't find any issue mentionning this (nor could I find any info in the docs).
After succesfully setting up Zitadel with my app, for testing purposes, I'm trying to set up another provider, Logto.
When trying to log in, the following exception is thrown :
Drenso\OidcBundle\Security\Exception\OidcAuthenticationException
#message: "No support for signature type: ES384"
#file: ".../vendor/drenso/symfony-oidc-bundle/src/OidcJwtHelper.php&line=130#line130)"
While the error itself is pretty self-explanatory, the following is not :
Thanks for reading, and thanks for the bundle 👍
Hello,
Seems there is a problem with set refresh token. I using this for a symfony project, and i found that refresh token is not set to user object, looked on source code and found the problem in src/OidcTokens.php in counstructor that it check a 'refresh_tokens' instead of 'refresh_token'
if (isset($tokens->refresh_tokens)) {
$this->refreshToken = $tokens->refresh_tokens;
}
is it correct or maybe it's a bug?
Hello,
I have a problem with authorization_endpoint, the client don't find my endpoint, I create a custom manager client with the correct authorization_endpoint but the problem is the bundle always take the default client. here my configuration
main:
lazy: true
oidc:
provider: oidc_provider
login_path: /gardian/login
check_path: /gardian/login_check
client: gardian
user_identifier_property: nni
Action in the controller
/**
* This controller forwards the user to the OIDC login
*
* @throws OidcException
*/
#[Route('/gardian/login', name: 'login_oidc')]
#[IsGranted('PUBLIC_ACCESS')]
public function surfconext(OidcClientInterface $gardianOidcClient): RedirectResponse
{
// Redirect to authorization @ OIDC provider
return $gardianClient->generateAuthorizationRedirect();
}
configuration of the bundle
drenso_oidc:
#default_client: default # The default client, will be aliased to OidcClientInterface
clients:
default: # The client name, each client will be aliased to its name (for example, $defaultOidcClient)
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: '%env(OIDC_CLIENT_ID)%'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
redirect_route: '%env(OIDC_REDIRECT_ROUTE)%'
gardian: # The client name, each client will be aliased to its name (for example, $gardianOidcClient)
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: '%env(OIDC_CLIENT_ID)%'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
redirect_route: '%env(OIDC_REDIRECT_ROUTE)%'
I used the OidcClientLocator but I have the same problem.
in my use case a have another identity provider so OidcClient dosn't work for me i have to override (generateAuthorizationRedirect methode) because my identity provider takes more paramets that are not available in
$data = [
'client_id' => $this->clientId,
'response_type' => 'code',
'redirect_uri' => $this->getRedirectUrl(),
'scope' => implode(' ', $scopes),
'state' => $this->generateState(),
'nonce' => $this->generateNonce(),
];
Is it possible to do such thing ?
phpsesclib contians the following security issues and needs to be pined to the versions ^2.0.47 and ^3.0.36.
+-------------------+----------------------------------------------------------------------------------+
| Package | phpseclib/phpseclib |
| Severity | high |
| CVE | CVE-2024-27354 |
| Title | phpseclib a large prime can cause a denial of service |
| URL | https://github.com/advisories/GHSA-hg35-mp25-qf6h |
| Affected versions | >=3.0.0,<3.0.36|>=2.0.0,<2.0.47|>=1.0.0,<1.0.23 |
| Reported at | 2024-03-02T00:31:33+00:00 |
+-------------------+----------------------------------------------------------------------------------+
+-------------------+----------------------------------------------------------------------------------+
| Package | phpseclib/phpseclib |
| Severity | high |
| CVE | CVE-2024-27355 |
| Title | phpseclib does not properly limit the ASN1 OID length |
| URL | https://github.com/advisories/GHSA-jr22-8qgm-4q87 |
| Affected versions | >=2.0.0,<2.0.47|>=3.0.0,<3.0.36|<1.0.23 |
| Reported at | 2024-03-02T00:31:33+00:00 |
+-------------------+----------------------------------------------------------------------------------+
https://github.com/phpseclib/phpseclib/blob/2.0.47/CHANGELOG.md
https://github.com/phpseclib/phpseclib/blob/3.0.36/CHANGELOG.md
My current workplace is an identity provider and we wanted to publish an example symfony project that uses OIDC with our product. Although I'm not a PHP engineer, it was quite straightforward to get started with Symfony and this OIDC bundle. Kudos for that!
I came across #1, where you mentioned:
I currently do not know of any project that uses this library, and is open source at the same time.
Well, we are a open source company and naturally our example is also open source 😄 . If it is is not a conflict with your own business, I would like to add a link to our project in your README.
https://github.com/zitadel/example-symfony-oidc
Thanks!
During my authentication phase, I am getting an error from OidcJwtHelper
.
Drenso\OidcBundle\OidcJwtHelper::decodeJwt(): Return value must be of type object, null returned
I did some debugging and it looks like the value that is being returned to decodeJwt
from the base64url_decode
function when $section
is 0
is binary so when json_decode
is called it fails and returns a null. I am not familiar enough with OIDC to be able to say why the value is binary or what the normal expected value is.
I would be happy to post the encoded value here, but I'm not sure if it contains any secrets.
Currently, I'm trying to implement an OIDC client flow using this bundle. After following the steps provided in the readme, I've received an "Unable to generate a URL for the named route "login_check" as such route does not exist." error. After checking out the source code, it has become clear that the login_check route is used to verify the returned authorization code. However, this is step is currently undocumented.
In Symfony 6.2 there is a new class AccessTokenHandler
, which allow you to implement support for checking a token which was provided through a Header, Request Body or Querystring.
Would you accept a PR which adds a AccessTokenHandler which can be activated through:
# config/packages/security.yaml
security:
firewalls:
main:
oidc: ~
access_token:
token_handler: Drenso\OidcBundle\Security\OidcAccessTokenHandler
The OidcAccessTokenHandler
will contain the code to check if the passed Token is valid against the active Oidc client for this particular firewall.
This implementation then can be used for example if the Symfony Application contains a REST api and the API client sends the token to the SF REST API. The AccessTokenHandler will then check if the passed token is still valid.
It would need a disclaimer it is only usable with SF 6.2
Hello,
Would it be possible to add an optional parameter to the OidcClient generateEndSessionEndpointRedirect function?
According to the documentation (https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout):
It is up to the RP whether to locally log out the End-User before redirecting the User Agent to the OP's Logout Endpoint. On one hand, if the End-User approves the logout at the OP, the RP initiating the logout should receive a logout message from the OP and can perform a local logout at that time. On the other hand, some logout notification methods from the OP to the RP are unreliable and therefore the notification might not be received. Also, the End-User might not approve the OP logging out, in which case the RP would not receive a logout notification.
This would avoid overwriting / decorating the functionality just to kill the token when you want to disconnect the application manually.
If it's possible, I'll leave it up to you how you implement it.
# In generateEndSessionEndpointRedirect function
# ...
if (null !== $postLogoutRedirectUrl) {
$data = array_merge($data, [
'post_logout_redirect_uri' => $postLogoutRedirectUrl,
]);
}
###############################################
// Implementation of conditional local logout
###############################################
$endpointHasQuery = parse_url($this->endSessionEndpoint, PHP_URL_QUERY);
return new RedirectResponse(
sprintf(
'%s%s%s',
$this->endSessionEndpoint,
$endpointHasQuery ? '&' : '?', http_build_query($data))
);
I see accessToken value in PHP Session. Can I get this by symfony-oidc-Library or by Symfony APIs ?
Versions
Symfony 6.4
drenso/symfony-oidc-bundle 2.13.0
Hi,
I'm looking to connect to AzureAD OIDC and match users in an LDAP that don't know the sub. I am not able to use the upn claim as the user_identifier_property
. The problem seems to be that the upn
claim is not present in the userinfo endpoint of AzureAD, but only in the idtoken. Apparently you can't change the data in de userinfo endpoint: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo. Yay Microsoft :-(.
"Notes and caveats on the UserInfo endpoint
You can't add to or customize the information returned by the UserInfo endpoint.
To customize the information returned by the identity platform during authentication and authorization, use claims mapping and optional claims to modify security token configuration."_
I don't see any existing option in the Drenso OIDC library to use data of the idtoken to use as user_identifier_property
. I see some solutions:
user_identifier_property
.public function retrieveUserInfo(OidcTokens $tokens): OidcUserData
. If there is an id_token. The idtoken is already passed in inside $token, I think.OidcClient
with a custom retrieveUserInfo()` which uses the id_token in the retrieveUserInfo. Which would work for me now and not require altering this library.What do you think is the way to do this best? Maybe I missed something obvious?
Regards,
Albert-Jan
We need to check some additional constraints / claims. How can I extend the verifyToken function to add an additional constraint (HasClaimWithValue)?
We have to set an acr claim value and therefor we have to check if the same acr
value is returned in the tokens.
I have upgraded a previously working setup to v3.0 and now I cannot login. The login_check
endpoint 500 errors with The JWT string must have two dots
.
I don't believe any of the upgrade notes affected my setup, my SSO provider (Zitadel) was working fine before the upgrade, so presuming tokens are the same. (i.e. no code has been changed, just the upgrade of the package to 3.0)
Is this because the v3.0 utilises the lcobucci/jwt
package which is applying stricter validation perhaps?
Lcobucci\JWT\Token\InvalidTokenStructure:
The JWT string must have two dots
at vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php:13
at Lcobucci\JWT\Token\InvalidTokenStructure::missingOrNotEnoughSeparators()
(vendor/lcobucci/jwt/src/Token/Parser.php:65)
Thank you
You were right about the rfc. I am sorry, had a different interpretation of the specs.
I've found some information about the difference to the Microsoft stuff and i have two initial questions:
If so, i would prefer to clarify how a possible solution could look like in first place.
Unfortunately Microsoft does here really something different (wrong!?) than expected.
Here is the Microsoft related problem:
Microsoft uses different issuers for ID Tokens and Access Tokens, which can lead to issues when validating the issuer on tokens. This is a common problem that developers face when working with Microsoft’s identity platform.
ID Tokens
ID Tokens are used for authentication and are issued by the Azure Active Directory (AAD) tenant. The issuer for ID Tokens is typically in the format https://login.microsoftonline.com/{tenant_id}/v2.0. For example, if the tenant ID is 12345678-1234-1234-1234-123456789012, the issuer would be https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0.
Access Tokens
Access Tokens, on the other hand, are used for authorization and are issued by the Azure AD App Registration. The issuer for Access Tokens is typically in the format https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration. Again, using the same example tenant ID, the issuer would be https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration.
Validation Issues
The main issue that arises from using different issuers for ID Tokens and Access Tokens is that when validating the issuer on tokens, the validation logic needs to be aware of the different issuers used by Microsoft. This can lead to complex and error-prone code, especially when working with multiple tenants or applications.
Conclusion
In conclusion, Microsoft’s use of different issuers for ID Tokens and Access Tokens can lead to issues when validating the issuer on tokens. Developers need to be aware of these differences and implement the necessary logic to handle the different issuers used by Microsoft.
Would be great to discuss a solution.
I am trying to have multiple firewalls in Symfony with each their own OIDC config.
In the firewall I specify the client:
rkd:
pattern: ^/rkd
lazy: true
provider: oidc_user_provider
oidc:
client: rkd
user_identifier_property: 'email'
login_path: '/rkd/login_oidc'
check_path: '/rkd/login_check'
logout:
path: logout
admin:
pattern: ^/admin
lazy: true
provider: oidc_user_provider
oidc:
client: admin
user_identifier_property: 'email'
login_path: '/admin/login_oidc'
check_path: '/admin/login_check'
logout:
path: logout
I have multiple clients defined, which I can load with DI if i know the client name in the DI OIDCClientInterface the login url. But I would like to get a specific named client dynamically.
default:
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: '%env(OIDC_CLIENT_ID)%'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
redirect_route: '/rkd/login_check'
admin:
# Required OIDC client configuration
well_known_url: '%env(OIDC_WELL_KNOWN_URL)%'
client_id: 'cap_rkd'
client_secret: '%env(OIDC_CLIENT_SECRET)%'
redirect_route: '/test/login_check'
The problem is with starting the OIDC, I always get the default client in the login controller.
#[Route('/{slug}/login_oidc', name: 'login_oidc')]
#[IsGranted('PUBLIC_ACCESS')]
public function surfconext(Organisation $organisation, OidcClientInterface $client): RedirectResponse
{
return $client->generateAuthorizationRedirect();
}
How can I best get the specific client in this case?
Hi There,
I am trying to implement the bundle with https://logto.io/, which is an OpenID provider. But when I redirect it through the $oidcClient->generateAuthorizationRedirect();
I instantly get an error while being redirected back to my application with the following error: "Authorization Server policy requires PKCE to be used for this request".
For now it is not an option to disable PKCE on the Logto side, is it possible to use PKCE with this bundle?
Thanks in advance.
Hello everyone
I have discovered a problem with token verification with Azure.
I don't know the reason yet and therefore I don't have a fix ready.
I have now built a workaround to move forward, like disable_nonce
but for disable_token_verification
.
Token verification can be switched off optionally but is switched on by default.
Not validating the token is of course bad and not a real solution, but would you allow this config or not?
Would you like this PR already or should I get back to you when/if I have a fix ready?
If any of you would like to have a look into that too, please feel free.
The error occurs on:
message = "Unable to verify JWT claims"
file = "/var/www/app/vendor/drenso/symfony-oidc-bundle/src/OidcJwtHelper.php"
line = 167
When OidcTokenType = ACCESS
It fails on validating token signature
The 5.3 release of Symfony has deprecated the previous security implementation in favour of the Authentication manager (https://symfony.com/doc/current/security/authenticator_manager.html).
Updating to the Authentication manager with Symfony-oidc as authentication provider gives an error message. This message mentions that oidc cannot be configured because it does not support the new authentication manager.
Edit : pre-existing well-known
data existed in the cache, so the custom parser wasn't called.
Hi,
I need to hook up my app with an OIDC provider that does not supply a "well-known" url, so I was thinking of injecting all the config through a well_known_parser
.
drenso_oidc:
clients:
default:
# [well_known_url, client_id, client_secret...]
well_known_parser: 'App\Security\Oidc\CustomWellKnownParser'
However, after setting one up (I called it CustomWellKnownParser
), it's never called. I know it has been taken into account, since I can see it while inspecting the OidcClient
in a debugger :
(No sensitive information here, it's a local test environment)
To test whether the custom parser was being called, I tried setting a breakpoint there (not hit) and changing the $config
array (the change is never reflected).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.