Skip to content

feat(stepup): add service display name to Stepup callout AuthnRequest - #2034

Open
kayjoosten wants to merge 2 commits into
mainfrom
feature/issue-2011-stepup-display-name
Open

feat(stepup): add service display name to Stepup callout AuthnRequest#2034
kayjoosten wants to merge 2 commits into
mainfrom
feature/issue-2011-stepup-display-name

Conversation

@kayjoosten

@kayjoosten kayjoosten commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds mdui:UIInfo/mdui:DisplayName to <samlp:Extensions> of the Stepup Gateway SFO callout AuthnRequest, so Stepup can surface the correct service name in its 2FA UI instead of the generic proxy name
  • Controlled by feature flag eb.stepup.send_service_name (disabled by default)
  • Uses the user's current engine locale, falling back to English; prefers mdui DisplayName over flat name* fields
  • Closes Add display name to the Extenstions of SAML request #2011

Technical notes

  • New StepupServiceNameExtension class in src/OpenConext/EngineBlock/Stepup/ follows the same pattern as StepupGsspUserAttributeExtension
  • xml:lang attribute set via setAttributeNS (XML namespace) so XPath and SAML consumers resolve it correctly
  • Locale resolved via existing LocaleProvider::getLocale() available through DiContainer

Test plan

  • 7/7 unit tests pass (StepupServiceNameExtensionTest)
  • 27/27 Behat scenarios pass in Stepup.feature (includes 2 new scenarios: feature enabled / disabled)
  • phpcs and docheader clean on new files
  • Feature flag disabled by default — existing Stepup flow unchanged when flag is off

@kayjoosten
kayjoosten force-pushed the feature/issue-2011-stepup-display-name branch 2 times, most recently from b0887cb to 168d03d Compare June 26, 2026 08:39
@kayjoosten
kayjoosten requested a review from johanib June 29, 2026 08:08
@kayjoosten
kayjoosten force-pushed the feature/issue-2011-stepup-display-name branch from 860bfac to c71e61d Compare July 10, 2026 11:10
Comment thread library/EngineBlock/Corto/ProxyServer.php
Comment thread library/EngineBlock/Corto/ProxyServer.php
final class StepupServiceNameExtension
{
private const MDUI_NS = 'urn:oasis:names:tc:SAML:metadata:ui';
private const SUPPORTED_LOCALES = ['en', 'nl', 'pt'];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hardcoding here, read symfony values or values?

public static function add(Message $message, ServiceProvider $sp, string $locale): void
{
if (!in_array($locale, self::SUPPORTED_LOCALES, true)) {
$locale = 'en';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fallback to global/symfony default?

$locale = 'en';
}
$result = self::resolveName($sp, $locale);
if ($result === null && $locale !== 'en') {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes the default locale === 'en'. Would be better to do $locale !== $defaultLocale

Comment thread src/OpenConext/EngineBlock/Stepup/StepupServiceNameExtension.php
Comment thread src/OpenConext/EngineBlock/Stepup/StepupServiceNameExtension.php
Comment thread config/packages/parameters.yml.dist
kayjoosten added a commit that referenced this pull request Jul 24, 2026
If applied, this commit will make the Stepup service-display-name
extension use EngineBlock's configured default/available locales
instead of a hardcoded locale set, and drop a dynamic property lookup
in favor of an explicit match.

Why is this change needed?
StepupServiceNameExtension hardcoded SUPPORTED_LOCALES = ['en', 'nl',
'pt'] and fell back to the literal string 'en', independent of how the
instance is actually configured. It also read the localized name via
$sp->{'name' . ucfirst($locale)}, a dynamic property access that
duplicates logic already present in
ServiceProvider::getDisplayName().

How does it address the issue?
Adds getDefaultLocale() and getAvailableLocales() to LocaleProvider,
and passes both into StepupServiceNameExtension::add() from
ProxyServer, replacing the hardcoded whitelist and 'en' literal.
Replaces the dynamic property read with an explicit match over the
three schema-backed name columns. Adds a CHANGELOG entry for the
eb.stepup.send_service_name feature flag.

Links / references:
#2034
Stepup currently receives a callout AuthnRequest without the
requesting service's display name. That leaves the Stepup UI showing
a generic proxy label instead of the application the user is logging
in to, which makes the step-up prompt less clear.

Add a dedicated Stepup AuthnRequest extension that emits the service
DisplayName in the SAML extensions payload when the feature flag is
enabled. The value follows the current EngineBlock locale, falls back
to English when needed, and now validates the locale before resolving
dynamic name fields so unsupported locales cannot break lookup.

Resolves: #2011
If applied, this commit will make the Stepup service-display-name
extension use EngineBlock's configured default/available locales
instead of a hardcoded locale set, and drop a dynamic property lookup
in favor of an explicit match.

Why is this change needed?
StepupServiceNameExtension hardcoded SUPPORTED_LOCALES = ['en', 'nl',
'pt'] and fell back to the literal string 'en', independent of how the
instance is actually configured. It also read the localized name via
$sp->{'name' . ucfirst($locale)}, a dynamic property access that
duplicates logic already present in
ServiceProvider::getDisplayName().

How does it address the issue?
Adds getDefaultLocale() and getAvailableLocales() to LocaleProvider,
and passes both into StepupServiceNameExtension::add() from
ProxyServer, replacing the hardcoded whitelist and 'en' literal.
Replaces the dynamic property read with an explicit match over the
three schema-backed name columns. Adds a CHANGELOG entry for the
eb.stepup.send_service_name feature flag.

Links / references:
#2034
@kayjoosten
kayjoosten force-pushed the feature/issue-2011-stepup-display-name branch from cc099f9 to fde41c1 Compare July 27, 2026 08:02
}

$isSendServiceNameConfigured = $features->hasFeature('eb.stepup.send_service_name');
$isSendServiceNameEnabled = $features->isEnabled('eb.stepup.send_service_name');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to inline if, so it doesnt get called if feature flag is not set

@johanib johanib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check dots on i, looks good, no regression 👍

@johanib

johanib commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

and check commit message

@johanib johanib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, we discussed applying the constraints on the servicename from the RFC at the source. So, here in EB.

Can we add the stepup bundle that supplies the sanitization logic so EB can sanitize it beforehand?

@kayjoosten

Copy link
Copy Markdown
Contributor Author

On second thought, we discussed applying the constraints on the servicename from the RFC at the source. So, here in EB.

Can we add the stepup bundle that supplies the sanitization logic so EB can sanitize it beforehand?

Tbh i dont see the benefit, it gets sanitized or overwritten in gateway either way. I know this is something we said in the standup but i think to leave it up to gateway as there the final value will be send out. What do you think about that?

@johanib

johanib commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

On second thought, we discussed applying the constraints on the servicename from the RFC at the source. So, here in EB.
Can we add the stepup bundle that supplies the sanitization logic so EB can sanitize it beforehand?

Tbh i dont see the benefit, it gets sanitized or overwritten in gateway either way. I know this is something we said in the standup but i think to leave it up to gateway as there the final value will be send out. What do you think about that?

If these were official saml specs, we should apply it here. But, as long as we keep within the saml extension fields limit, it should be ok.

Applying this only in gateway seems sensible.
Maybe a good check here in EB would be, what happens if a service name is 2000 chars long? It should probably cut it at a sensible length, like 1000 chars?
Otoh, might as well apply the same sanitization as in stepup, if needed, just add the function to eb.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add display name to the Extenstions of SAML request

2 participants