cms
cms copied to clipboard
When using Saml2 Socialite provider callback page 404s
Bug description
I set up Saml2 socialite provider. I clicked the "Log in with..." link on /cp
. I authenticate with my identity provider and it redirects to oauth/saml2/callback
that page 404s instead of getting logged in.
After I resolved the issue (see additional details) there are still issues with using saml2 as provider.
How to reproduce
set up a saml socialite provider (I am using Okta) and click the "Log in with..." link.
Logs
No response
Environment
PHP: 8.1.20
laravel/framework: v9.52.16
Statamic: 4.37.0
laravel/socialite: v5.11.0
socialiteproviders/saml2: 4.7.2
Environment
Laravel Version: 9.52.16
PHP Version: 8.1.20
Composer Version: 2.5.8
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED
Drivers
Broadcasting: log
Cache: statamic
Database: mysql
Logs: errorlog
Mail: sendmail
Queue: sync
Session: file
Statamic
Addons: 20
Antlers: runtime
Stache Watcher: Disabled
Static Caching: Disabled
Version: 4.37.0 PRO
Statamic Addons
4rn0/statamic-v3-image-optimizer: 1.1.1
aryehraber/statamic-captcha: 1.10.0
aryehraber/statamic-logbook: 3.1.0
handmadeweb/statamic-cloudflare: 2.0.0
heidkaemper/statamic-toolbar: 1.1.2
jacksleight/statamic-bard-mutator: 2.3.0
jacksleight/statamic-bard-texstyle: 3.1.5
kind-work/two-fa: 1.5.1
rias/statamic-color-swatches: 2.2.0
rias/statamic-redirect: 3.6.1
roorda-ict/statamic-entries-export: 2.1.0
simonridley/tracking-code-manager: 1.0.2
statamic/collaboration: 0.7.3
stillat/relationships: 2.1.3
teamnovu/statamic-unused-assets: 2.0.1
webographen/statamic-admin-log: 1.0.8
webographen/statamic-widget-continue-editing: 1.1.0
withcandour/aardvark-seo: 3.0.1
Installation
Fresh statamic/statamic site via CLI
Antlers Parser
None
Additional details
After debugging the Saml response is a POST request and the statamic callback route is defined as GET.
The main gist of the solution would be to change the line in statamic web.php routes from Route::get(config('statamic.oauth.routes.callback'), [OAuthController::class, 'handleProviderCallback'])->name('oauth.callback');
to Route::any(config('statamic.oauth.routes.callback'), [OAuthController::class, 'handleProviderCallback'])->name('oauth.callback');
to handle any kind of response.
The next issue is that the OAuthController doesn't handle Saml2's stateless nature very well. Below is the route and code I put together to handle the some of the functionality as the controller.
// redirect code from OauthController::successRedirectUrl
// This doesn't redirect correctly back to the control panel
function successRedirectUrlHelper()
{
$default = '/';
$previous = session('_previous.url');
if (! $query = array_get(parse_url($previous), 'query')) {
return $default;
}
parse_str($query, $query);
return array_get($query, 'redirect', $default);
}
Route::post('/oauth/saml2/callback', function () {
$provider = 'saml2';
// some code from Statamic\Http\Controllers\OauthController::handleProviderCallback
// use stateless https://stackoverflow.com/questions/30660847/laravel-socialite-invalidstateexception second answer
$providerUser = Socialite::driver($provider)->stateless()->user();
$userData = [];
// iterate over LiteSAML User assertion attributes
// https://github.com/litesaml/lightsaml/blob/master/src/Model/Assertion/Attribute.php
foreach ($providerUser->user as $attribute) {
$userData[$attribute->getName()] = $attribute->getFirstAttributeValue();
}
// find a user the old fashioned way
$user = User::query()
->where('email', $userData['email'])
->first();
//handle user creation as needed
// more code from OauthController::handleProviderCallback
session()->put('oauth-provider', $provider);
Auth::login($user, config('statamic.oauth.remember_me', true));
return redirect()->to(successRedirectUrlHelper());
});