toga-ai 1.0.670 → 1.0.671
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.
|
@@ -6,3 +6,4 @@
|
|
|
6
6
|
| [SAML Downstream Integration Contract](features/downstream-integration-contract.md) | The contract a **downstream TOGa app** implements to authenticate users through the SAML gateway (`saml.togahub.com`). | saml/Controller/Index.php, _underscore/Model/Core/ClientAuthentication.php, _underscore/Model/True/ClientAuthentication.php |
|
|
7
7
|
| [Rate SAML User Provisioning](features/rate-user-provisioning.md) | When a Rate user authenticates via SSO, `_Model_Rate_ClientAuthentication::getAuthenticatedSsoUser()` is called by the saml gateway. | _underscore/Model/Rate/ClientAuthentication.php, _underscore/Model/Rate/User.php, _underscore/Model/Rate/Customer.php, _underscore/Model/Rate/Contact.php |
|
|
8
8
|
| [Onboarding a New SSO Client with Just-In-Time User Provisioning](workflows/onboarding-a-new-sso-client.md) | The repeatable procedure for adding a new client to the 2.0 `saml` gateway when that client's users do **not** pre-exist in our database and must be created on | saml/Controller/Index.php, _underscore/Model/Core/ClientAuthentication.php, _underscore/Model/Rate/ClientAuthentication.php, _underscore/Database.php |
|
|
9
|
+
| [Rotating the SAML SP Certificate](workflows/rotating-the-saml-sp-certificate.md) | The repeatable procedure for replacing the TOGa **SAML Service Provider (SP) credential** — the X.509 cert + private key at `_underscore/Assets/ssl/togahub_com. | _underscore/Assets/ssl/togahub_com.crt, _underscore/Assets/ssl/togahub_private_key.key, _underscore/Model/Core/ClientAuthentication.php, saml/Controller/Index.php |
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Rotating the SAML SP Certificate
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: saml
|
|
5
|
+
project: SAML SSO Gateway
|
|
6
|
+
client: shared
|
|
7
|
+
type: workflow
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-27
|
|
10
|
+
owners: ["jcardinal"]
|
|
11
|
+
files:
|
|
12
|
+
- _underscore/Assets/ssl/togahub_com.crt
|
|
13
|
+
- _underscore/Assets/ssl/togahub_private_key.key
|
|
14
|
+
- _underscore/Model/Core/ClientAuthentication.php
|
|
15
|
+
- saml/Controller/Index.php
|
|
16
|
+
related:
|
|
17
|
+
- 2.0/apps/saml/architecture.md
|
|
18
|
+
- 2.0/apps/saml/workflows/onboarding-a-new-sso-client.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
|
|
23
|
+
The repeatable procedure for replacing the TOGa **SAML Service Provider (SP) credential** — the
|
|
24
|
+
X.509 cert + private key at `_underscore/Assets/ssl/togahub_com.crt` and
|
|
25
|
+
`_underscore/Assets/ssl/togahub_private_key.key`. This credential is the SP's own identity, used
|
|
26
|
+
to **sign outgoing AuthnRequests** and to **decrypt inbound assertions**. It is a bilateral,
|
|
27
|
+
partner-pinned trust artifact, **not** the TLS cert that terminates browser HTTPS. There was no
|
|
28
|
+
rotation runbook before this (git shows two prior undocumented swaps); this closes that gap.
|
|
29
|
+
|
|
30
|
+
For *why* a self-signed, long-lived cert is the correct choice here (rather than a public-CA TLS
|
|
31
|
+
cert), see the SSL certificate trust-model strategy standard.
|
|
32
|
+
|
|
33
|
+
## How the SP credential is used
|
|
34
|
+
|
|
35
|
+
- **Private key — signs outgoing SP AuthnRequests.** `_Model_Core_ClientAuthentication`
|
|
36
|
+
(`_underscore/Model/Core/ClientAuthentication.php`) points its `PATH_TO_PRIVATE_KEY` constant
|
|
37
|
+
at `_underscore/Assets/ssl/togahub_private_key.key` and signs with XMLSecLibs `RSA_SHA256`
|
|
38
|
+
(around lines 11 / 95 / 107).
|
|
39
|
+
- **Public cert — published in SP metadata and used to decrypt assertions.** The `saml` repo's
|
|
40
|
+
`Controller/Index.php` uses the cert for assertion decryption; the `/meta` route publishes it
|
|
41
|
+
in SP metadata via `file_get_contents` read fresh on each request (no server-side cache).
|
|
42
|
+
- **IdPs cache metadata up to 7 days** (`cacheDuration PT604800S`), so a cert change is not
|
|
43
|
+
guaranteed to be picked up by every IdP immediately after deploy.
|
|
44
|
+
|
|
45
|
+
## Current credential (as of 2026-08-27, staged — cutover pending)
|
|
46
|
+
|
|
47
|
+
A dedicated **self-signed** replacement was generated to decouple the SP credential from the
|
|
48
|
+
short-lived DigiCert/Thawte TLS wildcard that had been reused as the SP cert (see Background):
|
|
49
|
+
|
|
50
|
+
- Self-signed X.509, RSA 2048, SHA-256.
|
|
51
|
+
- Subject/Issuer: `C=US, ST=Illinois, L=Naperville, O=TOGA Technology, Inc., CN=togahub.com`
|
|
52
|
+
(reflects the new company name TOGA Technology, Inc. / Naperville, IL — formerly Agilant
|
|
53
|
+
Solutions, Inc.). CN only, **no SANs** — SANs are meaningless for bilateral SAML/AS2 trust.
|
|
54
|
+
- Validity: **2026-08-27 → 2036-08-27** (10 years). Capped at 10y because RSA 2048 is
|
|
55
|
+
NIST-assured only to ~2030; a longer term would call for RSA 4096, and client compatibility
|
|
56
|
+
with 4096 is unconfirmed.
|
|
57
|
+
- SHA-256 fingerprint:
|
|
58
|
+
`0E:1E:9E:11:35:B9:74:79:6F:07:2B:1F:E7:05:B8:B6:E9:07:00:0B:9E:A2:36:94:04:F6:AC:65:AC:B0:03:78`
|
|
59
|
+
|
|
60
|
+
### Where the material lives (never paste the key)
|
|
61
|
+
|
|
62
|
+
- **AWS Secrets Manager**, account **654654170868**, region **us-east-1**.
|
|
63
|
+
- Secret name: **`toga/ssl/togahub_com-selfsigned-2036`**.
|
|
64
|
+
- ARN: `arn:aws:secretsmanager:us-east-1:654654170868:secret:toga/ssl/togahub_com-selfsigned-2036-S2r3SR`.
|
|
65
|
+
- JSON keys: `{certificate, privateKey}`. Retrieve the private key from here at cutover — it is
|
|
66
|
+
**not** stored anywhere else and must never be committed or pasted into chat/docs.
|
|
67
|
+
- The public cert only was staged locally at `C:\TEMP\toga-ssl-2026\togahub_com.crt`; the local
|
|
68
|
+
private key was deleted.
|
|
69
|
+
|
|
70
|
+
## Cutover procedure
|
|
71
|
+
|
|
72
|
+
1. **PRE-CUTOVER SAFETY CHECK — confirm this cert is not serving live TLS.** Before replacing a
|
|
73
|
+
real CA cert with a self-signed one, verify the `.crt`/`.key` at `_underscore/Assets/ssl/` is
|
|
74
|
+
**not** also terminating browser/API TLS anywhere (check the `saml` repo + its EB/Apache
|
|
75
|
+
config). TLS is normally ACM-terminated at the ALB, so this repo file should only be the
|
|
76
|
+
SAML/AS2 credential — but verify against the checked-out `saml` repo first.
|
|
77
|
+
2. **Distribute the new public cert to every pinning partner** (SAML IdPs, AS2 partners, any
|
|
78
|
+
PunchOut buyer that pins our leaf) and let them import it. Include the SHA-256 fingerprint
|
|
79
|
+
above as the verification line.
|
|
80
|
+
3. **Coordinate a cutover date/time** with those partners.
|
|
81
|
+
4. **Replace both files in `_underscore` on the `_production` branch** — via a feature branch +
|
|
82
|
+
PR, **never a direct commit to `_production`**. No code change is needed: the path constants
|
|
83
|
+
already point at these filenames.
|
|
84
|
+
5. **Redeploy `saml` after the `_underscore` merge.** `saml` pulls `_underscore` from
|
|
85
|
+
`_production` at EB build time (`.ebextensions/git.php` + prebuild hook), so a saml-only
|
|
86
|
+
deploy will **not** pick up the new cert. Deploy target: `saml-production` EB env, us-east-1,
|
|
87
|
+
DNS `saml.togahub.com`.
|
|
88
|
+
6. **Deploy the cert+key to the other bilateral services** that use the same SP credential —
|
|
89
|
+
AS2 (AWS Transfer Family) and any other pinned endpoint — importing both cert and key.
|
|
90
|
+
|
|
91
|
+
## Background — why the change
|
|
92
|
+
|
|
93
|
+
The old `_underscore/Assets/ssl/togahub_com.crt` was a **reused DigiCert/Thawte multi-domain
|
|
94
|
+
wildcard TLS cert** (issuer "Thawte TLS RSA CA G1"; SANs for togahub.com, togacommerce.com,
|
|
95
|
+
togadesk.com, togaretail.com, togasupply.com, togaview.com, togaiq.com plus `*.` of each; RSA
|
|
96
|
+
2048; validity Mar 2 2026 → Sep 16 2026, ~6.5 months). Reusing a short-lived public-CA TLS cert
|
|
97
|
+
as the SAML SP credential accidentally coupled SAML to a ~6-month renewal treadmill and forced
|
|
98
|
+
every pinning partner to reinstall on each renewal. The dedicated self-signed 10-year cert
|
|
99
|
+
**decouples the SP credential from TLS renewals** — that is the whole point of the change.
|
|
100
|
+
|
|
101
|
+
## Change history
|
|
102
|
+
- 2026-08-27 — Created while replacing the SAML SP credential. Documented the SP cert's dual use
|
|
103
|
+
(signing AuthnRequests / decrypting assertions), the new self-signed 10-year cert identity and
|
|
104
|
+
its AWS Secrets Manager location, the pre-cutover TLS-usage safety check, and the
|
|
105
|
+
`_underscore`-then-`saml` cutover ordering. Discovered the prior cert was a reused short-lived
|
|
106
|
+
DigiCert wildcard TLS cert, which is the reason for the switch. Cutover itself still pending.
|
|
107
|
+
(jcardinal)
|
|
108
|
+
</content>
|
|
109
|
+
</invoke>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SSL Certificate Trust-Model Strategy
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
project: _Underscore
|
|
5
|
+
client: shared
|
|
6
|
+
type: standard
|
|
7
|
+
status: active
|
|
8
|
+
updated: 2026-08-27
|
|
9
|
+
owners: [jcardinal]
|
|
10
|
+
files: []
|
|
11
|
+
related:
|
|
12
|
+
- ../apps/saml/workflows/rotating-the-saml-sp-certificate.md
|
|
13
|
+
- ../apps/saml/architecture.md
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
Which kind of SSL/TLS certificate to use is decided by the **trust model** of the endpoint, not
|
|
19
|
+
by habit. Pick wrong and you land on a renewal treadmill; pick right and renewals become either
|
|
20
|
+
invisible or irrelevant. This standard is platform-wide (1.0, 2.0, standalone, and pure-AWS
|
|
21
|
+
infra). It was established while replacing the 2.0 SAML SP credential — see the
|
|
22
|
+
[SAML SP certificate rotation runbook](../apps/saml/workflows/rotating-the-saml-sp-certificate.md).
|
|
23
|
+
|
|
24
|
+
**Critical rule:** if a partner installs/pins OUR specific cert, use a **self-signed, long-lived**
|
|
25
|
+
cert. If AWS terminates the TLS for browsers/generic clients, use **ACM public, auto-renewing**.
|
|
26
|
+
Never reuse a public-CA TLS cert as a pinned bilateral credential.
|
|
27
|
+
|
|
28
|
+
## The decision
|
|
29
|
+
|
|
30
|
+
### 1. Bilateral / pinned trust → self-signed, long-lived
|
|
31
|
+
The partner installs and pins our specific certificate: SAML SP credential, AS2 (AWS Transfer
|
|
32
|
+
Family), PunchOut endpoints a buyer pins. Use a **self-signed** cert with a multi-year validity
|
|
33
|
+
(we generate 10-year). Distribute the public cert to the partner; import cert + key into the
|
|
34
|
+
service. Because trust is by pinning, no public CA is involved and validity can be long.
|
|
35
|
+
|
|
36
|
+
### 2. Standard HTTPS, AWS-terminated → ACM public, non-exportable, auto-renewing
|
|
37
|
+
Browsers / generic clients reach the endpoint through an ALB, CloudFront, or API Gateway that AWS
|
|
38
|
+
terminates. Use an **ACM public certificate** (non-exportable, auto-renewing). Distribute nothing;
|
|
39
|
+
renewal is invisible.
|
|
40
|
+
|
|
41
|
+
### 3. Standard HTTPS, NOT AWS-terminated → ACM exportable, or move behind an ALB
|
|
42
|
+
A server terminates its own TLS (e.g. the legacy Vision box). Options: an **ACM *exportable*
|
|
43
|
+
public cert** (a real 2025 AWS feature) — but still ~13-month validity, so you must redeploy on
|
|
44
|
+
every renewal — OR move the endpoint behind an ALB to get free auto-renew (option 2).
|
|
45
|
+
|
|
46
|
+
## Why long-lived ⇒ self-signed
|
|
47
|
+
|
|
48
|
+
**Every publicly-trusted cert, exportable or not, is capped at ~398 days** by the CA/Browser
|
|
49
|
+
Forum, dropping toward ~47 days by 2029. Only **self-signed / private-CA** certs can be
|
|
50
|
+
multi-year. So "long-lived AND distributable" necessarily means self-signed (or AWS Private CA at
|
|
51
|
+
~$400/mo — rejected here as overkill).
|
|
52
|
+
|
|
53
|
+
The pain of "shrinking public-cert validity" is really a **distribution problem**: automate
|
|
54
|
+
distribution via ACM and it disappears; a partner who pins the leaf breaks on every rotation.
|
|
55
|
+
That is exactly why bilateral, pinned credentials should be self-signed and long-lived — and why
|
|
56
|
+
reusing a short-lived public-CA TLS cert as a pinned SP/AS2 credential (as we accidentally did for
|
|
57
|
+
SAML) couples an otherwise stable credential to a ~6-month treadmill.
|
|
58
|
+
|
|
59
|
+
## Key sizing
|
|
60
|
+
|
|
61
|
+
Self-signed long-lived certs use RSA 2048 / SHA-256 with validity capped at ~10 years, because
|
|
62
|
+
RSA 2048 is NIST-assured only to ~2030. A longer term would want RSA 4096, but partner
|
|
63
|
+
compatibility with 4096 is often unconfirmed — verify before choosing it.
|
|
64
|
+
|
|
65
|
+
## Worked example — Vision / Canon cXML PunchOut (a split-trust endpoint)
|
|
66
|
+
|
|
67
|
+
The Vision cXML PunchOut endpoint (`vision.asisystem.com`, a separate domain/cert from
|
|
68
|
+
togahub.com) is a single cert serving **two legs with different trust models**, which is why its
|
|
69
|
+
renewals are painful:
|
|
70
|
+
|
|
71
|
+
- **Server-to-server cXML leg** — auth is a `<Credential>` **SharedSecret** (localVerifyIdentity),
|
|
72
|
+
not a client cert; our cert there is only the endpoint's TLS wrapper. The buyer reinstalling our
|
|
73
|
+
cert on every renewal indicates they **pin our leaf** — effectively bilateral trust → a
|
|
74
|
+
self-signed long-lived cert fits.
|
|
75
|
+
- **PunchOut portal StartPage** (`punchoutSetupResponseUrlPrefix`) is a real **browser** session →
|
|
76
|
+
needs a public-CA cert (option 2).
|
|
77
|
+
|
|
78
|
+
Bundling both on one cert is the root of the pain. The fix is to **split** them: ACM for the
|
|
79
|
+
browser portal, self-signed for the pinned cXML endpoint. StartPage host is per-identity
|
|
80
|
+
configurable, so the split is feasible. Canon is slated to move from Vision to TOGa Commerce (2.0,
|
|
81
|
+
already ALB+ACM), which auto-solves the browser leg.
|
|
82
|
+
</content>
|
package/knowledge/INDEX.md
CHANGED
|
@@ -23,7 +23,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
23
23
|
- **api2** (API) — 25 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
24
24
|
- **dbchanges2** (Database Changes) _(framework core)_ — 13 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
25
25
|
- **toga2-supply** (TOGa Supply) — 9 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
|
26
|
-
- **saml** (SAML SSO Gateway) —
|
|
26
|
+
- **saml** (SAML SSO Gateway) — 5 doc(s) → [2.0/apps/saml/INDEX.md](2.0/apps/saml/INDEX.md)
|
|
27
27
|
- **toga2-view** (TOGa View Frontend) — 12 doc(s) → [2.0/apps/toga2-view/INDEX.md](2.0/apps/toga2-view/INDEX.md)
|
|
28
28
|
- **toga2-hub** (TOGa Hub) — 2 doc(s) → [2.0/apps/toga2-hub/INDEX.md](2.0/apps/toga2-hub/INDEX.md)
|
|
29
29
|
- **talos** (TOGa IQ) — 7 doc(s) → [2.0/apps/talos/INDEX.md](2.0/apps/talos/INDEX.md)
|
package/package.json
CHANGED