Skip to content

Commit 1d30033

Browse files
committed
fix(auth): restore include-injected enableSession after cross-engine testing
Both placements were tested against Lucee, macOS RustCFML, and the Linux RustCFML build: the declared-method form fails the RustCFML mixin copy on both platforms; the include-injected form passes Lucee and macOS RustCFML. Restore the include (auth.cfm + ladder) as the best-known cross-engine state. Signed-off-by: Peter Amiri <peter@alurium.com>
1 parent de2cd20 commit 1d30033

2 files changed

Lines changed: 82 additions & 68 deletions

File tree

vendor/wheels/Global.cfc

Lines changed: 18 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,24 @@ component output="false" {
531531
}
532532
}
533533

534+
// Auth wiring facade (enableSession) — same mapping-absolute include
535+
// ladder as the other global files above.
536+
try {
537+
include "/wheels/global/auth.cfm";
538+
} catch (any e) {
539+
if (!$isMissingMappedInclude(e)) {
540+
rethrow;
541+
}
542+
try {
543+
include "global/auth.cfm";
544+
} catch (any e2) {
545+
if (!$isMissingMappedInclude(e2)) {
546+
rethrow;
547+
}
548+
include "../vendor/wheels/global/auth.cfm";
549+
}
550+
}
551+
534552
// User-defined global functions
535553
try {
536554
include "/app/global/functions.cfm";
@@ -564,72 +582,4 @@ component output="false" {
564582
// "The key [...] was not found in the struct. Valid keys are ([VARKEY])".
565583
$promoteIncludedGlobalsToThis();
566584

567-
/**
568-
* One-line session-auth wiring for `config/services.cfm`.
569-
*
570-
* The auth subsystem ships complete (Authenticator strategy registry +
571-
* SessionStrategy with login/logout/currentUser and SID rotation) but
572-
* wiring it by hand spans two files: map the singletons here, then
573-
* register the strategy in `app/events/onapplicationstart.cfm`.
574-
* `enableSession()` collapses that into one idempotent call:
575-
*
576-
* // config/services.cfm
577-
* enableSession(sessionKey = "wheels.auth");
578-
*
579-
* The DI container is available in services.cfm (it is NOT available in
580-
* config/app.cfm — services.cfm is loaded after the container is built).
581-
* Manual wiring keeps working; this helper is the convenience path.
582-
*
583-
* Declared as a real method (not an include-injected global): the
584-
* include-injection + promotion path proved unreliable on RustCFML's
585-
* Linux build, where the function silently went missing from the Global
586-
* instance.
587-
*/
588-
public any function enableSession(string sessionKey = "wheels.auth", any onLogin = "", any onLogout = "") {
589-
// Guard: enableSession() belongs in config/services.cfm, where the
590-
// container exists. Fail with a pointer rather than an opaque scope
591-
// error when it is called from a context without one.
592-
try {
593-
var di = injector();
594-
} catch (any e) {
595-
Throw(
596-
type = "Wheels.Injector",
597-
message = "enableSession() requires the DI container — call it from config/services.cfm (loaded at application start).",
598-
detail = e.message
599-
);
600-
}
601-
if (!isObject(di)) {
602-
Throw(
603-
type = "Wheels.Injector",
604-
message = "enableSession() requires the DI container — call it from config/services.cfm (loaded at application start)."
605-
);
606-
}
607-
608-
// Map the singletons only when they aren't already mapped, so manual
609-
// wiring and repeat calls stay idempotent.
610-
if (!di.containsInstance("authenticator")) {
611-
di.map("authenticator").to("wheels.auth.Authenticator").asSingleton();
612-
}
613-
if (!di.containsInstance("sessionStrategy")) {
614-
di.map("sessionStrategy").to("wheels.auth.SessionStrategy").asSingleton();
615-
}
616-
617-
// Resolve with explicit initArguments: the singleton cache honors the
618-
// first resolution's arguments, so a custom sessionKey/callbacks stick
619-
// even if something else resolved the strategy first with defaults.
620-
var authenticator = service("authenticator");
621-
var strategy = di.getInstance(
622-
"sessionStrategy",
623-
{ sessionKey: arguments.sessionKey, onLogin: arguments.onLogin, onLogout: arguments.onLogout }
624-
);
625-
626-
// Register once. Repeat calls (dev reloads, double-includes) must not
627-
// stack duplicate registrations.
628-
if (!authenticator.hasStrategy("session")) {
629-
authenticator.registerStrategy(name = "session", strategy = strategy);
630-
}
631-
632-
return strategy;
633-
}
634-
635585
}

vendor/wheels/global/auth.cfm

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<cfscript>
2+
/**
3+
* One-line session-auth wiring for `config/services.cfm`.
4+
*
5+
* The auth subsystem ships complete (Authenticator strategy registry +
6+
* SessionStrategy with login/logout/currentUser and SID rotation) but
7+
* wiring it by hand spans two files: map the singletons here, then
8+
* register the strategy in `app/events/onapplicationstart.cfm`.
9+
* `enableSession()` collapses that into one idempotent call:
10+
*
11+
* // config/services.cfm
12+
* enableSession(sessionKey = "wheels.auth");
13+
*
14+
* The DI container is available in services.cfm (it is NOT available in
15+
* config/app.cfm — services.cfm is loaded after the container is built).
16+
* Manual wiring keeps working; this helper is the convenience path.
17+
*/
18+
public any function enableSession(string sessionKey = "wheels.auth", any onLogin = "", any onLogout = "") {
19+
// Guard: enableSession() belongs in config/services.cfm, where the
20+
// container exists. Fail with a pointer rather than an opaque scope
21+
// error when it is called from a context without one.
22+
try {
23+
var di = injector();
24+
} catch (any e) {
25+
Throw(
26+
type = "Wheels.Injector",
27+
message = "enableSession() requires the DI container — call it from config/services.cfm (loaded at application start).",
28+
detail = e.message
29+
);
30+
}
31+
if (!isObject(di)) {
32+
Throw(
33+
type = "Wheels.Injector",
34+
message = "enableSession() requires the DI container — call it from config/services.cfm (loaded at application start)."
35+
);
36+
}
37+
38+
// Map the singletons only when they aren't already mapped, so manual
39+
// wiring and repeat calls stay idempotent.
40+
if (!di.containsInstance("authenticator")) {
41+
di.map("authenticator").to("wheels.auth.Authenticator").asSingleton();
42+
}
43+
if (!di.containsInstance("sessionStrategy")) {
44+
di.map("sessionStrategy").to("wheels.auth.SessionStrategy").asSingleton();
45+
}
46+
47+
// Resolve with explicit initArguments: the singleton cache honors the
48+
// first resolution's arguments, so a custom sessionKey/callbacks stick
49+
// even if something else resolved the strategy first with defaults.
50+
var authenticator = service("authenticator");
51+
var strategy = di.getInstance(
52+
"sessionStrategy",
53+
{ sessionKey: arguments.sessionKey, onLogin: arguments.onLogin, onLogout: arguments.onLogout }
54+
);
55+
56+
// Register once. Repeat calls (dev reloads, double-includes) must not
57+
// stack duplicate registrations.
58+
if (!authenticator.hasStrategy("session")) {
59+
authenticator.registerStrategy(name = "session", strategy = strategy);
60+
}
61+
62+
return strategy;
63+
}
64+
</cfscript>

0 commit comments

Comments
 (0)