24Slides / laravel-saml2

[Laravel 5.4+] An integration to add SSO to your service via SAML2 protocol based on OneLogin toolkit with support of multiple Identity Providers
MIT License
232 stars 69 forks source link

Redirect Loop #17

Closed juno-w closed 2 years ago

juno-w commented 3 years ago

Hi,

I got a redirect loop on the Microsoft Login page. It keeps log in and log in and log in. The following code is my event listener.

namespace App\Listeners;

use Slides\Saml2\Events\SignedIn;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Auth;
use App\Providers\RouteServiceProvider;

class Saml2SignedIn
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  SignedIn  $event
     * @return void
     */
    public function handle(SignedIn $event)
    {
        // your own code preventing reuse of a $messageId to stop replay attacks
        $user = $event->getSaml2User();

        $userEmail = $user->getAttributes()['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'][0];
        $name = $user->getAttributes()['http://schemas.microsoft.com/identity/claims/displayname'][0];

       $searchUser = \App\Models\User::where('email', $userEmail)->first();

       if ($searchUser) {

                Auth::login($searchUser, true);

                ray('login from existing user');
                ray($searchUser);

                return redirect('/');
            } else {

                $azureUser = \App\Models\User::create([
                    'name' => $name,
                    'email' => $userEmail,
                    'password' => bcrypt('password')
                ]);

                Auth::login($azureUser, true);

                ray('login from new user');

                return redirect(RouteServiceProvider::HOME);
            }

    }
}

I'm able to see the login is success by adding ray debug ray('login from existing user'); . After logged in, it keeps redirect to the same login page again.

juno-w commented 3 years ago
Screenshot 2021-11-01 at 2 39 31 PM

The screenshot shows [Saml2] Tenant resolved being fired twice. This screenshot is a single transaction from after logging in.

juno-w commented 3 years ago

I managed to solve it by adding ?returnTo=https://yourdomain.com/your/actual/link based on your docs. Is this the only solution?

nspaul commented 1 year ago

@juno-w Where did you put this ?returnTo=<url> in your code. I am running into the same issue of getting an infinite SAML loop upon login, and then when I stop that loop and punch my homepage URL in, I am authenticated. It sounds like I am in the same boat as you, but I'm not sure where to actually put that returnTo URL.

juno-w commented 1 year ago

@juno-w Where did you put this ?returnTo=<url> in your code. I am running into the same issue of getting an infinite SAML loop upon login, and then when I stop that loop and punch my homepage URL in, I am authenticated. It sounds like I am in the same boat as you, but I'm not sure where to actually put that returnTo URL.

You may use https://github.com/24Slides/laravel-saml2#sso-friendly-links saml_url() and it will generate link something like https://yourdomain/saml/63fffdd1-f416-4bed-b3db-967b6a56896b/login?returnTo=https://yourdomain.com/your/actual/link

On your Blade file.

<div>
  {{ saml_url() }}
</div>
nspaul commented 1 year ago

Ok, I have generated that URL, but where do you tell the app to redirect to that URL? In your code above, the last few lines of your listener look like this:

Auth::login($azureUser, true);
ray('login from new user');
return redirect(RouteServiceProvider::HOME);

I have very similar code in my listener. Previously when using the aactroneo library, I would just auth that user and then it would pass me through to the app. I auth the user like so: \Auth::login($laravelUser);

I've done some experimentation based on what you have above and I'm trying something like this:

\Auth::login($laravelUser);
return redirect('/');

It's almost like the app is ignoring that redirect, though. I can pepper a bunch of dd() commands in there and I know if auths the user just fine. Once it hits that redirect, though, that's when it gives me the infinite loop of hitting the SAML endpoint, and it's like it can't make it back into my app. If I stop that infinite loop and just put in the root url of my app, it loads the app and I am authenticated. Any thoughts on this?

juno-w commented 1 year ago

...?returnTo=https://yourdomain.com/your/actual/link is the URL you wish to redirect after authenticated. Your SAML service provider (eg. Microsoft) will do the job.

ioiofadhil commented 5 months ago

For me, providing "relay_state_url" in table "saml2_tenants" is the answer, so you don't need to put hardcode returnTo links... I found this code in the vendor folders that says

/**
* Initiate a login request.
*
* @param Illuminate\Http\Request $request
* @param Auth $auth
*
* @return void
*
* @throws OneLoginError
*/
public function login(Request $request, Auth $auth)
{
$redirectUrl = $auth->getTenant()->relay_state_url ?: config('saml2.loginRoute');
$auth->login($request->query('returnTo', $redirectUrl));
}

It just trying to catch your "relay_state_url" in the DB, since it's null, it won't redirect anywhere... @juno-w @nspaul

jithintc commented 4 months ago

I know its a closed thread.. Just adding the solution for new devs ,those who are still facing this issue, I also had the same redirect loop issue when there is no 'relaystate' url provided in the tenant table. In that particular scenario it redirects to the saml login url again. That creates the loop here. To fix this problem simply add the default redirect url as 'loginRoute' at 'config/saml2.php'