45 lines
3.0 KiB
Markdown
45 lines
3.0 KiB
Markdown
# Architecture
|
|
|
|
The portal is a Linux FastAPI app. It is the **enrollment client**. Apple devices only download a finished, signed configuration profile.
|
|
|
|
## Flow
|
|
|
|
1. **OIDC.** The browser is redirected to a generic OpenID Provider (Keycloak, Okta, Authentik, Entra ID, …). Authorization code + PKCE. A small user dict (`sub`, `username`, `email`, `name`) is stored in a signed session cookie. Access tokens are not kept.
|
|
2. **LDAP.** Using the username claim (default `email`, then `preferred_username`), the portal binds as a service account and searches Active Directory. It reads `objectSid`, `userPrincipalName`, and `displayName`. An optional group gate uses `LDAP_MATCHING_RULE_IN_CHAIN` (nested membership).
|
|
3. **Key + CSR (memory only).** On **Download**, not at login, the portal generates RSA-2048 (configurable), and a CSR:
|
|
- Subject `CN=<UPN>`
|
|
- SAN otherName `1.3.6.1.4.1.311.20.2.3` = UPN
|
|
- SAN URI `tag:microsoft.com,2022-09-14:sid:<SID>` (Microsoft strong mapping / KB5014754)
|
|
4. **certsrv.** NTLM POST to `/certsrv/certfnsh.asp` with `CertificateTemplate:<name>`. On issued, GET `/certsrv/certnew.cer?ReqID=&Enc=b64`. Pending or denied is an error; this portal does not wait for manager approval.
|
|
5. **Identity PKCS#12.** Private key + issued cert (+ optional CA) encrypted with a one-time password. Not written to disk.
|
|
6. **Unsigned plist.** A `com.apple.security.pkcs12` payload holds the identity P12 and that password. Optional CA payload if `PROFILE_CA_CERT_PATH` is set.
|
|
7. **Sign.** The completed plist is wrapped in attached CMS (not detached), equivalent to `openssl smime -sign -nodetach -outform der`, using the **profile-signing** PKCS#12.
|
|
8. **HTTPS download.** `Content-Type: application/x-apple-aspen-config`.
|
|
|
|
The CA database requester is the **portal NTLM account**. The **user** is bound by SAN (UPN + SID URI), not by Windows impersonation. OIDC does not yield a Kerberos ticket for the end user, so there is no Enrollment Agent / on-behalf-of in this version.
|
|
|
|
## Two PKCS#12 files
|
|
|
|
| File | Lifetime | Role |
|
|
| --- | --- | --- |
|
|
| Identity P12 | One download, RAM only | Embedded in the profile as `com.apple.security.pkcs12`. User cert + private key. |
|
|
| Profile-signing P12 | Long-lived file on the server | CMS-signs the `.mobileconfig`. Must already be trusted on the device. |
|
|
|
|
Do not reuse the signing P12 as a user identity, and do not save identity P12s.
|
|
|
|
## Why the phone never talks to the CA
|
|
|
|
SCEP/NDES would have the device generate a key and speak SCEP to NDES. This portal instead returns the cert and key inside the profile. After install, nothing on the phone needs `certsrv` or NDES reachability.
|
|
|
|
## Code map
|
|
|
|
| Module | Responsibility |
|
|
| --- | --- |
|
|
| `auth_oidc.py` | OIDC client registration, claim → username |
|
|
| `directory.py` | LDAPS, `objectSid` decode, group gate |
|
|
| `enrollment.py` | RSA key, CSR SAN, PKCS#12 export |
|
|
| `certsrv.py` | NTLM submit/fetch, HTML disposition parser |
|
|
| `profile.py` | Unsigned plist + CMS sign |
|
|
| `issue.py` | Orchestrates one download |
|
|
| `app.py` | HTTP routes, session, templates |
|