mariovalney / laravel-keycloak-web-guard

Simple Keycloak Guard to Laravel Web Routes - https://packagist.org/packages/vizir/laravel-keycloak-web-guard
146 stars 80 forks source link

Wrong redirection #42

Closed wilf1rst closed 3 years ago

wilf1rst commented 3 years ago

Hello,

I've trouble to set the plugin working with my keycloak local development infrastructure.

I've a keycloak container that answer to https://keycloak.dev.local:8443/auth and a laravel / bootstrap frontend that answer to http://serversrequests.dev.local/.

In keycloak I've set a Realm named ServersRequests with a public client frontend-public. The Valid Redirect URIs of the public client is http://serversrequests.dev.local/*.

I hope, when I opened my root url (http://serversrequests.dev.local/), to be redirected to my keycloak address, something like: https://keycloak.dev.local:8443/auth/realms/ServersRequests/protocol/openid-connect/auth?cliend_id=frontend-public&&redirect_uri=http%3A%2F%2Fserversrequests.dev.local%2F but instead i get redirected to http://serversrequests.dev.local/login which indeed not exist and I get a Guzzle error:

Error
Call to undefined method GuzzleHttp\Exception\ConnectException::getResponse() 

Located in: vendor/vizir/laravel-keycloak-web-guard/src/Services/KeycloakService.php:577

Is there's something I miss in my configuration ?

Here's my configuration files:

<?php

return [

    'base_url' => env('KEYCLOAK_BASE_URL', 'https://keycloak.dev.local:8443/auth'),
    'realm' => env('KEYCLOAK_REALM', 'ServersRequests'),
    'realm_public_key' => env('KEYCLOAK_REALM_PUBLIC_KEY', null),
    'client_id' => env('KEYCLOAK_CLIENT_ID', 'frontend-public'),
    'client_secret' => env('KEYCLOAK_CLIENT_SECRET', null),
    'cache_openid' => env('KEYCLOAK_CACHE_OPENID', false),
    'redirect_url' => '/',

    'routes' => [
        'login' => 'login',
        'logout' => 'logout',
        'register' => 'register',
        'callback' => 'callback',
    ],

   'guzzle_options' => [],
];
<?php

return [

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    'guards' => [
        'web' => [
            'driver' => 'keycloak-web',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'keycloak-users',
            'model' => Vizir\KeycloakWebGuard\Models\KeycloakUser::class,
        ],
    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    'password_timeout' => 10800,

];
<?php

use Illuminate\Support\Facades\Route;

Route::group(['middleware' => 'keycloak-web'], function () {
    Route::get('/', function () {
        return view('home');
    }); 
    Route::resource('servers', 'App\Http\Controllers\ServerController');
    Route::resource('tests', 'App\Http\Controllers\TestController');
});
mariovalney commented 3 years ago

Hi Wilfried. How are you?

The "login" route is default for this package. So the redirect is OK, but the Laravel is not able to go to Keycloak login page.

Maybe it's a connection error to get Keycloak openid data. When developing I had a lot of issues with using HTTPS / ports and GuzzleHttp / cURL on my local environment. Maybe your server is not able to get your Keycloak server.

About the error: Call to undefined method GuzzleHttp\Exception\ConnectException::getResponse()

I'll check it but it's just the Log not being able to print the connection exception. So the real problem is the connection. Would you please provide your Laravel and Guzzle versions from composer.json?

wilf1rst commented 3 years ago

Hi Mario,

Here's the package version regarding guzzle and laravel I get from grepping composer.json:

"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^8.12",
"laravel/tinker": "^2.5",
"vizir/laravel-keycloak-web-guard": "^2.3"
"laravel/sail": "^0.0.5",

To add to the discussion: I signed my local development certificate using mkcert, It's a local fake CA that is not know inside the nginx / php-fpm container I used to develop this php app. Can we add an insecure option to guzzle / cURL (like -k|--insecure on cli) if you think that can be a problem ? Or add a debug / trace logs for your package to trace the error ?

Edit:

adding 'guzzle_options' => ['verify' => false], didn't change a thing.

homeoftheunits commented 3 years ago

I have the same Problem. When i use the same keycloak Client in my Vue App, it works

Wenn i call the URL from src/Services/KeycloakService.php:529 in my Browser, i get an correct JSON Response

mariovalney commented 3 years ago

Hi! I updated my Guzzle and as said in documentation:

Function GuzzleHttp\Exception\ConnectException::getResponse() is removed.

I changed the code to handle this. Please, update to 2.3.2 and check the exception message to fix your connection problem.

mariovalney commented 3 years ago

I always had problems to connect a container (laravel curl) to another (keycloak).

I'm not sure it will help, but I'm using a nginx-proxy and to make web container find the SSO URL/domain I'd to add a external_links configuration point to my network.

Screenshot-20210127214341

Maybe you should try something like this or use the container IP. Please check your port is exposed too.

I'm sorry not being able to help more assertive about docker.

homeoftheunits commented 3 years ago

Hm, after the update the error is fixed. But there is an new error:

[Keycloak Error] It was not possible to load OpenId configuration: cURL error 7: Failed to connect to keycloak.local port 443: Connection refused (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://keycloak.local/auth/realms/UnitFactory/.well-known/openid-configuration

I run an docker stack behind an traefik proxy. Nginx and php are seperated containers. I add this to the php container:

    external_links:
      - keycloak_proxy_1:keycloak.local

But it has no affect :(

wilf1rst commented 3 years ago

Hello @mariovalney thanks for the followup.

I just updated the packages version to the 2.3.2 and I get the same error than @homeoftheunits using my local container FQDN keycloak.dev.local (FQDN set in my /etc/hosts, 127.0.0.1 keycloak.dev.local => poor man DNS ;) ).

As you suggest I tried to use the IP container address than and the redirect works.

I think i understand well now what's going on ! The issue seems now more related to the container and how it handle the local FQDN. Indeed I think now it's because how I encode my local FQDN directly in my /etc/hosts and the phpfpm container tried to resolve keycloak.dev.local to itself.

For development purpose it's good however as the authentication works now, I now pass an env variables to my container with my keycloak container IP address -e KEYCLOAK_BASE_URL="https://10.88.2.3:8443/auth". and will do the same to production using the production keycloak FQDN.

I will try afterwards on production on our kubernetes cluster using the real FQDN of our keycloak SSO but I think it would work as it's our DNS that answer keycloak FQDN and not local dev IP umbroglio ;)

I will keep you updated.

Many thanks for your correction !

homeoftheunits commented 3 years ago

Hey guys,

i solved the Problem with the SSL Url. In the getOpenIdConfiguration() i used the ip, then it works. But now, the middleware redirect to often to login.

I debug this, and in the Guard the setUser() sets the user, but the user is null in the KeycloakAuthenticated Middleware. Thats why the middleware redirects to /login, Keycloak says, user is logged, and so on. Until the Browser breaks with to many redirects.

Something should wrong in the Guard

homeoftheunits commented 3 years ago

@mariovalney Is there an solution? It looks like, that the user from keycloak doesn't attempt to Auth?

mariovalney commented 3 years ago

Hi. I just checked new version and it's working well.

Maybe you have a problem in tokens/session been saved?

Please check tokens are saved and retrieved well. If you have any other debug information would help.

Said that, I guess we can use a new issue to don't spam the OP.

homeoftheunits commented 3 years ago

Yes, i make an new issue

wilf1rst commented 3 years ago

@mariovalney To let you know the transition to our kubernetes cluster using env variables for KEYCLOAK_BASE_URL to define the keycloak FQDN works well. So as for now I set the env variable to container IP in local dev and to keycloak FQDN in production. Thanks for your help

BTW: I use podman as a container engine so the problem can differ if using docker (I didn't verify for instance if docker mount your host /etc/hosts inside you container as podman do)

wilf1rst commented 3 years ago

To let you know I was thinking a bit about this issue and using the service discovery features of container you could use your containers name to get rid of the containers IP in you env variables like just:

-e KEYCLOAK_BASE_URL="https://keycloak:8443/auth"

You had to explicitly named your keycloak container first with the --name keycloak flag (docker/podman cli) or container_name: keycloak key (docker-compose/podman-compose).