Session work 2026-05-04: Grabb Leap calendar fix, Dataforth lobby phone VLAN, IMC printer + VPN
- Grabb & Durando: investigated and resolved Svetlana Larionova's Leap-to-M365 calendar OAuth consent issue (Graph-side report + session log). Syncro #32245. - Dataforth: lobby phone (ext 201) was offline due to D1-Server-Room port 1 being on the wrong VLAN; reconfigured to VLAN 100, phone re-provisioned and registered. Session log + PROJECT_STATE update. Syncro #32246. - Instrumental Music Center: Station 2 receipt printer reconnect + VPN install on Manda's machine. Syncro #32247. - Memory: generalized the Syncro blank-contact rule (was Cascades-only) and added the labor-type rule (never use "Prepaid project labor") per Winter's 2026-05-04 corrections. - Gitignored `.claude/tmp/` so per-session helper scripts don't sneak in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ Session manager was being developed for SAGE-SQL deployment — see `clients/dat
|
||||
|
||||
| Date | By | Change | Status |
|
||||
|------|-----|--------|--------|
|
||||
| 2026-05-04 | Howard | Lobby phone offline — D1-Server-Room port 1 reconfigured to VLAN 100. Syncro #32246. Phone registered after TFTP + SIP handshake. See `session-logs/2026-05-04-lobby-phone-vlan-fix.md`. | COMPLETE |
|
||||
| 2026-04-14 | Mike | Session log: follow-up work on datasheet pipeline | COMPLETE |
|
||||
| 2026-04-13 | Mike | Session log: pipeline verification | COMPLETE |
|
||||
| 2026-04-12 | Mike | SCMVAS/SCMHVAS pipeline deployed to production | DEPLOYED |
|
||||
|
||||
69
clients/dataforth/reports/2026-05-03-account-status-check.md
Normal file
69
clients/dataforth/reports/2026-05-03-account-status-check.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Dataforth — Account Status Check
|
||||
|
||||
**Date:** 2026-05-03 (UTC)
|
||||
**Tenant:** Dataforth Corporation (`dataforth.com`, `7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584`)
|
||||
**Tool:** ComputerGuru Security Investigator (App ID `bfbc12a4-f0dd-4e12-b06d-997e7271e10c`) — Graph read-only
|
||||
**Scope:** Status lookup only (enabled / licensed / last sign-in / object type). No remediation.
|
||||
**Operator:** Howard Enos
|
||||
|
||||
## Summary
|
||||
|
||||
- 1 of 4 addresses is an **active licensed user** (`jantar@`).
|
||||
- 1 of 4 is an **active distribution list** (`sales@`) routing to 3 employees.
|
||||
- 2 of 4 (`dchapman@`, `dhenderson@`) **do not exist** anywhere in the directory — no user, no group, no contact, no alias, not in the 30-day soft-delete recycle bin.
|
||||
|
||||
## Results
|
||||
|
||||
| Address | Object type | Enabled | Licensed | Last sign-in (interactive) | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| `sales@dataforth.com` | Mail-enabled distribution list ("Sales") | Active | n/a | n/a | Members: ltobey@, ghaubner@, tdean@ |
|
||||
| `jantar@dataforth.com` | User — Jacque Antar | Yes | 1 license | 2026-04-20 17:44 UTC (~13d ago) | Primary SMTP confirmed |
|
||||
| `dchapman@dataforth.com` | **Does not exist** | — | — | — | Not a user, group, contact, or alias; not in soft-delete |
|
||||
| `dhenderson@dataforth.com` | **Does not exist** | — | — | — | Not a user, group, contact, or alias; not in soft-delete |
|
||||
|
||||
## What "does not exist" means here
|
||||
|
||||
For `dchapman@` and `dhenderson@` we checked, against the live tenant:
|
||||
|
||||
1. `/users` filtered on `mail` and `proxyAddresses/any(p: p eq 'smtp:<addr>')` — 0 results. Rules out the address being a primary SMTP, a UPN, or a secondary alias on any mailbox.
|
||||
2. `/groups` same filter — 0 results. Rules out distribution lists and M365 groups.
|
||||
3. `/directory/deletedItems/microsoft.graph.user` — 0 results. The user object was not soft-deleted in the past 30 days (so not recoverable via the standard restore path).
|
||||
4. `/contacts` (beta, org-level mail contacts) — 0 results.
|
||||
|
||||
If mail to these addresses is bouncing now, that is consistent — the tenant has no recipient with that smtp address. If mail to these addresses was being delivered historically and we need to know when they were removed, that requires a unified audit log search (`auditLogs/directoryAudits` with `activityDisplayName eq 'Delete user'`) over a longer window — say so and I can run it.
|
||||
|
||||
## Per-address detail
|
||||
|
||||
### sales@dataforth.com — Distribution List
|
||||
- Group ID: `6dd5ec2b-c220-49bf-bd00-8d4d123914e7`
|
||||
- mail-enabled, security-disabled, classic DL (no `groupTypes`)
|
||||
- Proxy addresses: `SMTP:sales@dataforth.com`, `smtp:sales1@dataforthcom.onmicrosoft.com`
|
||||
- Members (3): Logan Tobey (`ltobey@`), Georg Haubner (`ghaubner@`), Theresa Dean (`tdean@`)
|
||||
|
||||
### jantar@dataforth.com — Jacque Antar
|
||||
- `accountEnabled`: true
|
||||
- 1 assigned license
|
||||
- Last interactive sign-in: 2026-04-20 17:44:45 UTC
|
||||
- Proxy addresses: `SMTP:jantar@dataforth.com`, `smtp:jantar@dataforthcom.onmicrosoft.com`
|
||||
|
||||
### dchapman@dataforth.com — not found
|
||||
- All four directory queries returned 0.
|
||||
|
||||
### dhenderson@dataforth.com — not found
|
||||
- All four directory queries returned 0.
|
||||
|
||||
## Data artifacts
|
||||
|
||||
Raw JSON in `/tmp/remediation-tool/7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584/account-active/`:
|
||||
- `sales@dataforth.com-users.json`, `sales@dataforth.com-groups.json`
|
||||
- `jantar@dataforth.com-users.json`, `jantar@dataforth.com-groups.json`
|
||||
- `dchapman@dataforth.com-users.json`, `dchapman@dataforth.com-groups.json`, `dchapman@dataforth.com-deleted.json`, `dchapman@dataforth.com-orgcontact.json`
|
||||
- `dhenderson@dataforth.com-users.json`, `dhenderson@dataforth.com-groups.json`, `dhenderson@dataforth.com-deleted.json`, `dhenderson@dataforth.com-orgcontact.json`
|
||||
|
||||
## Operational note
|
||||
|
||||
PyJWT + cryptography are not installed on HOWARD-HOME, so `get-token.sh` cert-auth (the new default) failed silently and the secret-auth fallback was used (`REMEDIATION_AUTH=secret`). Token issuance still works either way; cert-auth is preferred per the recent migration. Fix on this machine:
|
||||
|
||||
```bash
|
||||
py -m pip install PyJWT cryptography
|
||||
```
|
||||
139
clients/dataforth/reports/2026-05-03-jantar-account-check.md
Normal file
139
clients/dataforth/reports/2026-05-03-jantar-account-check.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Dataforth — Account & Mailbox Check: jantar@dataforth.com
|
||||
|
||||
**Date:** 2026-05-03 (UTC)
|
||||
**Tenant:** Dataforth Corporation (`dataforth.com`, `7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584`)
|
||||
**Subject:** Jacque Antar (UPN `jantar@dataforth.com`, object id `daa60027-be31-47a5-87af-d728499a9cc4`)
|
||||
**Trigger:** Email surfaced on a paid dark-web ID monitoring report.
|
||||
**Tool:** ComputerGuru Security Investigator (Graph read-only) — App ID `bfbc12a4-f0dd-4e12-b06d-997e7271e10c`
|
||||
**Operator:** Howard Enos
|
||||
**Scope:** Read-only. No remediation taken.
|
||||
|
||||
## Summary
|
||||
|
||||
- **MFA is ENABLED and IS being enforced.** Per-user MFA state = `enforced`. Last 30 days of sign-ins all show `MFA requirement satisfied by claim in the token`. Non-interactive sign-ins (Outlook, Teams, etc.) all report `authenticationRequirement: multiFactorAuthentication`.
|
||||
- **MFA method registered: SMS only** to `+1 520-245-6929`. No Authenticator app, no FIDO key. SMS is the weakest second factor (SIM-swap, SS7).
|
||||
- **Mailbox is clean of obvious breach indicators.** No suspicious inbox rules, no auto-forwarding visible in Graph, no foreign sign-ins, no mass-mail patterns in sent items, no flagged risk detections. Sent items match her accounting role.
|
||||
- **Posture gaps to fix (separate from breach response):**
|
||||
1. All 3 Conditional Access policies on this tenant are in **report-only** mode (`enabledForReportingButNotEnforced`) — including "Require MFA", "Block Legacy Authentication", and "Block Foreign Sign-Ins". The only thing enforcing MFA today is the deprecated per-user MFA toggle. Microsoft has been pushing tenants off per-user MFA for years.
|
||||
2. She has **OAuth grants for legacy email scopes** (IMAP, EWS, EAS) to "Apple Internet Accounts" and "eM Client". These are legitimate clients she uses, but they're protocol-level paths that the disabled "Block Legacy Auth" CA policy would close.
|
||||
3. **All 30d sign-ins originate from `67.206.163.122` (Salt Lake City, UT, CenturyLink residential).** Dataforth is Tucson. Either she's remote-working from SLC, uses a VPN exiting there, or this is persistent unauthorized access. **Confirm with her / Mike.** Same IP for 30 days = same workstation, not impersonation churn — but that workstation might or might not be hers.
|
||||
|
||||
## Target details
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| UPN | jantar@dataforth.com |
|
||||
| Object ID | daa60027-be31-47a5-87af-d728499a9cc4 |
|
||||
| Display name | Jacque Antar |
|
||||
| Account enabled | true |
|
||||
| Created | 2023-12-07 |
|
||||
| Last password change | **2026-03-09** (~55 days ago) |
|
||||
| Assigned licenses | 1 |
|
||||
|
||||
## MFA — enabled and enforced?
|
||||
|
||||
**Enabled: YES.** Per-user MFA legacy endpoint returned `perUserMfaState: enforced`. Registration report: `isMfaCapable: true, isMfaRegistered: true`.
|
||||
|
||||
**Enforced at sign-in: YES.** Evidence:
|
||||
|
||||
- All 8 interactive sign-ins (last 30d) ended successfully with `additionalDetails: "MFA requirement satisfied by claim in the token"`. That string only appears when Entra evaluated MFA and it was satisfied (either by fresh challenge or by an MFA-claim in the cached refresh token).
|
||||
- Non-interactive sign-ins (10 sampled from 2026-05-02 alone — Outlook, Edge, OfficeHome, WeveAgave, etc.) all show `authenticationRequirement: "multiFactorAuthentication"`.
|
||||
|
||||
**Methods registered:** `mobilePhone` only (SMS to `+1 520-245-6929`). `defaultMfaMethod: null`, `userPreferredMethodForSecondaryAuthentication: sms`.
|
||||
|
||||
**Caveat — what's enforcing the MFA:**
|
||||
- It is the legacy **per-user MFA "enforced"** flag, not Conditional Access. All 3 CA policies on this tenant are in `enabledForReportingButNotEnforced`:
|
||||
- `ACG - Require MFA for All Users` — report-only
|
||||
- `ACG - Block Legacy Authentication` — report-only
|
||||
- `ACG - Block Foreign Sign-Ins` — report-only
|
||||
- Security Defaults: disabled.
|
||||
- This works today, but Microsoft is sunsetting per-user MFA. The CA policies should be flipped to "On".
|
||||
|
||||
**Recommendation for Jacque specifically:**
|
||||
1. Have her register Microsoft Authenticator (push/TOTP) as her primary, demote SMS to fallback. Self-service: https://aka.ms/mfasetup
|
||||
2. Treat SMS-only as a known posture gap until Authenticator is added.
|
||||
|
||||
## Per-check findings
|
||||
|
||||
### 1. Inbox rules (Graph v1.0)
|
||||
- 1 rule, **disabled**. Moves messages whose header contains `X-Inky-Graymail: True` to a folder, then stops processing. This is a normal Inky-anti-phishing graymail filter. **Not suspicious.**
|
||||
|
||||
### 2. Mailbox settings (Graph)
|
||||
- Auto-reply: disabled. Time zone US Mountain. Locale en-US. **Nothing flagged.**
|
||||
|
||||
### 3. Exchange REST (hidden rules / mailbox permissions / SendAs / Get-Mailbox)
|
||||
- **NOT CHECKED.** Exchange admin endpoint returned **HTTP 401** for the Security Investigator SP on this tenant. The "Exchange Administrator" directory role is not assigned to that SP in Dataforth. This is a known gap from the per-tenant onboarding step.
|
||||
- To enable: a tenant Global Admin assigns the Exchange Administrator role to the `ComputerGuru Security Investigator` service principal in this tenant's Entra Roles blade (or run `bash .claude/skills/remediation-tool/scripts/onboard-tenant.sh dataforth.com` if cert auth works on this machine). Without it we can't see hidden inbox rules, delegates, SendAs, or the canonical `ForwardingAddress / ForwardingSmtpAddress / DeliverToMailboxAndForward` mailbox flags.
|
||||
- The Graph-side mailbox settings show no forwarding flag (`automaticRepliesSetting.status: disabled`) but Graph cannot see the Exchange-only forwarding fields.
|
||||
|
||||
### 4. OAuth consents + app role assignments
|
||||
- **2 user-consented OAuth grants** (both consented by her, scope = legacy email):
|
||||
| Resource | Client ID | Scopes |
|
||||
|---|---|---|
|
||||
| Office 365 Exchange Online | `85e650f8-5eec-4523-a9ef-fc1a031fb1d6` | `openid offline_access EAS.AccessAsUser.All` (Apple Internet Accounts — EAS) |
|
||||
| Office 365 Exchange Online | `25db1c08-f5a0-4f6c-bbdd-a738689b1587` | `IMAP.AccessAsUser.All EWS.AccessAsUser.All offline_access email openid` (eM Client) |
|
||||
- **2 app role assignments** under her account:
|
||||
- "Apple Internet Accounts" (assigned 2024-04-02)
|
||||
- "eM Client" (assigned 2024-08-26)
|
||||
- Both consistent with a Mac user running Apple Mail + a Windows/Mac user running eM Client. **Legitimate clients**, but they consume legacy auth scopes (IMAP / EWS / EAS) that bypass modern auth challenges. The disabled "Block Legacy Auth" CA policy would normally block these.
|
||||
|
||||
### 5. Authentication methods
|
||||
- 2 methods on record:
|
||||
- `passwordAuthenticationMethod` (last set 2026-03-09)
|
||||
- `phoneAuthenticationMethod` mobile, `+1 520-245-6929`
|
||||
- No `microsoftAuthenticatorAuthenticationMethod`, no FIDO2, no Windows Hello, no software OATH token.
|
||||
|
||||
### 6. Sign-ins (last 30 days, interactive)
|
||||
- 8 successful sign-ins. **All 8 from `67.206.163.122` (Salt Lake City, UT, CenturyLink-issued residential).** No failures, no foreign-geo, no legacy-auth client app types in this set.
|
||||
- App: mostly "Dime Client" (`a2760c41-63c9-42b5-8d58-bfa1fd9e2eb3` — Microsoft first-party app, used by some web client surfaces) + one "One Outlook Web".
|
||||
- Risk level: `hidden` (Identity Protection not licensed).
|
||||
- **Action:** confirm with Jacque or Mike that the SLC IP is hers (remote work, VPN, etc.). If not, treat as compromise.
|
||||
|
||||
### 7. Directory audits (last 30 days, target = jantar)
|
||||
- 5 events, all benign:
|
||||
- 3 × "Update user" by Microsoft Substrate Management (Microsoft system process, automatic profile maintenance)
|
||||
- 2 × "Add member to group" on 2026-04-06 by `dcenter@dataforth.com` (admin activity)
|
||||
- **No password resets, no auth-method changes, no role grants, no app consents by anyone other than her.**
|
||||
|
||||
### 8. Risky users / risk detections
|
||||
- **HTTP 403 Forbidden** — `"Your tenant is not licensed for this feature."` Identity Protection requires Entra ID P2; Dataforth's SKUs (O365 Business Premium, Business Standard, Exchange Standard) include P1 only. **Not checkable on this tenant.**
|
||||
|
||||
### 9. Sent items (last 25)
|
||||
- Normal accounting/AP work: Patricia at `times-biz.com` (external bookkeeper), AMoreno + sabreu at `crestins.com` (insurance broker), Paychex contacts (`nknippel@`, `cknoll@`), internal Dataforth (`Kellynwackerly@`, `tdean@`, `dcenter@`, `ghaubner@`, `ofest@`, `ltobey@`, `shipping@`), various vendor reply-thread subjects ("Sales Invoice", "Statement", "JE to correct AP issue", "Commissions", "ACH", "Bank", "PER1 and PIN1").
|
||||
- **No blast patterns, no unusual external recipients, no obvious phishing or BEC payloads.** Subject lines and recipient mix consistent with her finance role.
|
||||
|
||||
### 10. Deleted items (last 25 visible)
|
||||
- Only 3 items: 1 promotional email (`info-az-specialists.com@shared1.ccsend.com`), 2 self-sent items (probably saved-then-discarded drafts). Low count likely indicates Deleted Items is being emptied regularly or auto-purged by retention. **Not flagged**, but anomalous low count means a mailbox-level audit log search would be needed if you want to see what was deleted earlier.
|
||||
|
||||
## Suspicious items pulled from above
|
||||
|
||||
- **All 30d sign-ins from a single Salt Lake City residential IP** (Dataforth is Tucson). Not a breach indicator on its own — the IP is consistent for 30 days, suggesting one persistent client. **Confirm with Jacque or Mike whether she works from SLC / uses a VPN there.**
|
||||
- **Two OAuth grants to legacy-auth third-party email clients** (eM Client, Apple Mail). These are legitimate apps but they keep IMAP/EWS/EAS sessions alive that the dormant "Block Legacy Auth" CA policy would otherwise close. Ask whether she still uses both clients.
|
||||
|
||||
## Gaps — checks not completed
|
||||
|
||||
| Gap | Reason | Fix |
|
||||
|---|---|---|
|
||||
| Hidden inbox rules, delegates, SendAs, mailbox forwarding fields | Exchange Admin role not assigned to Security Investigator SP in this tenant (HTTP 401) | Tenant Global Admin: assign "Exchange Administrator" to SP `bfbc12a4-...` in Entra Roles. Or run `onboard-tenant.sh dataforth.com` after fixing PyJWT on operator workstation. |
|
||||
| Identity Protection (riskyUsers, riskDetections) | Tenant not licensed for AAD/Entra ID P2 | Out of scope — would require license upgrade for ~$9/user/mo. |
|
||||
|
||||
## Next actions
|
||||
|
||||
1. **Confirm SLC sign-in IP with Mike or Jacque** — is `67.206.163.122` her? (single highest-value question)
|
||||
2. **Have Jacque add Microsoft Authenticator** as MFA method, demote SMS to backup. Self-service: https://aka.ms/mfasetup. Could be done in 2 minutes during her next phone call with us.
|
||||
3. **Force a password reset** as a precaution given the dark-web hit (separate `/remediation-tool remediate jantar@dataforth.com password-reset` would do it after explicit YES — currently NOT executed).
|
||||
4. **Tenant-level posture (separate engagement, discuss with Mike before doing):**
|
||||
- Flip the 3 ACG CA policies from report-only to On.
|
||||
- Assign Exchange Administrator to the Security Investigator SP so we can see hidden rules / forwarding on future investigations.
|
||||
- Decide whether eM Client / Apple Mail (legacy-auth scopes) are still needed — if yes, those users will need an exemption when "Block Legacy Auth" is enforced.
|
||||
|
||||
## Data artifacts
|
||||
|
||||
Raw JSON in `/tmp/remediation-tool/7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584/user-breach/jantar_dataforth_com/`:
|
||||
- `00_user.json`, `01_inbox_rules_graph.json`, `02_mailbox_settings.json`
|
||||
- `04a_oauth_grants.json`, `04b_app_role_assignments.json`
|
||||
- `05_auth_methods.json`, `06_signins.json`, `07_dir_audits.json`
|
||||
- `08a_risky_user.json` (403 — not licensed), `08b_risk_detections.json` (403)
|
||||
- `09_sent.json`, `10_deleted.json`
|
||||
- `mfa_perUserState.json`, `mfa_regDetails.json`, `ca_policies.json`, `secdef.json`
|
||||
- `03a_InboxRule_hidden.json` / `03d_Mailbox.json` are EMPTY (Exchange 401)
|
||||
@@ -0,0 +1,68 @@
|
||||
# Dataforth — Lobby Phone Offline (VLAN/Switch Port Fix)
|
||||
|
||||
**Date (UTC):** 2026-05-04
|
||||
**Tech:** Howard Enos
|
||||
**Time onsite:** 0.5 hours
|
||||
**Syncro ticket:** #32246 (`109836123`), invoice #67558 (`1650188916`)
|
||||
|
||||
## User
|
||||
- **User:** Howard Enos (howard)
|
||||
- **Machine:** Howard-Home (driving the PBX remotely via Tailscale)
|
||||
- **Role:** tech
|
||||
|
||||
## Summary
|
||||
|
||||
Lobby visitor phone (Cisco SPA502G, ext 201) had been offline — no dial tone, dialing extensions did nothing, displayed an incorrect date/time. Root cause: the lobby drop's switch port had been on the wrong VLAN, isolating the phone from the PBX. Fix was reconfiguring D1-Server-Room port 1 to VLAN 100. Phone immediately TFTP-pulled fresh provisioning and registered.
|
||||
|
||||
## Diagnosis path
|
||||
|
||||
1. **Phone state:** screen showed normal idle, but no dial tone. Dialing an extension just returned to home screen with no tone, ringback, or error. Wrong date/time on display — strong clue that the phone hadn't reached NTP for a while.
|
||||
2. **PBX-side check** (driven from Howard-Home over Tailscale via SSH to `192.168.100.2` with vault creds):
|
||||
- `pjsip show endpoint 201` → `Unavailable`, no contact, AOR but no registration.
|
||||
- **Zero traffic from the phone's last known IP `192.168.100.235`** in the last 2 hours of TFTP/SIP logs.
|
||||
- PBX could not ping `.235`; ARP "who-has" requests went unanswered.
|
||||
- SIP secret in `pjsip.auth.conf` for ext 201 matched the secret in the per-MAC TFTP config `spa58bfea1158b4.xml` — so credentials were not the issue.
|
||||
3. **VLAN test:** Howard plugged his laptop into the same lobby wall jack. Laptop received `192.168.0.53` (Unifi UDM main LAN). Meanwhile, the phone — after a factory reset to clear cached state — landed on `192.168.1.235` via LLDP-MED voice tagging onto Unifi's default voice VLAN (`192.168.1.0/24`). Neither matches the production voice/PBX VLAN, which is `192.168.100.0/24`.
|
||||
4. **Cable trace:** Howard followed the lobby drop back to the **D1-Server-Room switch, port 1**. That port was not configured for VLAN 100.
|
||||
|
||||
## Network topology learned
|
||||
|
||||
| Subnet | Used for |
|
||||
|---|---|
|
||||
| `192.168.0.0/24` | Unifi main LAN (UDM is at `192.168.0.254`) |
|
||||
| `192.168.1.0/24` | Unifi default voice VLAN (LLDP-MED) — NOT used for production phones in this office |
|
||||
| `192.168.6.0/24` | OpenVPN management range (per UDM config) |
|
||||
| `192.168.100.0/24` | **Production voice/PBX VLAN** — PBX on `.196` (and `.2` aliased), all production phones |
|
||||
| `10.208.107.116/30` | PBX `ens224` secondary interface |
|
||||
|
||||
Working office phones live on `192.168.100.x` directly. The Unifi-default voice VLAN (`192.168.1.x`) is not wired to anything that can reach the PBX.
|
||||
|
||||
## Fix
|
||||
|
||||
Reconfigured **D1-Server-Room port 1** to VLAN 100. After replug:
|
||||
|
||||
- Phone DHCP'd `192.168.100.235`.
|
||||
- TFTP fetched `/spa502G.cfg` (12:29:40 PDT) and per-MAC `/spa58bfea1158b4.xml` (12:30:40 PDT).
|
||||
- SIP REGISTER → 401 Unauthorized → REGISTER (auth) → 200 OK at 12:31:42 PDT.
|
||||
- `pjsip show endpoint 201` → `In use`, contact `201/sip:201@192.168.100.235:5060` Avail, RTT 22ms.
|
||||
- NTP sync brought date/time current.
|
||||
|
||||
## Recommendation for Mike / Dataforth IT
|
||||
|
||||
- **Audit other Unifi-managed switch ports** for voice drops to ensure they all stay tagged on VLAN 100. A port that reverts to defaults will silently isolate any phone plugged into it (untagged main LAN for laptops, LLDP-MED voice tag onto `192.168.1.x` for phones — neither reaches the PBX). The wrong date/time is the canary; check that on phones that have been complained about.
|
||||
- **D1-Server-Room port 1** should stay tagged on VLAN 100. If config drifts, the lobby phone goes silent again.
|
||||
|
||||
## Tools / accounts touched
|
||||
|
||||
- SSH to PBX (`sangoma@192.168.100.2`) via Tailscale + paramiko (vault creds).
|
||||
- No production config changes on the PBX itself (read-only diagnostics there).
|
||||
- Switch port config change: D1-Server-Room port 1 → VLAN 100 (changed from whatever it was before — not captured; assumed default Unifi profile).
|
||||
|
||||
## Tools `not` touched
|
||||
|
||||
- UDM controller (`192.168.0.254`) — has 2FA push enabled and was not accessed during this work. The switch port change was made by Howard via direct switch access.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- TFTP config file confirmed correct: `/tftpboot/spa58bfea1158b4.xml` on PBX (mtime 2026-04-23 — was already current; no FreePBX-side change needed).
|
||||
- pjsip auth password matches XML password (md5 hash form `4b57418f0a921fbce9d1bee10b6084e5`).
|
||||
@@ -0,0 +1,115 @@
|
||||
# LEAP Calendar Sync Permission Investigation — slarionova@grabblaw.com
|
||||
|
||||
**Date (UTC):** 2026-05-04
|
||||
**Tenant:** grabblaw.com (`032b383e-96e4-491b-880d-3fd3295672c3`) — Grabb & Durando, P.C.
|
||||
**User:** Svetlana Larionova (`slarionova@grabblaw.com`, `affab40c-5535-4c1a-9a78-a2eda1a4a3b7`)
|
||||
**Issue:** "Not able to add calendar event from Leap to M365 — no admin permissions"
|
||||
**Investigator:** Howard Enos (read-only Graph via Security Investigator app)
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
**She does NOT need an M365 admin role.** The error is a misnamed OAuth consent block — Leap's sign-in app asks for scopes (Mail.ReadWrite, Mail.Send, Files.ReadWrite.All) that the tenant's user-consent policy classifies as "high-risk" and reserves for admin approval. Five of her co-workers (4 with no admin roles at all, 1 with User Administrator) already have these grants because an admin previously approved them per-user. She just needs the same per-user approval — not an elevated role.
|
||||
|
||||
**Recommended fix:** Have Svetlana run through Leap's M365 connect again and click "Request approval from your administrator." Then approve the request in Entra → Enterprise Applications → Admin consent requests, scoped to her user only.
|
||||
|
||||
---
|
||||
|
||||
## Findings
|
||||
|
||||
### 1. User account is healthy
|
||||
- Account enabled: `true`
|
||||
- License: `O365_BUSINESS_PREMIUM` (Exchange, SharePoint, Teams all enabled)
|
||||
- Mailbox settings reachable (English-US, MST timezone, autoreply off)
|
||||
- Group memberships: only `Grabb & Durando, P.C.` distribution group
|
||||
- **Directory roles: NONE** (correctly, no admin role)
|
||||
- Existing OAuth grants: **0**
|
||||
|
||||
### 2. Two LEAP service principals are registered in this tenant
|
||||
|
||||
| App ID | Display | Role | Consent state |
|
||||
|---|---|---|---|
|
||||
| `5602fc50-4c30-4faa-a595-e5a0f15d2cce` | LEAP (service) | App-only/daemon — runs as the app, not a user | Tenant-wide app-permission consent already granted (Calendars/Mail/Files via Application roles on Graph + EXO + SharePoint) |
|
||||
| `a7d19842-33e2-457b-a399-d4e6ec010f0a` | LEAP (delegated) | User sign-in — runs as the signed-in user | Per-user (`consentType=Principal`) grants for 5 users only |
|
||||
|
||||
### 3. The 5 users who already have working Leap calendar sync
|
||||
|
||||
| User | Admin role? |
|
||||
|---|---|
|
||||
| jsosa@grabblaw.com (Jeannette Sosa) | None |
|
||||
| rpesqueira@grabblaw.com (Reyna Pesqueira) | None |
|
||||
| avazquez@grabblaw.com (Ana Vazquez) | None |
|
||||
| yheredia@grabblaw.com (Yvette Heredia) | None |
|
||||
| jwilliams@grabblaw.com (Jeff Williams) | User Administrator (incidental) |
|
||||
|
||||
Each holds a `Principal`-type OAuth grant on the LEAP delegated app with the full scope set:
|
||||
|
||||
```
|
||||
Calendars.Read Calendars.ReadWrite Mail.Read Mail.ReadWrite Mail.Send
|
||||
Contacts.Read Tasks.Read Tasks.ReadWrite OnlineMeetings.ReadWrite
|
||||
ChannelMessage.Send ChannelMessage.Edit Chat.Create Chat.ReadWrite
|
||||
ChatMessage.Send Files.ReadWrite.All User.Read User.ReadBasic.All
|
||||
offline_access email profile openid
|
||||
```
|
||||
|
||||
The per-user grant is what makes Leap → calendar work. **No admin role is required to hold the grant.**
|
||||
|
||||
### 4. Tenant user-consent policy
|
||||
|
||||
`policies/authorizationPolicy` shows:
|
||||
- `permissionGrantPoliciesAssigned`:
|
||||
- `ManagePermissionGrantsForSelf.microsoft-user-default-recommended`
|
||||
- `ManagePermissionGrantsForSelf.microsoft-user-default-allow-consent-apps`
|
||||
|
||||
Under the **recommended** baseline, users may self-consent to apps from verified publishers, but only for "low-risk" delegated permissions. `Mail.ReadWrite`, `Mail.Send`, `Files.ReadWrite.All` are explicitly classified as **not** low-risk → admin approval required. This is what produces the "no admin permissions" message in Leap.
|
||||
|
||||
### 5. Why she's the only one stuck
|
||||
|
||||
She was hired/onboarded after the previous batch of 5 users was approved. The other consents were granted point-in-time (per-user), so a new user has to go through the same approval again. This is not a policy regression — it's the steady-state pattern in this tenant.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Fix (least-privilege)
|
||||
|
||||
### Option A — Admin Consent Request (preferred, matches existing pattern)
|
||||
|
||||
1. Have Svetlana sign in to Leap, click **Connect to Microsoft 365 / Enable calendar sync**.
|
||||
2. When she hits the "approval required" page, she clicks **Request approval from your administrator** and submits a short justification.
|
||||
3. The admin (`sysadmin@grabblaw.com` or the `guru@grabblaw.com` Global Admin) approves at:
|
||||
`https://entra.microsoft.com → Identity → Applications → Enterprise applications → Admin consent requests`
|
||||
4. Choose **Approve for this user only** (this matches what the other 5 employees have).
|
||||
5. Leap calendar sync starts working immediately.
|
||||
|
||||
Net effect: a single new `oauth2PermissionGrant` row tied to her object ID with `consentType=Principal`. No role change. No tenant-wide impact.
|
||||
|
||||
### Option B — Switch to tenant-wide admin consent (broader, easier going forward)
|
||||
|
||||
If new hires keep tripping over this, an admin can grant the LEAP delegated app **tenant-wide** consent once:
|
||||
|
||||
`https://entra.microsoft.com → Enterprise applications → LEAP (appId a7d19842-33e2-457b-a399-d4e6ec010f0a) → Permissions → Grant admin consent for Grabb & Durando`
|
||||
|
||||
Trade-off: ALL users get those scopes automatically (including new hires). The existing pattern in this tenant is per-user, so this is a deliberate change in posture — not a fix. Worth considering if Leap is the firm's standard practice management tool and everyone needs it.
|
||||
|
||||
### What NOT to do
|
||||
|
||||
- Do **not** assign her any directory role (Global Admin, Exchange Admin, etc.). It would not fix this — the error is OAuth consent, not RBAC. A user with no admin role can hold the grant, as 4 of the 5 working users prove.
|
||||
|
||||
---
|
||||
|
||||
## Evidence Artifacts
|
||||
|
||||
Raw JSON in `/tmp/remediation-tool/032b383e-96e4-491b-880d-3fd3295672c3/sla-check/`:
|
||||
- `user.json` — slarionova profile + license
|
||||
- `memberOf.json`, `transitive.json` — group/role membership (no admin roles)
|
||||
- `grants.json` — her OAuth grants (empty)
|
||||
- `sp-leap.json` — both LEAP SPs found in tenant
|
||||
- `sp-{spid}-grants.json` (via direct query) — current consent state on each LEAP SP
|
||||
- `skus.json` — license definitions
|
||||
- `ga-role.json`, `exo-role.json` — directory role lookups
|
||||
|
||||
## Tools used
|
||||
|
||||
- App tier: `investigator` (Graph read-only) — `bfbc12a4-f0dd-4e12-b06d-997e7271e10c`
|
||||
- Auth: cert (client_assertion JWT) via `get-token.sh`
|
||||
- No write actions performed.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Grabb & Durando — Leap M365 Calendar Sync + Teams + Monitor
|
||||
|
||||
**Date (UTC):** 2026-05-04
|
||||
**Tech:** Howard Enos
|
||||
**User helped:** Svetlana Larionova (`slarionova@grabblaw.com`)
|
||||
**Tenant:** grabblaw.com (`032b383e-96e4-491b-880d-3fd3295672c3`)
|
||||
|
||||
## User
|
||||
- **User:** Howard Enos (howard)
|
||||
- **Machine:** Howard-Home
|
||||
- **Role:** tech
|
||||
|
||||
## Summary
|
||||
|
||||
Multiple support items for Svetlana at Grabb & Durando in one session: got Leap's M365 calendar sync working for her account (admin-consent + token-rebind cleanup), added a second monitor to her workstation, and resolved a Teams file-send issue.
|
||||
|
||||
## 1. Leap M365 calendar sync — root cause and fix
|
||||
|
||||
### Problem
|
||||
Svetlana could not add calendar events from Leap to M365. Leap displayed "no admin permissions" during the connect-to-M365 flow.
|
||||
|
||||
### Root cause
|
||||
The error message is misleading — it's an OAuth consent block, not an RBAC issue. Leap's user-facing app (appId `a7d19842-33e2-457b-a399-d4e6ec010f0a`, registered in tenant as service principal `7dd62220-081d-4c6b-8184-dc3187e81578`) requests scopes including `Mail.ReadWrite`, `Mail.Send`, `Files.ReadWrite.All` along with `Calendars.ReadWrite`. The grabblaw.com tenant's user-consent policy (`microsoft-user-default-recommended` + `microsoft-user-default-allow-consent-apps`) classifies those as high-risk and blocks user-level self-consent. New users have to be admin-approved for Leap to connect — at the time of investigation, five other users (jsosa, rpesqueira, avazquez, jwilliams, yheredia) already had per-user `Principal` grants from a prior approval round; Svetlana didn't because she was onboarded later.
|
||||
|
||||
### Investigation
|
||||
Used the ComputerGuru Security Investigator (Graph read-only) app to:
|
||||
- Pull Svetlana's user record — confirmed `accountEnabled=true`, license `O365_BUSINESS_PREMIUM`, no admin roles, no group memberships beyond the company DL.
|
||||
- Enumerate the LEAP service principals — found two: a daemon/app-only app (5602fc50…, has `Calendars.ReadWrite` Application permission) and the user-facing delegated app (a7d19842…, requires per-user delegated consent).
|
||||
- Confirm the 5 working users had `Principal`-type OAuth grants on the delegated app and 4 of them had no admin roles. Conclusion: she did not need an admin role — just admin approval for the Leap app for her account.
|
||||
|
||||
Full investigation report: `clients/grabb-durando/reports/2026-05-04-leap-calendar-permission-investigation.md`.
|
||||
|
||||
### Fix
|
||||
Mike granted **tenant-wide** consent (`consentType=AllPrincipals`) on the LEAP delegated app at 16:26 UTC via sysadmin@grabblaw.com. Verified via `oauth2PermissionGrants` endpoint — grant count on LEAP2 went from 5 (per-user Principals) → 6 (5 Principals + 1 AllPrincipals).
|
||||
|
||||
This is broader than my original recommendation (per-user via Admin Consent Request), but it has a useful side-effect: any future new hire at Grabb & Durando won't hit the consent block — Leap will just work.
|
||||
|
||||
### Second issue — Leap bound to sysadmin's identity
|
||||
After consent, Leap stopped asking for admin permission but threw "unable to subscribe to notifications. leap cannot complete this action" instead. On further inspection, Leap was syncing **sysadmin's** mailbox/calendar instead of Svetlana's — because when Mike signed in to Leap on Svetlana's PC to grant consent, Leap stored sysadmin's user token as the calendar identity.
|
||||
|
||||
### Resolution steps Howard performed
|
||||
1. Ran Leap repair (leap.us) — did not fully fix.
|
||||
2. Revoked the M365 OAuth grant for Leap on sysadmin's account.
|
||||
3. Deleted the Leap Outlook integration cache from `%LOCALAPPDATA%\Microsoft Corporation\` on Svetlana's PC.
|
||||
4. Re-enabled the M365 connection in Leap, signing in as Svetlana.
|
||||
5. Calendar sync now works against Svetlana's mailbox.
|
||||
|
||||
### Going forward
|
||||
For future new hires at Grabb & Durando, do NOT have an admin sign in to Leap on the user's machine to grant consent — the admin's identity gets bound to that Leap install. Either:
|
||||
- Have the user run the connect flow themselves (tenant-wide consent now exists, so they should sail through), OR
|
||||
- If broader consent is ever needed, grant it via the Entra portal admin-consent flow, not by signing in to the third-party app.
|
||||
|
||||
## 2. Teams not sending files — "outside of their domain"
|
||||
|
||||
Svetlana was getting blocked sending files in Teams. Root cause: the recipient was outside the grabblaw.com domain. Teams correctly enforces the firm's external-collaboration policy; this isn't a bug. Walked through the limitation with her so she knows when to use email/secure-share for external recipients vs. Teams for internal.
|
||||
|
||||
(No tenant-side change needed — this is policy working as intended.)
|
||||
|
||||
## 3. Second monitor
|
||||
|
||||
Added a second monitor to her workstation. Plug-and-play; configured display arrangement.
|
||||
|
||||
## Tools / accounts touched
|
||||
|
||||
- ComputerGuru Security Investigator (Graph read-only) — investigation only
|
||||
- sysadmin@grabblaw.com — granted tenant-wide consent for LEAP delegated app
|
||||
- Svetlana's PC — Leap repair, deleted `%LOCALAPPDATA%\Microsoft Corporation\` Leap cache, re-signed in to Leap
|
||||
|
||||
## Follow-up
|
||||
|
||||
- Syncro ticket to create + bill (this session).
|
||||
- No further M365 / Leap work needed unless calendar sync regresses.
|
||||
@@ -0,0 +1,20 @@
|
||||
# IMC — Station 2 receipt printer reconnect + VPN install on Manda's machine
|
||||
|
||||
**Date (UTC):** 2026-05-04
|
||||
**Tech:** Howard Enos
|
||||
**Time onsite:** 0.5 hours
|
||||
**Syncro ticket:** #32247 (`109838539`), invoice #67559 (`1650189692`)
|
||||
|
||||
## User
|
||||
- **User:** Howard Enos (howard)
|
||||
- **Machine:** Howard-Home
|
||||
- **Role:** tech
|
||||
|
||||
## Summary
|
||||
|
||||
Two quick onsite items at Instrumental Music Center on Speedway:
|
||||
|
||||
1. **Station 2 receipt printer.** Stopped printing. Removed the shared printer from Station 2 and re-added it from `\\imc1`. Test print succeeded; printer back to normal operation. Classic Windows print spooler / shared-printer drift — re-adding the share refreshes the local print queue binding.
|
||||
2. **VPN install on Manda's machine.** Installed and configured the VPN client; verified connection.
|
||||
|
||||
No other findings. No follow-up needed.
|
||||
Reference in New Issue
Block a user