Files
claudetools/temp/vwp_add_mail_send.py
Mike Swanson fa15b03180 sync: Auto-sync from ACG-M-L5090 at 2026-03-10 19:11:00
Synced files:
- Quote wizard frontend (all components, hooks, types, config)
- API updates (config, models, routers, schemas, services)
- Client work (bg-builders, gurushow)
- Scripts (BGB Lesley termination, CIPP, Datto, migration)
- Temp files (Bardach contacts, VWP investigation, misc)
- Credentials and session logs
- Email service, PHP API, session logs

Machine: ACG-M-L5090
Timestamp: 2026-03-10 19:11:00

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:59:08 -07:00

107 lines
3.5 KiB
Python

"""Add Mail.Send permission to the app registration and grant admin consent."""
import json
import sys
import urllib.request
import urllib.parse
import urllib.error
import ssl
TENANT_ID = "5c53ae9f-7071-4248-b834-8685b646450f"
APP_ID = "fabb3421-8b34-484b-bc17-e46de9703418"
APP_SECRET = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO"
GRAPH_APP_ID = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
ctx = ssl.create_default_context()
def get_token():
data = urllib.parse.urlencode({
"client_id": APP_ID,
"scope": "https://graph.microsoft.com/.default",
"client_secret": APP_SECRET,
"grant_type": "client_credentials",
}).encode()
req = urllib.request.Request(
f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token",
data=data, method="POST"
)
with urllib.request.urlopen(req, context=ctx) as resp:
return json.loads(resp.read())["access_token"]
def graph_get(token, url):
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"})
with urllib.request.urlopen(req, context=ctx) as resp:
return json.loads(resp.read())
def graph_post(token, url, payload=None):
headers = {"Authorization": f"Bearer {token}"}
body = None
if payload:
headers["Content-Type"] = "application/json"
body = json.dumps(payload).encode()
else:
body = b""
req = urllib.request.Request(url, data=body, headers=headers, method="POST")
try:
with urllib.request.urlopen(req, context=ctx) as resp:
content = resp.read()
return json.loads(content) if content else {}
except urllib.error.HTTPError as e:
body = e.read().decode()
try:
return json.loads(body)
except:
return {"error": {"message": body, "code": str(e.code)}}
token = get_token()
print("[OK] Token acquired")
# Find our app's service principal
filter_val = urllib.parse.quote(f"appId eq '{APP_ID}'")
url = f"https://graph.microsoft.com/v1.0/servicePrincipals?$filter={filter_val}"
data = graph_get(token, url)
if not data.get("value"):
print("[ERROR] Could not find our service principal")
print(json.dumps(data, indent=2)[:1000])
sys.exit(1)
our_sp_id = data["value"][0]["id"]
print(f"[OK] Our SP ID: {our_sp_id}")
# Find Microsoft Graph service principal
filter_val2 = urllib.parse.quote(f"appId eq '{GRAPH_APP_ID}'")
url2 = f"https://graph.microsoft.com/v1.0/servicePrincipals?$filter={filter_val2}"
data2 = graph_get(token, url2)
graph_sp_id = data2["value"][0]["id"]
print(f"[OK] Graph SP ID: {graph_sp_id}")
# Find Mail.Send role
app_roles = data2["value"][0].get("appRoles", [])
mail_send_id = None
for role in app_roles:
if role.get("value") == "Mail.Send":
mail_send_id = role["id"]
break
if not mail_send_id:
print("[ERROR] Mail.Send role not found")
sys.exit(1)
print(f"[OK] Mail.Send role ID: {mail_send_id}")
# Grant the appRoleAssignment (admin consent)
payload = {
"principalId": our_sp_id,
"resourceId": graph_sp_id,
"appRoleId": mail_send_id
}
url3 = f"https://graph.microsoft.com/v1.0/servicePrincipals/{our_sp_id}/appRoleAssignments"
result = graph_post(token, url3, payload)
if result.get("id"):
print(f"[SUCCESS] Mail.Send permission granted! Assignment ID: {result['id']}")
elif "already exists" in str(result.get("error", {}).get("message", "")):
print("[INFO] Mail.Send permission already assigned")
else:
print(f"[RESULT] Response: {json.dumps(result, indent=2)[:1000]}")