Offer «Entrar con Pireon» on the panel's login page
Under the e-mail and password form, a button takes the redirect flow (Authorization Code + PKCE), so the password is only ever typed at the identity server. The routes for it were already there; the page had no way to reach them. A Pireon client allows one grant type and the panel's is a password client, so the redirect flow can use its own: PIREON_REDIRECT_CLIENT_ID and PIREON_REDIRECT_CLIENT_SECRET (the main client when they are empty). The button shows up once that client is set, or with PIREON_REDIRECT_LOGIN=true. Each session renews its token with the client that issued it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,8 +5,13 @@ declare(strict_types=1);
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Pireon\AccessToken;
|
||||
use App\Services\Pireon\TokenStore;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Database\Seeders\RolePermissionSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\Client\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Tests\FakesPireon;
|
||||
use Tests\TestCase;
|
||||
@@ -144,4 +149,57 @@ class PireonLoginTest extends TestCase
|
||||
$this->assertGuest();
|
||||
$this->assertNull(session('pireon.token'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function the_redirect_flow_uses_its_own_client_when_one_is_set(): void
|
||||
{
|
||||
config(['pireon.redirect_client_id' => 'code-client', 'pireon.redirect_client_secret' => 'code-secret']);
|
||||
|
||||
$response = $this->get(route('auth.redirect'));
|
||||
|
||||
$query = [];
|
||||
parse_str((string) parse_url($response->headers->get('Location'), PHP_URL_QUERY), $query);
|
||||
$this->assertSame('code-client', $query['client_id']);
|
||||
|
||||
$this->fakePireon();
|
||||
$this
|
||||
->withSession(['pireon.state' => 'expected-state', 'pireon.code_verifier' => 'the-verifier'])
|
||||
->get(route('auth.callback', ['code' => 'auth-code', 'state' => 'expected-state']))
|
||||
->assertRedirect();
|
||||
|
||||
// The code is redeemed with the client it was issued for.
|
||||
Http::assertSent(fn (Request $request) => str_ends_with($request->url(), '/oauth/token')
|
||||
&& $request['grant_type'] === 'authorization_code'
|
||||
&& $request['client_id'] === 'code-client'
|
||||
&& $request['client_secret'] === 'code-secret');
|
||||
$this->assertSame('redirect', session('pireon.token_issuer'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_redirect_session_renews_its_token_with_the_redirect_client(): void
|
||||
{
|
||||
config(['pireon.redirect_client_id' => 'code-client', 'pireon.redirect_client_secret' => null]);
|
||||
$this->fakePireon(token: ['access_token' => 'renewed-token']);
|
||||
|
||||
$store = app(TokenStore::class);
|
||||
$store->put(new AccessToken('old-token', 'the-refresh-token', CarbonImmutable::now()->subMinute()), viaRedirect: true);
|
||||
|
||||
$this->assertSame('renewed-token', $store->accessToken());
|
||||
Http::assertSent(fn (Request $request) => str_ends_with($request->url(), '/oauth/token')
|
||||
&& $request['grant_type'] === 'refresh_token'
|
||||
&& $request['client_id'] === 'code-client');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function the_login_page_offers_pireon_only_with_a_redirect_client(): void
|
||||
{
|
||||
config(['pireon.redirect_login' => false]);
|
||||
$this->get('/admin/login')->assertOk()->assertDontSee(__('pireon.continue_with_pireon'));
|
||||
|
||||
config(['pireon.redirect_login' => true, 'pireon.redirect_client_id' => 'code-client']);
|
||||
$this->get('/admin/login')
|
||||
->assertOk()
|
||||
->assertSee(__('pireon.continue_with_pireon'))
|
||||
->assertSee(route('auth.redirect'), escape: false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user