-
Notifications
You must be signed in to change notification settings - Fork 25
/
authn_requests.py
137 lines (101 loc) · 3.31 KB
/
authn_requests.py
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from enum import Enum
from typing import List, Literal, Optional
from pydantic import BaseModel, HttpUrl, conlist, constr, validator
# TODO: Schema of claims is not genrated
class AcrValuesSpid(str, Enum):
l1 = "https://www.spid.gov.it/SpidL1"
l2 = "https://www.spid.gov.it/SpidL2"
l3 = "https://www.spid.gov.it/SpidL3"
class AcrValuesCie(str, Enum):
l1 = "CIE_L1"
l2 = "CIE_L2"
l3 = "CIE_L3"
class ScopeSpid(str, Enum):
openid = "openid"
offline_access = "offline_access"
class ScopeCie(str, Enum):
openid = "openid"
offline_access = "offline_access"
profile = "profile"
email = "email"
class ClaimsTypeEssential(BaseModel):
essential: Optional[bool]
class ClaimsTypeStringValue(BaseModel):
value: Optional[str]
class ClaimsTypeStringValues(BaseModel):
values: Optional[conlist(str, max_items=2, min_items=2)]
class ClaimsType(str, Enum):
essential = ClaimsTypeEssential
value = ClaimsTypeStringValue
values = ClaimsTypeStringValues
class UserInfo(BaseModel):
given_name: Optional[dict]
family_name: Optional[dict]
email: Optional[dict]
email_verified: Optional[dict]
gender: Optional[dict]
birthdate: Optional[dict]
phone_number: Optional[dict]
phone_number_verified: Optional[dict]
address: Optional[dict]
place_of_birth: Optional[dict]
document_details: Optional[dict]
e_delivery_service: Optional[dict]
fiscal_number: Optional[dict]
physical_phone_number: Optional[dict]
class IdToken(UserInfo):
pass
TYPES = {
"essential": ClaimsTypeEssential,
"value": ClaimsTypeStringValue,
"values": ClaimsTypeStringValues,
}
CLAIMS_SPID = {"userinfo": UserInfo}
CLAIMS_CIE = {"userinfo": UserInfo, "id_token": IdToken}
class AuthenticationRequest(BaseModel):
client_id: HttpUrl
response_type: Literal["code"]
scope: List[str]
code_challenge: str
code_challenge_method: Literal["S256"]
nonce: constr(min_length=32)
redirect_uri: HttpUrl
claims: Optional[dict]
state: constr(min_length=32)
# TODO: to be improved
ui_locales: Optional[List[str]]
sub: HttpUrl
iss: HttpUrl
iat: int
exp: Optional[int]
jti: Optional[str]
aud: List[HttpUrl]
@validator("claims")
def validate_claims(cls, claims):
for k_claim, v_claim in claims.items():
cl = cls.get_claims()
claims_items = cl.get(k_claim, None)
if not claims_items:
continue
claims_items(**v_claim)
for k_item, v_item in v_claim.items():
if v_item is not None:
for k_type, v_type in TYPES.items():
v_type(**v_item)
return claims
@validator("scope")
def validate_scope(cls, scope):
if "openid" not in scope:
raise ValueError("'scope' attribute must contain 'openid'")
class AuthenticationRequestSpid(AuthenticationRequest):
scope: List[ScopeSpid]
prompt: Literal["consent", "consent login", "verify"]
acr_values: List[AcrValuesSpid]
def get_claims() -> dict:
return CLAIMS_SPID
class AuthenticationRequestCie(AuthenticationRequest):
scope: List[ScopeCie]
prompt: Literal["consent", "consent login"]
acr_values: List[AcrValuesCie]
def get_claims() -> dict:
return CLAIMS_CIE