toga-ai 1.0.528 → 1.0.529
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -108,9 +108,15 @@ divergent shapes (read `emailAddress` with `email` fallback).
|
|
|
108
108
|
|
|
109
109
|
**SAML** (rumcsi, towfoundation, newcenturyholdingsllc) is handled in `framework.php`
|
|
110
110
|
(`meta`/`acs`/`sls`); newcenturyholdingsllc and towfoundation **auto-create `people` rows** for
|
|
111
|
-
unknown SAML users. rumcsi additionally accepts a
|
|
112
|
-
account-takeover path that
|
|
113
|
-
|
|
111
|
+
unknown SAML users. rumcsi additionally accepts a `?hash=<base64 email>` auto-login — **an unauthenticated
|
|
112
|
+
account-takeover path that is also, per the routing evidence, RUMC's live production SSO login**:
|
|
113
|
+
the block holds the only rumcsi route to `/enterprise_dashboard` (where a real production SSO
|
|
114
|
+
login lands), and togaview has no `?saml=` handling, so the 2.0 SAML gateway is not involved.
|
|
115
|
+
Only rumcsi's `acs` handler fails to populate the session (newcenturyholdingsllc `:819` and
|
|
116
|
+
towfoundation `:1180` do), which is why only rumcsi has a magic link. **Deleting it breaks RUMC
|
|
117
|
+
login into an IdP redirect loop** — sign the token or complete the `acs` handler instead, in
|
|
118
|
+
coordination with the external link generator. A cold-login capture to confirm the inbound
|
|
119
|
+
`?hash=` hop is still outstanding (see [login flows](features/login-flows.md)).
|
|
114
120
|
|
|
115
121
|
## Dashboards
|
|
116
122
|
Five dashboards, one per audience/business model, each delegating to a client override or the
|
|
@@ -72,26 +72,65 @@ lookup silently found nothing. Removed, and `email LIKE '…'` changed to `=` in
|
|
|
72
72
|
|
|
73
73
|
## Gotchas / known issues
|
|
74
74
|
|
|
75
|
-
### OPEN SECURITY ITEM — rumcsi `?hash=`
|
|
75
|
+
### OPEN SECURITY ITEM — rumcsi `?hash=` is the LIVE production SSO login (do not delete it)
|
|
76
76
|
`_/app/framework.php` authenticates a rumcsi user on nothing but
|
|
77
77
|
`base64_decode(urldecode($_GET['hash']))` matching an active `people` row for the rumcsi
|
|
78
78
|
clientid — **no password, signature, nonce, or expiry** — then populates ~18 session keys and
|
|
79
79
|
redirects to `/enterprise_dashboard`. Anyone who can guess a RUMC user's email can log in as
|
|
80
80
|
them.
|
|
81
81
|
|
|
82
|
-
It was removed during TRUE-80671 and then **deliberately reverted
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
It was removed during TRUE-80671 and then **deliberately reverted**. Routing evidence gathered
|
|
83
|
+
afterwards shows this is not a dormant legacy backdoor — it is **how RUMC actually logs in**:
|
|
84
|
+
|
|
85
|
+
- Jonathan performed a real production SSO login and was returned to
|
|
86
|
+
`https://rumcsi.togaview.agilantsolutions.com/enterprise_dashboard`.
|
|
87
|
+
- Inside the rumcsi block, **`framework.php:278` is the ONLY path to `/enterprise_dashboard`** —
|
|
88
|
+
and it sits **inside the hash block**, behind `if ($rumcsiUser)`. The SAML `acs` handler instead
|
|
89
|
+
does `App_MVC::routeTo('/')`. The only other RUMC route to that page is
|
|
90
|
+
`mvc/login/post.php:511`, which is the *password* login. **Landing on `/enterprise_dashboard`
|
|
91
|
+
after an SSO login is the hash block's signature.**
|
|
92
|
+
- The absence of `?hash=` in the final URL is **expected, not exculpatory**: the block consumes
|
|
93
|
+
the parameter and issues a fresh redirect, so the query string is gone from the address bar.
|
|
94
|
+
- **The modern alternative is ruled out.** The 2.0 SAML gateway (repo `saml`,
|
|
95
|
+
`Controller/Index.php:456-460`) hands off with `?saml=<base64 JSON whose client and user UUIDs
|
|
96
|
+
are encrypted via `_String::encryptWithKey`>` — the correct mechanism, which `tools` uses.
|
|
97
|
+
togaview has **zero** handling for `?saml=` (no `$_GET['saml']` anywhere). RUMC does not come
|
|
98
|
+
through that gateway, and there is no hidden session-population path.
|
|
99
|
+
- **Had the deletion shipped, RUMC SSO would have broken outright:** authenticate at the IdP →
|
|
100
|
+
`acs` → `/` → no `contactId` → bounced back to the IdP. A redirect loop, not a login. The
|
|
101
|
+
revert was correct.
|
|
102
|
+
|
|
103
|
+
**Still open — who generates the link.** Nothing in togaview/togadesk/library builds a `hash=`
|
|
104
|
+
URL, so the generator is external (likely RUMC's IdP-initiated flow or their own portal).
|
|
105
|
+
**Confirming test:** a **cold** SSO login in a private window with DevTools → Network →
|
|
106
|
+
*Preserve log*, capturing the full redirect chain and checking whether the hop **into** togaview
|
|
107
|
+
carries `?hash=`. Jonathan's test may not have exercised a cold login at all — with a live session
|
|
108
|
+
cookie the `!array_key_exists('contactId', $_SESSION)` gate is skipped entirely and
|
|
109
|
+
`/enterprise_dashboard` is simply where he already was.
|
|
110
|
+
|
|
111
|
+
**Fix shape — a coordinated change, never a deletion.** Two options, both requiring coordination
|
|
112
|
+
with whoever generates the link:
|
|
113
|
+
- **(a) Keep the handoff but sign it.** Replace the unsigned base64 email with an HMAC-signed
|
|
114
|
+
token via `App_String::encrypt`/`decrypt` (`library/app/string.php`). Smallest change; kills
|
|
115
|
+
guessability.
|
|
116
|
+
- **(b) Complete the rumcsi `acs` handler** so it builds the session itself, then retire the
|
|
117
|
+
handoff.
|
|
118
|
+
|
|
119
|
+
⚠ **Do NOT delete the block first, under either option.**
|
|
120
|
+
|
|
121
|
+
### Why rumcsi is the only one of the three SAML clients with a magic-link login
|
|
122
|
+
The real lesson is the contrast between the three `acs` handlers in `_/app/framework.php`:
|
|
123
|
+
|
|
124
|
+
| Client | `acs` handler | Sets `contactId` / session? |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| newcenturyholdingsllc | `:819` | **Yes** — completes the login |
|
|
127
|
+
| towfoundation | `:1180` | **Yes** — completes the login |
|
|
128
|
+
| rumcsi | `:399-417` | **No** — only `routeTo('/')` (since 9e7d306, "phase one … make sure redirect works") |
|
|
129
|
+
|
|
130
|
+
rumcsi's handler was never finished, and the `?hash=` block is what filled the gap. When adding a
|
|
131
|
+
SAML client, the `acs` handler **must** populate the session — an unfinished one invites exactly
|
|
132
|
+
this kind of unsigned side door.
|
|
133
|
+
|
|
95
134
|
- Note the surviving SAML branch is gated on `!inTestMode()`, so **test mode leaves rumcsi with
|
|
96
135
|
no login path at all**.
|
|
97
136
|
|
|
@@ -106,6 +145,14 @@ generated outside our codebase.
|
|
|
106
145
|
- The flows are order-dependent: a contact matching an earlier flow never reaches later ones.
|
|
107
146
|
|
|
108
147
|
## Change history
|
|
148
|
+
- 2026-08-05 (later, TRUE-80671) — **Upgraded the rumcsi `?hash=` finding from "may be" to
|
|
149
|
+
evidenced:** `framework.php:278` inside the hash block is the only rumcsi route to
|
|
150
|
+
`/enterprise_dashboard`, where a real production SSO login landed; togaview has no `?saml=`
|
|
151
|
+
handling at all, so the 2.0 SAML gateway is ruled out; deleting the block would have produced an
|
|
152
|
+
IdP redirect loop, not a login. Recorded the three-way `acs` handler contrast (newcentury :819 /
|
|
153
|
+
towfoundation :1180 populate the session, rumcsi :399-417 never did), both fix shapes (sign the
|
|
154
|
+
token with `App_String::encrypt`, or finish `acs`), and the outstanding cold-login DevTools test.
|
|
155
|
+
(mhammontree)
|
|
109
156
|
- 2026-08-05 (TRUE-80671, uncommitted) — Fixed the unguarded `$user_name[1]` session-name build
|
|
110
157
|
that **locked mononym / shared-mailbox users out entirely** (4 sites); removed
|
|
111
158
|
`sqlProtect(sqlEscape())` and switched email lookups to `=`; recorded the rumcsi `?hash=`
|
|
@@ -35,13 +35,19 @@ Richmond University Medical Center (**RUMCSI**) is a framework **1.0** client se
|
|
|
35
35
|
- **TOGa View SAML.** `togaview/_/app/framework.php` has a RUMCSI-specific host branch that selects
|
|
36
36
|
branding (`$_SESSION['stylePath']`) and the SAML login path — an unregistered togaview hostname
|
|
37
37
|
falls through to default branding and skips SAML.
|
|
38
|
-
- **⚠ Portal login
|
|
39
|
-
handler never populates `$_SESSION
|
|
40
|
-
`_/app/framework.php` block that authenticates on nothing but a base64-encoded email in
|
|
41
|
-
`?hash
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
- **⚠ Portal login IS an unauthenticated `?hash=` magic link — and it is load-bearing.** The
|
|
39
|
+
rumcsi SAML `acs` handler never populates `$_SESSION`; the only working rumcsi session builder
|
|
40
|
+
is a `_/app/framework.php` block that authenticates on nothing but a base64-encoded email in
|
|
41
|
+
`?hash=` (no signature, nonce, or expiry). The routing evidence is firm: `framework.php:278`,
|
|
42
|
+
inside that block, is the **only** rumcsi route to `/enterprise_dashboard`, which is exactly
|
|
43
|
+
where a real production SSO login landed
|
|
44
|
+
(`rumcsi.togaview.agilantsolutions.com/enterprise_dashboard`), and togaview has **no** `?saml=`
|
|
45
|
+
handling, so the 2.0 SAML gateway is not involved. **Deleting the block breaks RUMC SSO into an
|
|
46
|
+
IdP redirect loop** — it must be signed or replaced by a completed `acs` handler, in
|
|
47
|
+
coordination with whoever generates the link (the generator is external to our repos and still
|
|
48
|
+
unidentified). Full analysis, both fix shapes, and the outstanding cold-login confirmation test:
|
|
49
|
+
[TOGa View login
|
|
50
|
+
flows](../../1.0/apps/togaview/features/login-flows.md#open-security-item--rumcsi-hash-is-the-live-production-sso-login-do-not-delete-it).
|
|
45
51
|
Note also that the SAML branch is gated on `!inTestMode()`, so **test mode leaves rumcsi with
|
|
46
52
|
no login path**.
|
|
47
53
|
- **Hardcoded client-ID branching.** RUMCSI appears in TOGa Desk's hardcoded client-ID branching
|
|
@@ -49,6 +55,9 @@ Richmond University Medical Center (**RUMCSI**) is a framework **1.0** client se
|
|
|
49
55
|
|
|
50
56
|
## Change history
|
|
51
57
|
|
|
58
|
+
- 2026-08-05 (later) — routing evidence confirms the `?hash=` path is the live SSO login (only
|
|
59
|
+
route to `/enterprise_dashboard`; no `?saml=` handling in togaview); deleting it would break
|
|
60
|
+
RUMC login into a redirect loop. (mhammontree)
|
|
52
61
|
- 2026-08-05 — recorded the `?hash=` portal-login path as an open takeover risk left in place
|
|
53
62
|
pending SSO confirmation, and the test-mode no-login-path gap (TRUE-80671). (mhammontree)
|
|
54
63
|
- 2026-08-04 — Client profile created during the TRUE-80139 read-only review of the RUMCSI branded
|
package/package.json
CHANGED