-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpasso7_isc_mock_api.py
More file actions
84 lines (66 loc) · 3.16 KB
/
Copy pathpasso7_isc_mock_api.py
File metadata and controls
84 lines (66 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""
PASSO 7 - Conectando "como em producao": mock da API do SailPoint ISC.
Esta API imita o jeito real do ISC funcionar:
- Autenticacao OAuth2 (client_credentials): voce troca client_id + client_secret
por um access_token (Bearer), igual ao tenant real.
- Endpoints no estilo /v3 protegidos: so respondem com um token valido.
A ideia: o cliente do PASSO 7 usa EXATAMENTE o mesmo codigo que usaria contra um
tenant real do ISC -- bastaria trocar a URL base e as credenciais.
Roda na porta 8003.
uvicorn passo7_isc_mock_api:app --reload --port 8003
"""
import secrets
from fastapi import Depends, FastAPI, Form, HTTPException
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
# Credenciais "de mentira" (no ISC real, voce gera no painel: API Management).
CLIENT_ID = "lab-client-id"
CLIENT_SECRET = "lab-client-secret"
# Tokens emitidos e ainda validos (em memoria).
TOKENS_VALIDOS: set[str] = set()
# Identities no formato parecido com o do ISC real.
IDENTITIES = [
{"id": "2c918085", "name": "ana.souza", "attributes": {
"email": "ana.souza@empresa.com", "department": "Financeiro"}, "lifecycleState": "active"},
{"id": "2c918086", "name": "bruno.lima", "attributes": {
"email": "bruno.lima@empresa.com", "department": "TI"}, "lifecycleState": "active"},
{"id": "2c918087", "name": "carla.mendes", "attributes": {
"email": "carla.mendes@empresa.com", "department": "RH"}, "lifecycleState": "inactive"},
]
app = FastAPI(title="Mock ISC API (SailPoint ISC Lab)", version="1.0.0")
bearer = HTTPBearer(auto_error=True)
def exigir_token(cred: HTTPAuthorizationCredentials = Depends(bearer)):
"""Valida o Bearer token, como o ISC faz em cada chamada protegida."""
if cred.credentials not in TOKENS_VALIDOS:
raise HTTPException(status_code=401, detail="Token invalido ou expirado.")
return cred.credentials
# 1) OAuth2 client_credentials: troca credenciais por um access_token.
@app.post("/oauth/token")
def emitir_token(
grant_type: str = Form(...),
client_id: str = Form(...),
client_secret: str = Form(...),
):
if grant_type != "client_credentials":
raise HTTPException(400, "grant_type deve ser 'client_credentials'.")
if client_id != CLIENT_ID or client_secret != CLIENT_SECRET:
raise HTTPException(401, "client_id ou client_secret invalidos.")
token = secrets.token_hex(16)
TOKENS_VALIDOS.add(token)
return {"access_token": token, "token_type": "Bearer", "expires_in": 3600}
# 2) Listar identities (protegido por token), no estilo /v3 do ISC.
@app.get("/v3/identities")
def listar_identities(_: str = Depends(exigir_token)):
return IDENTITIES
# 3) Criar um access request (protegido), no estilo /v3 do ISC.
@app.post("/v3/access-requests")
def criar_access_request(corpo: dict, _: str = Depends(exigir_token)):
requested_for = corpo.get("requestedFor")
itens = corpo.get("requestedItems", [])
if not requested_for or not itens:
raise HTTPException(400, "Informe 'requestedFor' e 'requestedItems'.")
return {
"id": secrets.token_hex(8),
"status": "PENDING",
"requestedFor": requested_for,
"requestedItems": itens,
}