Closed SolveSoul closed 1 year ago
I advise you to use mocks on tests. You should never hit real Keycloak instance.
@robsontenorio yes, that's very solid feedback!
However, our application is currently migrating from using the native Laravel authentication using sessions to a Keycloak instance using tokens. So all existing unit tests would need to be mocked against every single possible API call of keycloak with all possible different outputs which is a time consuming task (at least in our case).
We've created an isolated test-specific realm which is used for testing and it seems to be working great so far.
Anyway, I've found a work-around:
If request()
is used instead of $this->request
in the KeycloakGuard class then the request object is always up-to-date instead of the one being set when Laravel is bootstrapped. Since #94 is merged it's now possible to have more control over the request property and the work-around can be implemented.
The last consideration for this issue could be to use request()
instead of passing app->request
into the constructor of the KeycloakGuard
but at this point in time I'm not sure if this causes any side-effects.
Here's how I fixed the authentication which works for testing against a live Keycloak instance and normal use
Custom guard which is made possible since PR #94
class ExtendedKeycloakGuard extends KeycloakGuard
{
public function __construct(UserProvider $provider)
{
parent::__construct($provider, request());
}
public function user(): Authenticatable|null
{
if (request()->bearerToken()) {
$this->authenticate();
}
return parent::user();
}
public function getTokenForRequest(): ?string
{
$this->request = request();
return parent::getTokenForRequest();
}
}
then in AppServiceProvider.php
Auth::extend('keycloak', function ($app, $name, array $config) {
return new ExtendedKeycloakGuard(Auth::createUserProvider($config['provider']));
});
Hi,
I'm currently having issues trying to write tests for authentication against a live Keycloak environment. More specifically, the request launched from the test is not the same request as the instance in the KeycloakGuard.
This is the scenario:
The request (
$app->request
) is automatically set at the start of the test via the KeycloakServiceProviderThen when running the test I get a valid access token from the Keycloak instance and set it in the PHPUnit test like this
So far, so good. However, since the request is was only just created and
$app->request
was already set in the KeycloakGuard at the start of the test it means that the token is not set in the request used by the KeycloakGuard. We can see this when dump the request.See this dump example in the Authenticate middleware class of Laravel:
Output (redacted a bit so the important parts are visible):
As you can see, the first request is from the test and correctly contains the bearer token in the Authorization header. However, the second request which was set in the
KeycloakServiceProvider
at the test start does not contain the token but is used to check if a user is authenticated or not.Any ideas on how this could be fixed?
Thanks in advance for any input (and thanks for the creation of this awesome library!)