1
1
import json
2
2
import logging
3
- from typing import Optional
4
- from typing import Union
3
+ from typing import Optional , Union
4
+
5
+ from idpyoidc .message import Message
6
+ from idpysdjwt .issuer import Issuer
7
+ from satosa_idpyop .persistence import Persistence
8
+ from satosa_idpyop .utils import combine_client_subject_id
9
+
10
+ from openid4v .openid_credential_issuer .credential import CredentialConstructor
11
+
12
+ logger = logging .getLogger (__name__ )
13
+
14
+
15
+ class PIDConstructor (CredentialConstructor ):
16
+
17
+ def __init__ (self , upstream_get , ** kwargs ):
18
+
19
+ CredentialConstructor .__init__ (self , upstream_get = upstream_get )
20
+ self .url = kwargs .get ("url" ) # MUST have a value
21
+ self .body = kwargs .get ("body" , {})
22
+ self .claims = kwargs .get (
23
+ "attributes" , ["family_name" , "given_name" , "birth_date" ]
24
+ )
25
+
26
+ def _get_userinfo (self , cntx , user_id , claims_restriction , client_id ):
27
+ _persistence = self .upstream_get ("attribute" , "persistence" )
28
+ logger .debug (f"Using { _persistence .name } persistence layer" )
29
+ client_subject_id = combine_client_subject_id (client_id , user_id )
30
+ authn_claims = _persistence .load_claims (client_subject_id )
31
+ # filter on accepted claims
32
+ _ava = {}
33
+ if {"family_name" , "given_name" , "birth_date" }.issubset (
34
+ set (list (authn_claims .keys ()))
35
+ ):
36
+ for attr , value in authn_claims .items ():
37
+ if attr in ["family_name" , "given_name" , "birth_date" ]:
38
+ _ava [attr ] = value
39
+
40
+ logger .debug (f"Authentication claims: { _ava } " )
41
+ return _ava
42
+
43
+ def __call__ (
44
+ self ,
45
+ user_id : str ,
46
+ client_id : str ,
47
+ request : Union [dict , Message ],
48
+ grant : Optional [dict ] = None ,
49
+ id_token : Optional [str ] = None ,
50
+ authz_detail : Optional [dict ] = None ,
51
+ persistence : Optional [Persistence ] = None ,
52
+ ) -> str :
53
+ logger .debug (":" * 20 + "PID constructor" + ":" * 20 )
54
+
55
+ # Get extra arguments from the authorization request if available
56
+ if "issuer_state" in grant .authorization_request :
57
+ msg = Message ().from_urlencoded (grant .authorization_request ["issuer_state" ])
58
+ _body = msg .to_dict ()
59
+ _body ["credential_type" ] = "sdjwt"
60
+ _vct = authz_detail ["vct" ]
61
+ _body ["document_type" ] = _vct
62
+ else :
63
+ _body = grant .authorization_request
64
+
65
+ logger .debug (f"Authorization request claims: { _body } " )
66
+
67
+ # and more arguments from what the authentication returned
68
+ # _persistence = self.upstream_get("attribute", "persistence")
69
+ logger .debug (f"Using { persistence .name } persistence layer" )
70
+ client_subject_id = combine_client_subject_id (client_id , user_id )
71
+ authn_claims = persistence .load_claims (client_subject_id )
72
+ # filter on accepted claims
73
+ _ava = {}
74
+ logger .debug (f"AVA claims: { authn_claims } " )
75
+ for attr , value in authn_claims .items ():
76
+ if attr in ["family_name" , "given_name" , "birth_date" ]:
77
+ _ava [attr ] = value
78
+ logger .debug (f"Authentication claims: { _ava } " )
79
+
80
+ if "birth_date" in _ava :
81
+ if isinstance (_ava ["birth_date" ], list ):
82
+ _ava ["birth_date" ] = _ava ["birth_date" ][0 ]
83
+
84
+ if "identity" not in _body :
85
+ _body ["identity" ] = {"schema" : {"name" : "FR" }}
86
+
87
+ _body ["identity" ].update (_ava )
88
+
89
+ _body ["jwk" ] = request ["__verified_proof" ].jws_header ["jwk" ]
90
+
91
+ ci = Issuer (
92
+ key_jar = self .upstream_get ("attribute" , "keyjar" ),
93
+ iss = self .upstream_get ("attribute" , "entity_id" ),
94
+ sign_alg = "ES256" ,
95
+ lifetime = 31536000 ,
96
+ holder_key = {},
97
+ )
98
+
99
+ logger .debug (f"Combined body: { _body } " )
100
+
101
+ _sdjwt = ci .create_holder_message (
102
+ payload = _body , jws_headers = {"typ" : "example+sd-jwt" }
103
+ )
104
+ return json .dumps ({"credentials" : [{"credential" : _sdjwt }]})
105
+
106
+
107
+ """
108
+ import json
109
+ import logging
110
+ from typing import Optional, Union
5
111
6
112
from cryptojwt.jwk.jwk import key_from_jwk_dict
7
113
from idpyoidc.client.exception import OidcServiceError
8
114
from idpyoidc.exception import RequestError
9
115
from idpyoidc.message import Message
10
- from openid4v .openid_credential_issuer .credential import CredentialConstructor
11
116
from satosa_idpyop.persistence import Persistence
12
117
from satosa_idpyop.utils import combine_client_subject_id
13
118
119
+ from openid4v.openid_credential_issuer.credential import CredentialConstructor
120
+
14
121
logger = logging.getLogger(__name__)
15
122
16
123
@@ -20,7 +127,9 @@ def __init__(self, upstream_get, **kwargs):
20
127
CredentialConstructor.__init__(self, upstream_get=upstream_get)
21
128
self.url = kwargs.get("url") # MUST have a value
22
129
self.body = kwargs.get("body", {})
23
- self .claims = kwargs .get ("attributes" , ["family_name" , "given_name" , "birth_date" ])
130
+ self.claims = kwargs.get(
131
+ "attributes", ["family_name", "given_name", "birth_date"]
132
+ )
24
133
25
134
def _get_userinfo(self, cntx, user_id, claims_restriction, client_id):
26
135
_persistence = self.upstream_get("attribute", "persistence")
@@ -29,15 +138,16 @@ def _get_userinfo(self, cntx, user_id, claims_restriction, client_id):
29
138
authn_claims = _persistence.load_claims(client_subject_id)
30
139
# filter on accepted claims
31
140
_ava = {}
32
- if {"family_name" , "given_name" , "birth_date" }.issubset (set (list (authn_claims .keys ()))):
141
+ if {"family_name", "given_name", "birth_date"}.issubset(
142
+ set(list(authn_claims.keys()))
143
+ ):
33
144
for attr, value in authn_claims.items():
34
145
if attr in ["family_name", "given_name", "birth_date"]:
35
146
_ava[attr] = value
36
147
37
148
logger.debug(f"Authentication claims: {_ava}")
38
149
return _ava
39
150
40
-
41
151
# def __call__(self,
42
152
# user_id: str,
43
153
# client_id: str,
@@ -95,3 +205,4 @@ def _get_userinfo(self, cntx, user_id, claims_restriction, client_id):
95
205
# msg = self.get_response(url=self.url, body=_body, headers={"Content-Type": "application/json"})
96
206
# logger.debug(f"return message: {msg}")
97
207
# return msg
208
+ """
0 commit comments