Problem/Motivation

When using a multilingual site using domain detection, line 326 of openid_connect/src/Controller/OpenIDConnectRedirectController.php

$redirect = Url::fromUri('internal:/' . ltrim($destination, '/'), ['language' => $language])->toString();

throws an invalid argument exception.

"The internal path component
is external. You are not allowed to specify an external URL together with internal:/."

This happens due to the URL being saved to the session data "openid_connect_destination" in OpenIdConnectSession::saveDestination method, being generated as an absolute URL when processed via LanguageNegorationUrl::processOutbound.

UrlHelper::isExternal is flagging this as external and an exception is thrown.

Steps to reproduce

Add a language and set URL detection to domain and add the domain and an alternative.
Add the OpenIDConnectLoginForm to a page and attempt to login via the form.

CommentFileSizeAuthor
#3 3478572-3.patch1.08 KBj-lee
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

shamrockonov created an issue. See original summary.

j-lee’s picture

Currently it is line 350.

But it is hard to test without the multi-domain language setup in Drupal.
What is provided in $destination? Something like https://my-language-domain.example.com?

Maybe, we can check if $destination is an external url and than remove the 'internal:/':

// The destination parameter should be a prepared uri and include any query
// parameters or fragments already.
//
// @see \Drupal\openid_connect\OpenIDConnectSessionInterface::saveDestination()
$session = $this->session->retrieveDestination();
$destination = $session['destination'] ?: $this->configFactory->get('openid_connect.settings')->get('redirect_login');
$langcode = $session['langcode'] ?: $this->languageManager->getCurrentLanguage()->getId();
$language = $this->languageManager->getLanguage($langcode);

if (UrlHelper::isExternal($destination)) {
    $redirect = $destination;
}
else {
    $redirect = Url::fromUserInput('/' . ltrim($destination, '/'), ['language' => $language])->toString();
}

return new RedirectResponse($redirect);
j-lee’s picture

Status: Active » Needs review
StatusFileSize
new1.08 KB

I have attached a patch file for initial review/testing before I create an MR.

pfrilling made their first commit to this issue’s fork.

pfrilling’s picture

Version: 3.0.0-alpha3 » 3.x-dev

I refactored the destination redirect logic into it's own method and added some validation to confirm if it is external and to confirm it is of the local domain.

I tested with the login block and domain based language detection and all seems to be working correctly.

benjifisher’s picture

Status: Needs review » Needs work

@pfrilling:

The changes for this issue are a little complicated, and I will need at least two rounds of review to understand them well. For this first round of review, I made some low-level suggestions on the MR.

benjifisher’s picture

I have the same question as in Comment #2:

What is provided in $destination? Something like https://my-language-domain.example.com?

I think this question should be answered in the "Steps to Reproduce" section of the issue summary.

As I said on the merge request, I do not see how the current version will fix the problem if $destination is something like https://de.example.com/some/page.

@pfrilling:

In Comment #6, you wrote,

I tested with the login block and domain based language detection and all seems to be working correctly.

Can you say a little more about how you tested? What destination parameter(s) did you try?

pfrilling’s picture

Status: Needs work » Needs review

@benjifisher, I updated the MR with your feedback and addressed some of the comments there.

I tested locally by:
- enabling language negotiation with a subdomain and added a subdomain as a FQDN within ddev.
- placing the login block provided by the module.
- Browsing to `node/1` and clicking login either in the default language or the subdomain, which provided the absolute url as the destination.

I also added an absolute url as the `redirect_login`, which was throwing in certain scenarios. That is why I used `` as the fallback within that method.