Repository navigation
Releases: jmoral/simplesamlphp-module-multiauthsinglepage
Releases · jmoral/simplesamlphp-module-multiauthsinglepage
Release list
v2.1.0-rc.6
[2.1.0-rc.6] - 2026-09-18
Fixed
LoginThrottle::ERROR_CODE(MULTIAUTHTHROTTLED) is now registered with
a title and description in the\SimpleSAML\Error\ErrorCodesmaps, via
the new\SimpleSAML\Module\multiauthsinglepage\Error\ErrorCodes. Without
this, any template renderingerrorcodes['title'][errorcode]generically
-- including a theme's own copy ofmultiauthonepage.twigthat predates
this error code -- crashed withTwig\Error\RuntimeError: Key "MULTIAUTHTHROTTLED" for sequence/mapping ... does not exist, since the
key was never registered anywhere.SinglepageControllernow builds
errorcodesfrom this class instead of the base one.
v2.1.0-rc.5
[2.1.0-rc.5] - 2026-09-18
Changed
- A
LoginThrottle-triggered block (more than 3 consecutive failed
username/password attempts for the same username in the same browser
session) is now shown to the user, unlike anaccessControl-triggered
block: a generic "please wait a moment" message with tips (check the
username/password, watch out for Caps Lock or the wrong keyboard layout),
with no exact countdown or attempt count. This is safe because, unlike
accessControl,LoginThrottledoesn't depend on the username
corresponding to a real account and doesn't expose anything about an
external system, so it cannot be used to enumerate accounts or fingerprint
another service's detection logic. NewLoginThrottle::ERROR_CODE
(MULTIAUTHTHROTTLED) distinguishes it fromWRONGUSERPASS, both in the
controller and intemplates/multiauthonepage.twig.
v2.1.0-rc.4
[2.1.0-rc.4] - 2026-09-18
Added
- A new, always-on local throttle: after more than 3 consecutive failed
username/password login attempts for the same username (tracked per
browser session), further attempts are refused with an exponential
backoff wait (2s, 4s, 8s, ... capped at 300s, counted from the last
failure) until it elapses, without even reaching the authentication
source. This is independent of theaccessControlwebservice option and
always active. As with a webservice-triggered block, it is indistinguishable
from a plain wrong password to the user; only the server-side log (error
level) shows it happened. See the new
\SimpleSAML\Module\multiauthsinglepage\LoginThrottleand the README.
Changed
- A blocked login attempt (
accessControlwebservice returning HTTP 429) no
longer shows a "please wait" message with a countdown: the login page now
shows the exact same generic wrong-username-or-password error as any other
rejected attempt, so an attacker cannot tell a backed-off attempt apart
from a plain wrong password. The computed wait time is only written to the
server-side log (AccessBackoff, aterrorlevel). AccessBackoff::registerBlock()now logs the username, attempt number and
computed wait time aterrorlevel on every block.
v2.1.0-rc.3
[2.1.0-rc.3] - 2026-09-17
Added
- A login attempt against a username/password source can now be checked
against an external webservice before the credentials are validated, via
the newaccessControlauthsource option (url,apiKey,verifySsl,
connectTimeout,timeout). Disabled unless aurlis configured. When
the webservice responds HTTP 429 ("too many requests"), the attempt is not
tried against the authentication source; the login page shows a generic
wait message with a per-username, per-session exponential backoff (2s, 4s,
8s, ... capped at 300s) instead. Any other failure talking to the
webservice fails open. This runs on every attempt regardless of outcome,
so it also covers users stuck in a wrong-password loop, unlike the
post-hocaccessLogreporting. See the new
\SimpleSAML\Module\multiauthsinglepage\AccessCheckerand
\SimpleSAML\Module\multiauthsinglepage\AccessBackoff, and the README. SinglepageControllergained protectedmakeAccessChecker()/
makeAccessBackoff()factory methods, overridable in tests the same way
setAuthState()already is.- Both
AccessCheckerandAccessLoggernow also sendforwarded(the
X-Forwarded-Forheader, if any) andpodName/nodeName(the
POD_NAME/NODE_NAMEenvironment variables, if set) to the webservice,
to help identify the originating client and serving instance in a
clustered deployment.
Changed
SinglepageController::checkAccessOrGetWaitSeconds()now skips the
access-control check (and the backoff-reset session write) entirely when
noaccessControl.urlis configured, instead of calling the webservice
gate and resetting the backoff counter on every login attempt regardless.
v2.0.0-rc.2
Changed
AccessLogger's defaultconnectTimeout/timeoutlowered from 10s/20s to
2s/3s. The webservice call is still synchronous (it runs inline in
handleUserPassLogin()), so a slow or unreachable webservice must not add
more than a couple of seconds to a failed login.
v2.1.0-rc.2
Pre-release for testing against a full pre-production SimpleSAMLphp
environment.
Added
- Failed login attempts against a username/password source can now be
reported to an external webservice, via the newaccessLogauthsource
option (url,apiKey,sistemaAutenticacion,idpExterno,
verifySsl,connectTimeout,timeout). Disabled unless aurlis
configured; a failure talking to the webservice is only logged and never
affects the login flow. See the new\SimpleSAML\Module\multiauthsinglepage\AccessLogger
and the README. ext-curladded tocomposer.json(used byAccessLogger).
v2.0.0
Verified against a full pre-production SimpleSAMLphp environment (as
v2.0.0-rc.1/rc.2). Breaking changes relative to v1.0.7: minimum PHP is now
8.3, minimum SimpleSAMLphp is now 2.5.2, and handleLoginPass() was renamed
to handleUserPassLogin() and retyped.
Added
- The
sourcesoption is now wired through to the login page: the controller
passes asourceslist (id,label,userpass) to the template, which
renders one form per source.authsourcevalues not insourcesare
rejected. - Tests for the
Multiauthsinglepageauthentication source (constructor
validation, credential guard, session handling, logout error path).
Changed
- Require PHP >= 8.3 and SimpleSAMLphp >= 2.5.2.
Multiauthsinglepage::authenticate()now returnsnever, to match
saml:SPin SimpleSAMLphp 2.5.- Any
core:UserPassBasesource (e.g.ldap:Ldap,sqlauth:SQL,
core:AdminPassword) is now authenticated on the single page, not just
ldap:Ldap. The dispatch checksinstanceof UserPassBase;
handleLoginPass()was renamed tohandleUserPassLogin(), typed
accordingly, and reaches the source's (alwaysprotected)login()via
reflection. - Replaced the deprecated
Request::get()(Symfony 7.4) with explicit
query-string / POST-body reads. - Single code style tool (
phpcswith the SimpleSAMLphp standard); dropped
php-cs-fixer. - Loosened the
simplesamlphp-module-ldapconstraint from2.5.2to
^2.5.2. - The test bootstrap defines
SIMPLESAMLPHP_TEST_NOEXITso redirect flows
can be exercised in tests. - Rewrote the README with a real configuration example.
Fixed
- The login template read
errorTitle/errorDesc, which the controller
never set, so errors were never shown; it now useserrorcode/
errorcodes/errorparams. handleUserPassLogin()no longer raises aTypeErrorwhen the username or
password is missing; it throwsError\Error(WRONGUSERPASS)instead.- The full authentication state is no longer written to the debug log.
LICENSEwas an empty file; it now contains the GNU LGPL 2.1 text.- Moved the
SuccessAuthSourcetest fixture out ofsrc/intotests/,
fixing its PSR-4 mapping. - The "skipping source" log for a source that fails to load is now a
warningrather thandebug, so a misconfiguration is visible without
turning on debug logging.
Removed
LdapSinglePage. It could never construct: anldap:Ldapsubclass
configured under any authsource type other thanldap:Ldapfails, because
SimpleSAML\Module\ldap\ConnectorFactory::fromAuthSource()asserts the
authsource's configured type is literally"ldap:Ldap"— regardless of the
PHP class hierarchy. Configure LDAP sources as plainldap:Ldap.
v2.0.0-rc.2
ound while testing v2.0.0-rc.1 against a full pre-production SimpleSAMLphp
environment.
Fixed
- Removed
LdapSinglePage. It could never construct: anldap:Ldap
subclass configured under any other authsource type (such as
multiauthsinglepage:LdapSinglePage) fails, because
SimpleSAML\Module\ldap\ConnectorFactory::fromAuthSource()asserts the
authsource's configured type is literally"ldap:Ldap"— regardless of the
PHP class hierarchy. Configure LDAP sources as plainldap:Ldap;
handleUserPassLogin()now always reacheslogin()through reflection
(this was already the fallback for every otherUserPassBasesource). - Raised the "skipping source" log for a source that fails to load from
debugtowarning, so a misconfiguration like the above is visible
without turning on debug logging.
v2.0.0-rc.1
This is a pre-release for testing against full SimpleSAMLphp pre-production
environments; expect breaking changes relative to v1.0.7 (minimum PHP is now
8.3, minimum SimpleSAMLphp is now 2.5.2, and handleLoginPass() was renamed).
Added
- The
sourcesoption is now wired through to the login page: the controller
passes asourceslist (id,label,userpass) to the template, which
renders one form per source.authsourcevalues not insourcesare
rejected. - Tests for the
Multiauthsinglepageauthentication source (constructor
validation, credential guard, session handling, logout error path).
Changed
- Require PHP >= 8.3 and SimpleSAMLphp >= 2.5.2.
Multiauthsinglepage::authenticate()now returnsnever, to match
saml:SPin SimpleSAMLphp 2.5.- Any
core:UserPassBasesource (e.g.sqlauth:SQL,core:AdminPassword)
is now authenticated on the single page, not justldap:Ldap. The
dispatch checksinstanceof UserPassBase;handleLoginPass()was renamed
tohandleUserPassLogin()and typed accordingly. handleUserPassLogin()usesLdapSinglePage::loginSinglePage()when
available and only falls back to reflection otherwise.- Replaced the deprecated
Request::get()(Symfony 7.4) with explicit
query-string / POST-body reads. - Single code style tool (
phpcswith the SimpleSAMLphp standard); dropped
php-cs-fixer. - Loosened the
simplesamlphp-module-ldapconstraint from2.5.2to
^2.5.2. - The test bootstrap defines
SIMPLESAMLPHP_TEST_NOEXITso redirect flows
can be exercised in tests. - Rewrote the README with a real configuration example.
Fixed
- The login template read
errorTitle/errorDesc, which the controller
never set, so errors were never shown; it now useserrorcode/
errorcodes/errorparams. handleUserPassLogin()(néehandleLoginPass()) no longer raises a
TypeErrorwhen the username or password is missing; it throws
Error\Error(WRONGUSERPASS)instead.- The full authentication state is no longer written to the debug log.
LICENSEwas an empty file; it now contains the GNU LGPL 2.1 text.- Moved the
SuccessAuthSourcetest fixture out ofsrc/intotests/,
fixing its PSR-4 mapping.