toga-ai 1.0.816 → 1.0.818
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.
- package/knowledge/1.0/apps/store/INDEX.md +6 -0
- package/knowledge/1.0/apps/store/architecture.md +72 -0
- package/knowledge/1.0/apps/store/features/saml-sso-certificate-and-keys.md +188 -0
- package/knowledge/INDEX.md +1 -0
- package/knowledge/clients/prudential/INDEX.md +1 -0
- package/knowledge/clients/prudential/profile.md +13 -0
- package/knowledge/clients/prudential/workflows/store-saml-deploy-topology.md +157 -0
- package/knowledge/clients/rumcsi/profile.md +10 -2
- package/knowledge/registry.json +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# store (Store) — 1.0 knowledge
|
|
2
|
+
|
|
3
|
+
| Doc | Summary |
|
|
4
|
+
|-----|---------|
|
|
5
|
+
| [Store (1.0 Storefront / SAML ACS) Architecture](architecture.md) | `store` is a framework **1.0** (`App_`) storefront app. |
|
|
6
|
+
| [Store SAML SP Certificate & Private Keys (togahub.com)](features/saml-sso-certificate-and-keys.md) | How the `store` repo's SAML Service Provider credential — the `togahub.com` X.509 cert and its RSA private key — is stored, loaded and rotated. |
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Store (1.0 Storefront / SAML ACS) Architecture
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: store
|
|
5
|
+
project: Store
|
|
6
|
+
client: shared
|
|
7
|
+
type: architecture
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-09-15
|
|
10
|
+
owners: ["rgirish"]
|
|
11
|
+
files:
|
|
12
|
+
- store/_/app/framework.php
|
|
13
|
+
- store/config.production.ini
|
|
14
|
+
related:
|
|
15
|
+
- ../library/architecture.md
|
|
16
|
+
- ./features/saml-sso-certificate-and-keys.md
|
|
17
|
+
- ../../../clients/prudential/workflows/store-saml-deploy-topology.md
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Summary
|
|
21
|
+
|
|
22
|
+
`store` is a framework **1.0** (`App_`) storefront app. It also hosts the **SAML Assertion
|
|
23
|
+
Consumer Service (ACS)** for several clients on the `*.togahub.com` hostnames — the inbound
|
|
24
|
+
IdP assertion is decrypted **here**, not in the 2.0 `saml` gateway. SAML lives inline in
|
|
25
|
+
`store/_/app/framework.php` as a large `switch ($returnTo)` on the RelayState value, with one
|
|
26
|
+
inline `$settingsInfo` block per client and a `case 'meta' / case 'acs'` pair inside each.
|
|
27
|
+
|
|
28
|
+
The SP cert/key material lives in the sibling `library` repo under `library/ssl/toga/` and is
|
|
29
|
+
read from disk at request time via `__LIBROOT__`.
|
|
30
|
+
|
|
31
|
+
**Critical rules:** never paste private-key material into `framework.php` — read it from
|
|
32
|
+
`library/ssl/toga/*.key` with `file_get_contents`. The SAML ACS host and the storefront host for
|
|
33
|
+
a client can be **different EB environments**; check DNS before assuming a deploy target
|
|
34
|
+
(see the Prudential store SAML deploy-topology workflow). Certificate and private key must be
|
|
35
|
+
rotated **together** — the three inline SP blocks each carry an `x509cert` that has to match the
|
|
36
|
+
key file.
|
|
37
|
+
|
|
38
|
+
## SAML entry points
|
|
39
|
+
|
|
40
|
+
Routing is by the RelayState value (`$_POST['RelayState']`, read as `$returnTo`), not by path:
|
|
41
|
+
|
|
42
|
+
| Sub-route | Purpose |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `?meta` | SP metadata XML from `OneLogin_Saml2_Settings::getSPMetadata()` |
|
|
45
|
+
| `?acs` | Assertion Consumer Service — decrypts the inbound `SAMLResponse` |
|
|
46
|
+
|
|
47
|
+
Two SAML stacks are in play in the same file:
|
|
48
|
+
- **php-saml (`OneLogin_Saml2_*`)** — builds the SP settings + `?meta` metadata.
|
|
49
|
+
- **LightSAML + xmlseclibs** — does the actual `?acs` assertion decryption
|
|
50
|
+
(`decryptMultiAssertion`). See the SAML SP certificate & keys feature doc.
|
|
51
|
+
|
|
52
|
+
The RUMCSI branch (`rumcsi.togaview.agilantsolutions.com`) skips decryption entirely and parses
|
|
53
|
+
the raw assertion XML with `SimpleXMLElement` + XPath.
|
|
54
|
+
|
|
55
|
+
## Handoff to the storefront
|
|
56
|
+
|
|
57
|
+
After a successful assertion, the Prudential-style branches base64-encode a plain
|
|
58
|
+
`xid:first:last:email` string and redirect to `<returnTo>?hash=<base64>`. This is **not
|
|
59
|
+
encrypted and not signed** — unlike the 2.0 gateway's `?saml=` encrypted + uuid-validated
|
|
60
|
+
handoff. See the "Client_True migration (deferred)" section of the SAML SP certificate & keys
|
|
61
|
+
feature doc.
|
|
62
|
+
|
|
63
|
+
## Known issues
|
|
64
|
+
|
|
65
|
+
- `case 'meta'` sets the `Content-Type` header and `exit`s **without ever echoing
|
|
66
|
+
`$metadata`** — the `?meta` endpoint returns an empty body. Present in both `meta` blocks.
|
|
67
|
+
- `'debug' => true` is set on all three SAML `$settingsInfo` blocks, and a `debugVar()` call
|
|
68
|
+
dumps SAML attributes (XID, name, email) to output.
|
|
69
|
+
- `'strict'` is never set, so php-saml defaults it to `false` and skips condition, timestamp and
|
|
70
|
+
audience validation. Neither `wantAssertionsSigned` nor `wantMessagesSigned` is set.
|
|
71
|
+
- Prudential's SAML config is ~700 lines of inline `switch` in one file with no
|
|
72
|
+
`_Model_<Client>_ClientAuthentication` equivalent.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Store SAML SP Certificate & Private Keys (togahub.com)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: store
|
|
5
|
+
project: Store
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-09-15
|
|
10
|
+
owners: ["rgirish"]
|
|
11
|
+
files:
|
|
12
|
+
- store/_/app/framework.php
|
|
13
|
+
- library/ssl/toga/togahub_com_2027-03-31.crt
|
|
14
|
+
- library/ssl/toga/toga_private_key_2027-03-31.key
|
|
15
|
+
related:
|
|
16
|
+
- ../architecture.md
|
|
17
|
+
- ../../library/features/app-sso-initiation.md
|
|
18
|
+
- ../../../2.0/apps/saml/workflows/rotating-the-saml-sp-certificate.md
|
|
19
|
+
- ../../../2.0/standards/ssl-certificate-trust-model.md
|
|
20
|
+
- ../../../clients/prudential/workflows/store-saml-deploy-topology.md
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
|
|
25
|
+
How the `store` repo's SAML Service Provider credential — the `togahub.com` X.509 cert and its
|
|
26
|
+
RSA private key — is stored, loaded and rotated. `store` decrypts inbound IdP assertions itself
|
|
27
|
+
(LightSAML), so this credential is what makes Prudential/RUMCSI SSO work. It is **separate from**
|
|
28
|
+
the 2.0 `saml` gateway's SP credential — rotating one does not rotate the other. (As of
|
|
29
|
+
2026-09-15 the gateway's `/acs` loads its decrypt certs from AWS Secrets Manager, not from disk;
|
|
30
|
+
`store` still reads files. See the SP cert-rotation workflow.)
|
|
31
|
+
|
|
32
|
+
The cert and key files live in the sibling `library` repo at `library/ssl/toga/` and are read at
|
|
33
|
+
request time through `__LIBROOT__`.
|
|
34
|
+
|
|
35
|
+
## How it works
|
|
36
|
+
|
|
37
|
+
### Where the material lives (never paste values)
|
|
38
|
+
|
|
39
|
+
- **AWS Secrets Manager**, account **654654170868**, region **us-east-1**.
|
|
40
|
+
- Secret: **`toga/ssl/togahub_com-casigned-2027-03-31`**.
|
|
41
|
+
- JSON keys: `certificate`, `privateKey`, `certificateChain`, `passphrase`.
|
|
42
|
+
- On disk (deployed with the `library` repo):
|
|
43
|
+
- `library/ssl/toga/togahub_com_2027-03-31.crt` — active cert
|
|
44
|
+
- `library/ssl/toga/togahub_com_2027-03-31-chain.crt` — chain
|
|
45
|
+
- `library/ssl/toga/toga_private_key_2027-03-31.key` — active key, **stored decrypted**, mode `600`
|
|
46
|
+
- `library/ssl/toga/togahub_com_2026-02-27.crt` + `toga_private_key.key` — previous pair,
|
|
47
|
+
kept only as the rotation fallback
|
|
48
|
+
|
|
49
|
+
### Current certificate (rotated 2026-09-15)
|
|
50
|
+
|
|
51
|
+
| | Old | New |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| File | `togahub_com_2026-02-27.crt` | `togahub_com_2027-03-31.crt` |
|
|
54
|
+
| Issuer | DigiCert / Thawte | Amazon (ACM, `Amazon RSA 2048 M01`) |
|
|
55
|
+
| Validity | expired **2026-09-16** | **2026-09-15 → 2027-03-31** |
|
|
56
|
+
| SANs | 14 | **2** — `togahub.com`, `*.togahub.com` |
|
|
57
|
+
|
|
58
|
+
**The new cert covers only `togahub.com`.** The six other domains the old cert carried
|
|
59
|
+
(`togacommerce`, `togadesk`, `togaview`, `togasupply`, `togaretail`, `togaiq`, plus their
|
|
60
|
+
wildcards) are **not** on it — each of those needs its own ACM cert on its own listener.
|
|
61
|
+
|
|
62
|
+
### Dual-keypair decrypt (rotation overlap)
|
|
63
|
+
|
|
64
|
+
`case 'acs'` in `store/_/app/framework.php` builds a `$samlKeyPairs` array — **active keypair
|
|
65
|
+
first, previous keypair second** — then one `LightSaml\Credential\X509Credential` per readable
|
|
66
|
+
pair, and passes the whole list to
|
|
67
|
+
`$reader->decryptMultiAssertion($credentials, $decryptDeserializeContext)`.
|
|
68
|
+
|
|
69
|
+
LightSAML's `decryptMulti()` loops the credentials, swallows each individual failure and returns
|
|
70
|
+
on the first success, re-throwing only when all fail. So **no custom retry logic is needed** and
|
|
71
|
+
it fails closed. An IdP still encrypting to the old cert and one already on the new cert both
|
|
72
|
+
work during the overlap. Unreadable keypairs are skipped with `error_log`; an empty credential
|
|
73
|
+
list throws `RuntimeException`.
|
|
74
|
+
|
|
75
|
+
This mirrors the overlap the 2.0 `saml` gateway provides, though the gateway now does it with
|
|
76
|
+
a multi-cert list out of Secrets Manager rather than two files on disk — see the SP
|
|
77
|
+
cert-rotation workflow.
|
|
78
|
+
|
|
79
|
+
### Two ACS handlers, two SAML libraries — tell them apart from the stack trace
|
|
80
|
+
|
|
81
|
+
`store/_/app/framework.php` has **two** separate `case 'acs'` handlers that use **different SAML
|
|
82
|
+
libraries**. They are easy to confuse when reading a production stack trace, and they run on
|
|
83
|
+
**different servers**:
|
|
84
|
+
|
|
85
|
+
| Handler | Library | Host / EB environment |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| The `togahub` host block's `case 'acs'` (the `$samlKeyPairs` dual-keypair decrypt) | **LightSAML** (`decryptMultiAssertion`) | `prudential.togahub.com` → `prudential-store-prod` |
|
|
88
|
+
| The `prudential` host block's `case 'acs'` | **OneLogin_Saml2_Auth** (`isAuthenticated()`, `getNameId()`, `getAttribute('givenname'/'surname'/'emailaddress')`) | `prudential.togacommerce.com` → `true-togacommerce-prod` |
|
|
89
|
+
|
|
90
|
+
**Diagnostic rule:** a trace with `LightSaml\Model\Assertion\*` frames is the **togahub** block
|
|
91
|
+
(`prudential-store-prod`). A trace with `OneLogin` frames is the **prudential** block
|
|
92
|
+
(`true-togacommerce-prod`). This is how a production decrypt error gets pinned to the right
|
|
93
|
+
server — and the two are deployed by different pipeline actions, so fixing the wrong one changes
|
|
94
|
+
nothing. See the Prudential store SAML deploy-topology workflow.
|
|
95
|
+
|
|
96
|
+
### Private key loading
|
|
97
|
+
|
|
98
|
+
The three inline `$settingsInfo` SP blocks read the key from disk:
|
|
99
|
+
|
|
100
|
+
```php
|
|
101
|
+
'privateKey' => trim(file_get_contents(__LIBROOT__ . '/ssl/toga/toga_private_key_2027-03-31.key')),
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The key file must be **decrypted on disk** because `framework.php` calls
|
|
105
|
+
`KeyHelper::createPrivateKey($path, '', true)` with an empty password — an encrypted PEM will not
|
|
106
|
+
load.
|
|
107
|
+
|
|
108
|
+
**Deploy model:** the `ssl/**/*.key` ignore rule was deliberately removed from
|
|
109
|
+
`library/.gitignore` so the key ships with the repo. That is the team's current model for this
|
|
110
|
+
key; it is a record of what we do, not a recommendation.
|
|
111
|
+
|
|
112
|
+
## Gotchas
|
|
113
|
+
|
|
114
|
+
- **PEM newlines are stored as SPACES in Secrets Manager.** The `certificate` / `privateKey`
|
|
115
|
+
values in `toga/ssl/togahub_com-casigned-2027-03-31` have their line breaks replaced by spaces.
|
|
116
|
+
`openssl` rejects the value straight out of the secret. Re-wrap the base64 body at 64 chars
|
|
117
|
+
before writing it to disk.
|
|
118
|
+
- **The date in a secret name is the EXPIRY date, not the issue date.** The secret
|
|
119
|
+
`toga/ssl/togahub_com-casigned-2026-09-16` is **not** a newer cert — it holds the cert that was
|
|
120
|
+
already expiring. Read the dates out of the cert itself, never off the secret name.
|
|
121
|
+
- **Rotate the cert and the key together.** Before 2026-09-15 the three SP blocks had the raw
|
|
122
|
+
private key pasted inline as a base64 string, and the `x509cert` values had been rotated while
|
|
123
|
+
those inline keys had not — cert and key no longer matched, which would have broken SSO on the
|
|
124
|
+
next deploy. Keys are now read from a file, so they cannot drift apart silently.
|
|
125
|
+
- **Don't assume where the ACS runs.** The host that terminates `?acs` for a client may be a
|
|
126
|
+
different EB environment from the storefront. See the Prudential store SAML deploy-topology
|
|
127
|
+
workflow before deploying a cert change.
|
|
128
|
+
- **A decrypt stack trace CANNOT tell you how many keys were tried.** In
|
|
129
|
+
`library/LightSaml/Model/Assertion/EncryptedElementReader.php`, `decryptMulti()` returns
|
|
130
|
+
`$this->decrypt($key)` from *inside* the `foreach`, and re-throws `$lastException` after the
|
|
131
|
+
loop. The re-thrown exception keeps the stack from where it was first thrown, so the captured
|
|
132
|
+
trace looks **identical** whether one key was tried or several all failed. Seeing
|
|
133
|
+
`decryptMultiAssertion` in a trace therefore does **not** prove the dual-keypair code is
|
|
134
|
+
deployed — the old single-key code called the same method with a one-item array. To tell them
|
|
135
|
+
apart, check the deployed EB `Deployment.VersionLabel`, or look for the new code's distinct log
|
|
136
|
+
line `SAML keypair not readable, skipping:`.
|
|
137
|
+
- **A mismatched cert/key pair fails with an OAEP padding error, not a clear message.** The
|
|
138
|
+
symptom is `Failure decrypting Data (openssl private) -
|
|
139
|
+
RSA_padding_check_PKCS1_OAEP_mgf1: oaep decoding error` (also seen as
|
|
140
|
+
`RSA_EAY_PRIVATE_DECRYPT: padding check failed`) thrown out of the LightSAML
|
|
141
|
+
`EncryptedElementReader`. Confirm a suspected mismatch by comparing the **modulus** of the cert
|
|
142
|
+
and the key with `openssl x509 -noout -modulus` / `openssl rsa -noout -modulus` — identical
|
|
143
|
+
modulus means the pair matches. Compare the **committed git blobs**, not just the local working
|
|
144
|
+
files, or you will verify a pair that was never deployed.
|
|
145
|
+
|
|
146
|
+
## Client_True migration (deferred 2026-09-15)
|
|
147
|
+
|
|
148
|
+
Moving Prudential SAML onto the `Client_True` pattern (config `[saml]` section +
|
|
149
|
+
`Core.ClientAuthentications` / `ClientAuthentications_Sso` rows + `App_Sso` + a
|
|
150
|
+
`_Model_<Client>_ClientAuthentication`) was reviewed and **deferred to its own ticket** — the cert
|
|
151
|
+
expired the next day and the migration is multi-day work.
|
|
152
|
+
|
|
153
|
+
Reference implementation to copy when it is picked up: `tools/config.production.ini` `[saml]`
|
|
154
|
+
section, `library/app/sso.php` (`App_Sso::initiate`), `tools/mvc/sso/initiate/get.php`,
|
|
155
|
+
`tools/mvc/sso/get.php`.
|
|
156
|
+
|
|
157
|
+
What the migration must handle:
|
|
158
|
+
- Prudential today has ~700 lines of inline `switch` keyed on `$returnTo`, with certs pasted into
|
|
159
|
+
PHP, and no `_Model_Prudential_ClientAuthentication`.
|
|
160
|
+
- Its handoff is a plain-base64 `?hash=` of `xid:first:last:email` — unencrypted and forgeable —
|
|
161
|
+
versus the encrypted, uuid-validated `?saml=` handoff `Client_True` uses.
|
|
162
|
+
- Prudential **auto-creates users on first login**. `Client_True`'s `getAuthenticatedSsoUser()`
|
|
163
|
+
does not, so that behavior must be written in or SSO logins will start failing for new users.
|
|
164
|
+
|
|
165
|
+
## Open security items (not fixed 2026-09-15)
|
|
166
|
+
|
|
167
|
+
- The old private key is still in git history — `library` commits `6addc58f7` and `29d55bb97`,
|
|
168
|
+
plus the `store` `framework.php` history. Tracked as a separate compromised-credential ticket.
|
|
169
|
+
- `'debug' => true`, missing `'strict'`, and the attribute-dumping `debugVar()` — see the store
|
|
170
|
+
architecture doc's Known issues.
|
|
171
|
+
|
|
172
|
+
## Change history
|
|
173
|
+
- 2026-09-15 — Documented that `framework.php` has two `case 'acs'` handlers on two different
|
|
174
|
+
SAML libraries (LightSAML for `togahub` vs OneLogin for `prudential`) running on two different
|
|
175
|
+
EB environments, and how to read a stack trace to tell which one failed. Recorded that a
|
|
176
|
+
LightSAML `decryptMulti()` trace cannot reveal how many keys were tried (re-thrown exception
|
|
177
|
+
keeps the original stack), so `decryptMultiAssertion` in a trace does not prove the
|
|
178
|
+
dual-keypair build is deployed — check the EB VersionLabel or the
|
|
179
|
+
`SAML keypair not readable, skipping:` log line. Added the OAEP-padding-error signature of a
|
|
180
|
+
mismatched cert/key pair and the openssl-modulus check against committed blobs. (rgirish)
|
|
181
|
+
- 2026-09-15 — Rotated the `togahub.com` SP cert to the ACM-issued `togahub_com_2027-03-31.crt`
|
|
182
|
+
and added a dual-keypair fallback in `?acs` so both the old and new certs decrypt during the
|
|
183
|
+
overlap (`decryptMultiAssertion`). Removed three hardcoded RSA private-key blobs from
|
|
184
|
+
`store/_/app/framework.php` and replaced them with `file_get_contents` on
|
|
185
|
+
`library/ssl/toga/toga_private_key_2027-03-31.key`; chmod 600 the old world-readable key.
|
|
186
|
+
Recorded the Secrets Manager location, the space-instead-of-newline PEM gotcha, and that the
|
|
187
|
+
new cert carries only 2 SANs. Deferred the `Client_True` SAML migration. Commit `3839e49a`.
|
|
188
|
+
(rgirish)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -14,6 +14,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
14
14
|
- **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
|
|
15
15
|
- **test** (Test) — 16 doc(s) → [1.0/apps/test/INDEX.md](1.0/apps/test/INDEX.md)
|
|
16
16
|
- **toga** (TOGa) — 3 doc(s) → [1.0/apps/toga/INDEX.md](1.0/apps/toga/INDEX.md)
|
|
17
|
+
- **store** (Store) — 2 doc(s) → [1.0/apps/store/INDEX.md](1.0/apps/store/INDEX.md)
|
|
17
18
|
- **tools** (Tools) — 18 doc(s) → [1.0/apps/tools/INDEX.md](1.0/apps/tools/INDEX.md)
|
|
18
19
|
|
|
19
20
|
## 2.0 framework
|
|
@@ -16,3 +16,4 @@
|
|
|
16
16
|
| [Prudential Financial](profile.md) | 2.0 | Prudential is a TOGA client whose device-fulfillment flow is driven by **Dell** via the Dell API (`Client_Prudential.Apis.id = 2`). |
|
|
17
17
|
| [Prudential: Dell ASN failed POST backfill replay](workflows/dell-asn-backfill-replay.md) | 2.0 | When Dell ASN POSTs fail in bulk (e.g. |
|
|
18
18
|
| [Prudential — HTTP/2 disabled on the Commerce ALB (proxy workaround) + open re-enable action](workflows/http2-alb-workaround.md) | 2.0 | Prudential users hit **`ERR_HTTP2_PROTOCOL_ERROR`** in Chrome and Edge (both Chromium) loading `https://prudential.togacommerce.com`, while the site worked fine |
|
|
19
|
+
| [Prudential store/SAML Deploy Topology & the Wedged-Agent Deploy Timeout](workflows/store-saml-deploy-topology.md) | 1.0 | Where Prudential's SAML ACS actually runs versus where its storefront runs — they are **two different Elastic Beanstalk environments**, and the CodePipeline act |
|
|
@@ -12,6 +12,7 @@ apps:
|
|
|
12
12
|
- toga2-commerce
|
|
13
13
|
- toga25-supply
|
|
14
14
|
- saml
|
|
15
|
+
- store
|
|
15
16
|
project: _Underscore
|
|
16
17
|
client: prudential
|
|
17
18
|
type: profile
|
|
@@ -33,6 +34,7 @@ related:
|
|
|
33
34
|
- features/supply-orders-csv-export.md
|
|
34
35
|
- features/order-email-pdf-attachments.md
|
|
35
36
|
- features/itemclasses-device-tier-data.md
|
|
37
|
+
- workflows/store-saml-deploy-topology.md
|
|
36
38
|
---
|
|
37
39
|
|
|
38
40
|
## Summary
|
|
@@ -80,6 +82,13 @@ The order-created cron branches on this id; the shipped/delivered crons branch o
|
|
|
80
82
|
breaks HTTP/2, causing `ERR_HTTP2_PROTOCOL_ERROR` in Chrome/Edge. HTTP/2 is currently disabled
|
|
81
83
|
globally on the `true-togacommerce-prod` ALB as a workaround — **open action to re-enable once
|
|
82
84
|
their IT fixes the proxy.** See workflows/http2-alb-workaround.md.
|
|
85
|
+
- **SAML ACS and the storefront are DIFFERENT EB environments.** `prudential.togahub.com` (where
|
|
86
|
+
the SAML assertion is decrypted, in the 1.0 `store` repo) points at `prudential-store-prod`
|
|
87
|
+
(us-west-2, account 502614707982), deployed by the pipeline action **`PrudentialStore`**.
|
|
88
|
+
`prudential.togacommerce.com` (the storefront) points at `true-togacommerce-prod` and is
|
|
89
|
+
deployed by **`TrueProductionDeployment`** — so the action named "PrudentialStore" does *not*
|
|
90
|
+
deploy the storefront. `rumcsi.togahub.com` shares `prudential-store-prod`. See
|
|
91
|
+
workflows/store-saml-deploy-topology.md.
|
|
83
92
|
- Dell will not change their payload shape — see the Dell ASN units interceptor feature doc for the
|
|
84
93
|
PRE/POST translation that keeps their feed working after the tracking-number bridge migration.
|
|
85
94
|
- Service request region is resolved from `Customers.name` string (`'USA'`/`'India'`/`'Ireland'`).
|
|
@@ -117,6 +126,10 @@ The order-created cron branches on this id; the shipped/delivered crons branch o
|
|
|
117
126
|
linking, the "null null" contact-export incident + dedup/backfill remediation.
|
|
118
127
|
- features/order-email-pdf-attachments.md — which PDF guide is attached to which customer
|
|
119
128
|
order email at which stage, the S3 asset list, and the four crons that send them.
|
|
129
|
+
- workflows/store-saml-deploy-topology.md — where Prudential's SAML ACS actually runs vs
|
|
130
|
+
the storefront, the split AWS accounts, and the wedged-agent EB deploy timeout.
|
|
131
|
+
- ../../1.0/apps/store/features/saml-sso-certificate-and-keys.md — the togahub.com SP cert/key
|
|
132
|
+
that decrypts Prudential's assertions.
|
|
120
133
|
- features/supply-orders-csv-export.md — the Prudential-only Sales Orders CSV export in TOGa 2.5
|
|
121
134
|
Supply (`toga25-supply`): its two queries, why contacts join `SalesOrders.contactId` (not
|
|
122
135
|
`Units.contactId`, NULL until Dell assigns the asset), and the `ServiceRequests_Units` fan-out.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Prudential store/SAML Deploy Topology & the Wedged-Agent Deploy Timeout
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
project: Store
|
|
5
|
+
client: prudential
|
|
6
|
+
type: workflow
|
|
7
|
+
status: active
|
|
8
|
+
updated: 2026-09-15
|
|
9
|
+
owners: ["rgirish"]
|
|
10
|
+
files:
|
|
11
|
+
- store/_/app/framework.php
|
|
12
|
+
related:
|
|
13
|
+
- ../profile.md
|
|
14
|
+
- ../../../1.0/apps/store/architecture.md
|
|
15
|
+
- ../../../1.0/apps/store/features/saml-sso-certificate-and-keys.md
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
Where Prudential's SAML ACS actually runs versus where its storefront runs — they are **two
|
|
21
|
+
different Elastic Beanstalk environments**, and the CodePipeline action names point at the
|
|
22
|
+
opposite one from what you would guess. Read this before deploying anything SAML-related for
|
|
23
|
+
Prudential. It also records the EB deploy failure mode we hit on 2026-09-15 (a wedged command
|
|
24
|
+
agent that times out after 14 minutes while the environment still shows Green).
|
|
25
|
+
|
|
26
|
+
## The full login flow — the two legs run on two different servers
|
|
27
|
+
|
|
28
|
+
The outbound (first) leg does **not** hop through togahub. It redirects the browser straight to
|
|
29
|
+
Microsoft Entra:
|
|
30
|
+
|
|
31
|
+
1. User hits `prudential.togacommerce.com` (**`true-togacommerce-prod`**). The `prudential`
|
|
32
|
+
host block in `store/_/app/framework.php` fires when the session host is `prudential`, the app
|
|
33
|
+
is not in test mode, and the session has no `accountId`.
|
|
34
|
+
2. With no recognized `?ssoCommand`, it falls to the `default:` case, which calls
|
|
35
|
+
`$auth->login($originUrl)` on `OneLogin_Saml2_Auth`.
|
|
36
|
+
3. That redirects to Prudential's Entra tenant:
|
|
37
|
+
`https://login.microsoftonline.com/d8fde2f5-9392-4260-8a03-0ad01f4746e9/saml2`.
|
|
38
|
+
4. The SP block advertises entityId `https://prudential.togahub.com/?meta` and ACS
|
|
39
|
+
`https://prudential.togahub.com/?acs` — so **Entra POSTs the response to togahub**, i.e. the
|
|
40
|
+
inbound leg lands on **`prudential-store-prod`**, a different EB environment.
|
|
41
|
+
5. `prudential-store-prod` decrypts the assertion (LightSAML), then redirects back to
|
|
42
|
+
`prudential.togacommerce.com/?hash=<base64 of xid:first:last:email>`.
|
|
43
|
+
|
|
44
|
+
**Why this matters:** the outbound and inbound legs are different servers with different
|
|
45
|
+
deploys. A deploy that succeeds on one does **not** fix the other. Decrypt/cert changes belong on
|
|
46
|
+
`prudential-store-prod`.
|
|
47
|
+
|
|
48
|
+
## The routing — the pipeline action names are misleading
|
|
49
|
+
|
|
50
|
+
| Hostname | CNAME → EB environment | Deployed by pipeline action |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `prudential.togacommerce.com` (storefront) | `true-togacommerce-prod.us-west-2` | **`TrueProductionDeployment`** |
|
|
53
|
+
| `prudential.togahub.com` (**SAML ACS**) | `prudential-store-prod.us-west-2` | **`PrudentialStore`** |
|
|
54
|
+
| `rumcsi.togahub.com` | `prudential-store-prod.us-west-2` | `PrudentialStore` |
|
|
55
|
+
|
|
56
|
+
**The action named `PrudentialStore` does NOT deploy the Prudential storefront.**
|
|
57
|
+
`TrueProductionDeployment` does. `PrudentialStore` deploys the host that decrypts the SAML
|
|
58
|
+
assertion — so **cert / decrypt code changes must land on `prudential-store-prod`.**
|
|
59
|
+
|
|
60
|
+
`rumcsi.togahub.com` shares that same environment, so a bad SAML deploy there breaks RUMCSI
|
|
61
|
+
login too.
|
|
62
|
+
|
|
63
|
+
### Accounts and regions (they are split)
|
|
64
|
+
|
|
65
|
+
- **Pipeline:** `Store-Production`, AWS account **502614707982**, region **us-west-2**.
|
|
66
|
+
Not `us-east-1`, and not account `654654170868` where most other TOGA pipelines live.
|
|
67
|
+
- **Route53** zones for `togacommerce.com` and `togahub.com` are in account **654654170868**,
|
|
68
|
+
while the EB environments they point at are in **502614707982**. You need both accounts to
|
|
69
|
+
trace a hostname end-to-end.
|
|
70
|
+
|
|
71
|
+
## Failure mode — 14-minute command timeout with a Green environment
|
|
72
|
+
|
|
73
|
+
Symptoms in the EB event log:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
The following instances have not responded in the allowed command timeout time
|
|
77
|
+
Command execution completed on all instances. Summary: [Successful: 0, TimedOut: 1]
|
|
78
|
+
Failed to deploy application.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The environment still reports **Green / Ok**, which is misleading — the deploy never ran, but
|
|
82
|
+
the old version is still serving traffic fine.
|
|
83
|
+
|
|
84
|
+
### How to confirm it is a wedged command agent
|
|
85
|
+
|
|
86
|
+
1. Check what the instance actually thinks it is running:
|
|
87
|
+
```
|
|
88
|
+
aws elasticbeanstalk describe-instances-health --attribute-names All \
|
|
89
|
+
--environment-name prudential-store-prod --region us-west-2
|
|
90
|
+
```
|
|
91
|
+
A wedged agent shows `Deployment.VersionLabel` still on the **old** build with
|
|
92
|
+
`Deployment.Status: Deployed`, while `CPU Idle` is ~99% and load average ~0.0. That means the
|
|
93
|
+
instance never picked up the deploy command at all — it is not busy, it is deaf.
|
|
94
|
+
2. Check whether SSM sees the instance:
|
|
95
|
+
```
|
|
96
|
+
aws ssm describe-instance-information --region us-west-2
|
|
97
|
+
```
|
|
98
|
+
An **empty** result for the instance confirms the agent is not reporting.
|
|
99
|
+
|
|
100
|
+
Observed 2026-09-15: `prudential-store-prod` on `i-07ae1b81ee48df938` (t3.micro, running since
|
|
101
|
+
2026-07-17), stuck on an Aug 13 build. `spglobal-store-prod` failed identically on
|
|
102
|
+
`i-04a6a50cffd37457e` — that environment has **no instances and no DNS pointing at it**.
|
|
103
|
+
|
|
104
|
+
## What you need to do
|
|
105
|
+
|
|
106
|
+
1. Confirm the diagnosis with the two AWS commands above before touching anything.
|
|
107
|
+
2. Reboot the EC2 instance (EC2 console or `aws ec2 reboot-instances`).
|
|
108
|
+
3. Watch the EB event log for `Command is executing on all instances` — that means the EB command
|
|
109
|
+
channel is back.
|
|
110
|
+
4. Re-run the failed pipeline deploy.
|
|
111
|
+
5. If it times out again, do **not** reboot a second time. Use an EB **Instance refresh** /
|
|
112
|
+
instance replacement instead.
|
|
113
|
+
|
|
114
|
+
A reboot restored the EB command channel on 2026-09-15, but SSM still did not report after 3
|
|
115
|
+
minutes — EB working again is the signal to retry, not SSM.
|
|
116
|
+
|
|
117
|
+
## Incident 2026-09-15 — OAEP decrypt error caused by the stuck deploy
|
|
118
|
+
|
|
119
|
+
Production Sentry showed, from the togahub (LightSAML) ACS handler:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Failure decrypting Data (openssl private) - RSA_padding_check_PKCS1_OAEP_mgf1: oaep decoding error
|
|
123
|
+
```
|
|
124
|
+
(also seen as `RSA_EAY_PRIVATE_DECRYPT: padding check failed`)
|
|
125
|
+
|
|
126
|
+
**Root cause: not a bad key — a deploy that never landed.** `prudential-store-prod` was still
|
|
127
|
+
running the pre-rotation code (commit `275d16a9`, an Aug 13 build) because its deploy kept timing
|
|
128
|
+
out with the wedged-agent failure above. That old code loaded a **mismatched cert/key pair**: the
|
|
129
|
+
`togahub_com_2025-03-25.crt` cert with `toga_private_key.key`, which belongs to the 2026-02-27
|
|
130
|
+
cert. Confirmed by comparing the two openssl moduli — they differ. The new dual-keypair fallback
|
|
131
|
+
fixes this, but it was not on the box.
|
|
132
|
+
|
|
133
|
+
The `library` repo was verified **clean and not the cause**: all three new files committed and
|
|
134
|
+
pushed on `_production`, both keypairs (2027 active and 2026-02-27 fallback) verified as matching
|
|
135
|
+
pairs against the **committed git blobs** (not just local files), both keys unencrypted (no
|
|
136
|
+
`Proc-Type` / `DEK-Info`), and both loading via the exact call the code makes —
|
|
137
|
+
`openssl_pkey_get_private($pem, "")`.
|
|
138
|
+
|
|
139
|
+
**Lesson:** when a SAML decrypt error appears right after a cert rotation, check *what build is
|
|
140
|
+
actually deployed* before you suspect the key material. Verify against committed blobs, and note
|
|
141
|
+
that the stack trace alone cannot tell you which build is running (see the cert & keys feature
|
|
142
|
+
doc's gotcha on `decryptMulti`).
|
|
143
|
+
|
|
144
|
+
## Change history
|
|
145
|
+
- 2026-09-15 — Traced the outbound SAML leg: `prudential.togacommerce.com` redirects the browser
|
|
146
|
+
straight to Prudential's Entra tenant (no togahub hop), and Entra POSTs back to
|
|
147
|
+
`prudential.togahub.com/?acs` on a different EB environment — so a deploy to one leg does not
|
|
148
|
+
fix the other. Recorded the OAEP decrypt incident: the error came from `prudential-store-prod`
|
|
149
|
+
still serving the pre-rotation Aug 13 build (`275d16a9`) with a mismatched cert/key pair,
|
|
150
|
+
because its deploy kept timing out; the `library` repo was verified clean against committed
|
|
151
|
+
git blobs. (rgirish)
|
|
152
|
+
- 2026-09-15 — Created while rotating the `togahub.com` SAML cert. Documented that
|
|
153
|
+
`prudential.togahub.com` (SAML ACS) and `prudential.togacommerce.com` (storefront) are separate
|
|
154
|
+
EB environments with swapped-sounding pipeline action names, the split AWS accounts/regions,
|
|
155
|
+
and the wedged-command-agent deploy timeout with its `describe-instances-health` /
|
|
156
|
+
`describe-instance-information` diagnosis and reboot-then-instance-refresh remediation.
|
|
157
|
+
(rgirish)
|
|
@@ -5,12 +5,13 @@ apps:
|
|
|
5
5
|
- togadesk
|
|
6
6
|
- togaview
|
|
7
7
|
- library
|
|
8
|
+
- store
|
|
8
9
|
project: TOGa Desk
|
|
9
10
|
client: rumcsi
|
|
10
11
|
type: profile
|
|
11
12
|
status: active
|
|
12
|
-
updated: 2026-
|
|
13
|
-
owners: ["mhammontree"]
|
|
13
|
+
updated: 2026-09-15
|
|
14
|
+
owners: ["mhammontree", "rgirish"]
|
|
14
15
|
files: []
|
|
15
16
|
related:
|
|
16
17
|
- ../../1.0/apps/togadesk/features/per-client-host-restriction.md
|
|
@@ -19,6 +20,7 @@ related:
|
|
|
19
20
|
- ../../1.0/apps/togadesk/features/email-to-ticket-intake.md
|
|
20
21
|
- ../../1.0/apps/togadesk/architecture.md
|
|
21
22
|
- ../../1.0/apps/togaview/architecture.md
|
|
23
|
+
- ../../1.0/apps/store/features/saml-sso-certificate-and-keys.md
|
|
22
24
|
---
|
|
23
25
|
|
|
24
26
|
## Summary
|
|
@@ -124,6 +126,12 @@ hardcoded to `clientId = 2`; no RUMC row has `adPeopleId`/`ldap_user`), and
|
|
|
124
126
|
- **No SAML auto-provisioning.** Unlike towfoundation and newcenturyholdingsllc, the rumcsi
|
|
125
127
|
branch only `SELECT`s `people`; it never creates them. That is precisely why the bulk load was
|
|
126
128
|
necessary.
|
|
129
|
+
- **`rumcsi.togahub.com` runs on the `prudential-store-prod` EB environment** (1.0 `store` repo,
|
|
130
|
+
us-west-2, account 502614707982) — the same host as Prudential's SAML ACS. A bad SAML/cert
|
|
131
|
+
deploy there breaks RUMCSI login too. RUMCSI's ACS branch skips assertion decryption (raw
|
|
132
|
+
`SimpleXMLElement` + XPath), so the SP cert rotation does not affect it directly. See
|
|
133
|
+
../../1.0/apps/store/features/saml-sso-certificate-and-keys.md and
|
|
134
|
+
../prudential/workflows/store-saml-deploy-topology.md.
|
|
127
135
|
|
|
128
136
|
## Change history
|
|
129
137
|
|
package/knowledge/registry.json
CHANGED
package/package.json
CHANGED