Skip to content

Give the authentication source Source and Destination before login - #86

Open
cicnavi wants to merge 1 commit into
masterfrom
feat-fticks-before-login
Open

cicnavi wants to merge 1 commit into
masterfrom
feat-fticks-before-login

Conversation

@cicnavi

@cicnavi cicnavi commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

An authentication source that reports failed logins, for example in F-ticks, reads $state['Source']['entityid'] and $state['Destination']['entityid']. casserver set them only after login, for the authproc filters, so a failed CAS login named neither entity. This follows #79, which gave the filters real values.

handleAuthenticate() now passes both to Auth\Simple::login(), with the values the filters see after a successful login:

  • Source comes from AttributeExtractor::resolveIdpEntityId(), now public and shared with runAuthProcs(), so the decision is made in one place.
  • Destination is the requesting service, left out when the request names none. A login without a service runs no authproc filters either.

This covers interactive, renewed and passive logins. A gateway request without passive mode and an existing session do not reach the authentication source and are unchanged.

Session. State::getPersistentAuthData() keeps neither key, so login()'s check that a resumed state belongs to the requested service does not bind a session to its first service. testLoginParamsDoNotBindTheSessionToTheService pins this. saml:SP builds its own Source and Destination after the IdP's response and does not read these.

Note for failure modes. resolveIdpEntityId() now runs on every login reaching the authentication source, not only when authproc is configured, so a non-string idp_entity_id fails there too.

Tests. Run on PHP 8.3 and 8.5 with SimpleSAMLphp v2.5.3.1: 168 tests, 558 assertions; phpcs and phpstan clean.

CI. The PHP 8.3 and 8.4 unit jobs fail on master since #85, unrelated to this change: simplesamlphp-test-framework v2.0.1 requires php ^8.5, so composer install cannot resolve there. I ran 8.3 locally with ~1.11 of the framework.

Assisted-by: Claude Code (claude-opus-5-5, implementation & unit tests)
Assisted-by: Google Antigravity (gemini-3.8-flash-high, review)

An authentication source that reports failed logins, for example in
F-ticks, reads $state['Source']['entityid'] and
$state['Destination']['entityid']. casserver set them only after login,
for the authproc filters, so a failed CAS login named neither entity.

handleAuthenticate() now passes both to Auth\Simple::login(), with the
values the filters see after a successful login: Source comes from
resolveIdpEntityId(), now shared with runAuthProcs(), and Destination is
the requesting service, left out when the request names none. This covers
interactive, renewed and passive logins.

A session keeps neither key, so login()'s check that a resumed state
belongs to the requested service does not bind a session to its first
service. The tests pin both the equal values and that.

Assisted-by: Claude Code (claude-opus-5-5, implementation & unit tests)
Assisted-by: Google Antigravity (gemini-3.8-flash-high, review)
@cicnavi
cicnavi requested a review from ioigoume November 6, 2026 14:24
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.

1 participant