Closed peppelinux closed 5 years ago
So what's in "jwks_dir/jwks.json" and 'static/jwks.json' ?
Note that the YAML file uses a set of tools the PY file doesn't. One such is bound to these lines:
OIDC_KEYS: 'private_path': "./priv/jwks.json" 'key_defs': *keydef 'public_path': './static/jwks.json'
Given that in the configuration file the RP will create a new set of keys if the given files don't exist or are empty. I need to convert the YAML config to PY config because the key creation function is quite useful.
Ah, reading the OIDC-op logs it's obvious :-/ In the client registration there MUST be a jwks or a jwks_uri claim. There ain't. So the OP doesn't get any keys from the RP. Now, the question is why the RP isn't registering keys. My guess is that a key file is missing. Which comes back to the: "What's in .. " questions above.
So what's in "jwks_dir/jwks.json" and 'static/jwks.json' ?
Regarding oidc-op, conf.yaml
op:
server_info:
...
jwks:
private_path: private/private_jwks.json
key_defs: *key_def
uri_path: static/jwks.json
I created private_jwks.json
in this way python -c 'import json; from cryptojwt.jwk.rsa import new_rsa_key; print(json.dumps(new_rsa_key().to_dict(), indent=2))'
(probably wrong, I need instead to deal with init_key_jar
). Here its content:
oidc-op$ cat private/private_jwks.json
{
"e": "AQAB",
"q": "0bM2G0rs0B_3Yzb46by5o96WzX-K1bcmdyfSWWjNKsZ0TB7I8tpWyJTYgQU_Tl_n_-ID80r77irOkrmkoYu4vX8sfSY2n_lXczp3YS9oHUu4DVzc2aGIyks2KJGR87mUhkpXkOXYokBr0nopVElTnv2rf9x309OojupqfPHtSMU",
"p": "1B5i7RDfSGtUlFCn4vHeVWlhtoLFDIRCDHW7gwl0eEPjbwzp-u10wTht4cRsc_N0cIPxssxEZdyDMBpDN4D_tSu5NoXN9V30XJG5UMqj--Kzqiqvmd3T6qU1MpEtY0a8HwqZUm53i3ufMb6a4GmpvouXS0Jp3IGU39jU96UKxX8",
"kid": "Y29IU1RCaEd3NXNZMU5YQ3VCNmNGcFhRVEllRUJjQU0yNXZWSkdxbTVfOA",
"kty": "RSA",
"n": "rcFM17ywh94KYrimjoe3lPByDmiuAORau_z4PSCZIh_aqWpQWPBVaAIhjYYSVtbffkOOJDYio0syCBE0ErwDggmXVGy4TH5ZOS6wmAjTmhTDzkfLIphafwg8oSnA1x65Y2057vrfaTp1rHMB1T3bUFeC2tEBajlmSAiJALRRYdK62nIBMkGROBKaMzynMUyWYYSxisVy0eFy2e4fR2uoUGMAeRucL3Vb0G3C1SzxZ1uLJt68b9rlWjdJ4tqe9L6u3hDqxYKupZm8KAAABBYUa-GgwqpXFL_owhJoyJbE2h1_KWQrFU6Ramr7fbtUa8SbpSsdgdZUwsboeLdmbmiyuw",
"d": "HyTtxCGzNrdK_0T_vb5_3nd2yjRjNA-6X8XJLRPBvwccp49B1Z9Gf70aDIcClIQxTS2Itd7qOIDK9_01a0I-ErnrYRuXsUZYcdJ3nti-LPkZ28islYffeLOeQnj8ctK0Aila4AYhs3fiDcYThwhuXilBcD1UVpjxR2oYPIMVr0XN0mcpuy8VMUrtb3shIJqFKkYhBzujbgVBRH4wnIrKpTJx-p0P3c7nsN8G7Sj7qkboobll4v3ZnJU9ryU-6gbsFXPijXQ3zvxSqGYxI8WEPhD7fDgwSd-dMzARVy-VJhv804LSUrqGXYQgC0GMcw9rh48N7WTScDvbD_bu52HuaQ"
}
I'll take a look into sources to see how it will be created automatically if absent. For example in oidc-op the following is created if absent:
token_handler_args:
jwks_def:
private_path: 'private/token_jwks.json'
This is oidc-op static/jwtk.json
cat static/jkws.json
{"keys": [{"kty": "RSA", "use": "sig", "kid": "TGhjUE8xYVRNc0E0UGl4NFBHNzZ2M1dJWXNkaU41TlY5Umxrdk9NT3JRYw", "e": "AQAB", "n": "6Ng0mZKOShKZEFwdJEAlPx-B1oTuH31ZDUvvinZnzkyoEeMfnK2_vxlrf-yHljDtiKBuqSa_wAUXVDKwc5krCUCYMnCPmORzqMkGyB2iqIgz62pQqlUx16ynM0XTTpoC2bgpto-KW3LurfCV6szEQ8nXorEfraXLaG-NkhZCohqC-fPtQyDZCvJCASbjSIATtqD0cXEVjYQyLoxh3WXw2hEWAUkfWSwEwh4saMOGxIWFn0Cs3X7_16yQpCa9Qn8kmgbNb-dndWHec5HyKUooetGkZqv8Pp90tstrza3e8JOtXoFfe0uT7ImuDDSLDgGYDxP6x2nucvQGvSjt8CdzrQ"}, {"kty": "EC", "use": "sig", "kid": "WGx2RmVhaUxaZ2ZmZWYwVngyMHZmaFFUSWJqblhpVURINXdnREZNakdZWQ", "crv": "P-256", "x": "e1HiQ-bNlVsdQ8DV95v6vgoQNXGEOY2Brbu9pz4AJVM", "y": "osKZQ8S20557irH8rklGTgmMwbNOhmObzeFw6KNwZg8"}]}
Note that the YAML file uses a set of tools the PY file doesn't. One such is bound to these lines:
OIDC_KEYS: 'private_path': "./priv/jwks.json" 'key_defs': *keydef 'public_path': './static/jwks.json'
Given that in the configuration file the RP will create a new set of keys if the given files don't exist or are empty.
tested in flask_rp/conf.yaml. It doesn't create the keys if they absent, using:
OIDC_KEYS:
'private_path': './private/jwks.json'
'key_defs': *keydef
'public_path': './static/jwks.json'
This is debug
JWTConnect-Python-OidcRP$ python3 -m flask_rp.wsgi flask_rp/conf.yaml
> ~/DEV3/OIDC-Project/JWTConnect-Python-OidcRP/flask_rp/application.py(17)init_oidc_rp_handler()
-> _kj = init_key_jar(**oidc_keys_conf)
(Pdb) oidc_keys_conf
{'public_path': './static/jwks.json', 'key_defs': [{'key': '', 'type': 'RSA', 'use': ['sig']}, {'crv': 'P-256', 'type': 'EC', 'use': ['sig']}], 'private_path': './private/jwks.json'}
(Pdb) n
> ~/DEV3/OIDC-Project/JWTConnect-Python-OidcRP/flask_rp/application.py(18)init_oidc_rp_handler()
-> _kj.verify_ssl = verify_ssl
(Pdb) _kj
<KeyJar(issuers=[''])>
(Pdb) _kj.__dict__
{'spec2key': {}, 'httpc': <function request at 0x7f2125d40730>, 'verify_ssl': True, 'remove_after': 3600, 'issuer_keys': {'': [<cryptojwt.key_bundle.KeyBundle object at 0x7f21276fc518>]}, 'keybundle_cls': <class 'cryptojwt.key_bundle.KeyBundle'>, 'ca_certs': None}
(Pdb)
I need to convert the YAML config to PY config because the key creation function is quite useful. See https://github.com/rohe/oidc-op/blob/master/src/oidcop/utils.py#L17, it will be trivial to store that IOStream to a real file.
ok, to get it to create the jwks files I added read_only=False as follow
OIDC_KEYS:
'private_path': './flask_rp/private/jwks.json'
'key_defs': *keydef
'public_path': './flask_rp/static/jwks.json'
'read_only': False
Right ! In the default case you don't want it to overwrite what's already there. If there is something there.
You definitely need init_key_jar to create a syntactically correct JWKS file.
I go ahead but I understand that in oidcendpoint.do_client_registration I cannot find jwks_uri
and jwks` in request, as you already told me but I'm tryng to find the right configuration to get those attributes available in my RP registration request.
the interesting part in oidcendpoint.registration is at line 212
t = {'jwks_uri': '', 'jwks': None}
for item in ['jwks_uri', 'jwks']:
if item in request:
t[item] = request[item]
# if it can't load keys because the URL is false it will
# just silently fail. Waiting for better times.
_context.keyjar.load_keys(client_id,
jwks_uri=t['jwks_uri'],
jwks=t['jwks'])
try:
n_keys = 0
for kb in _context.keyjar[client_id]:
n_keys += len(kb.keys())
msg = "found {} keys for client_id={}"
logger.debug(msg.format(n_keys, client_id))
You definitely need init_key_jar to create a syntactically correct JWKS file.
this is something usefull for the enduser documentation.
RPHandler loads corretly my jwks definitions, but they do not appear in the RP registration request. I'm going through this....
JWTConnect-Python-OidcRP/flask_rp/application.py(32)init_oidc_rp_handler()
-> return rph
(Pdb) rph
<oidcrp.RPHandler object at 0x7fad78a10320>
(Pdb) rph.__dict__
{'base_url': 'https://127.0.0.1:8090', 'hash_seed': b'BabyHoldOn', 'client_authn_factory': None, 'client_cls': <class 'oidcrp.oidc.RP'>, 'session_interface': <oidcservice.state_interface.StateInterface object at 0x7fad7a2b7048>, 'extra': {'jwks_path': 'static/jwks.json'}, 'jwks_uri': 'https://127.0.0.1:8090/static/jwks.json', 'services': None, 'keyjar': <KeyJar(issuers=[''])>, 'verify_ssl': False, 'hash2issuer': {}, 'issuer2rp': {}, 'client_configs': {'flop': {'client_preferences': {'token_endpoint_auth_method': ['client_secret_basic', 'client_secret_post'], 'contacts': ['ops@example.com'], 'scope': ['openid', 'profile', 'email', 'address', 'phone'], 'application_type': 'web', 'application_name': 'rphandler', 'response_types': ['code']}, 'issuer': 'https://127.0.0.1:5000/', 'services': {'refresh_accesstoken': {'kwargs': {}, 'class': 'oidcservice.oidc.refresh_access_token.RefreshAccessToken'}, 'userinfo': {'kwargs': {}, 'class': 'oidcservice.oidc.userinfo.UserInfo'}, 'discovery': {'kwargs': {}, 'class': 'oidcservice.oidc.provider_info_discovery.ProviderInfoDiscovery'}, 'authorization': {'kwargs': {}, 'class': 'oidcservice.oidc.authorization.Authorization'}, 'accesstoken': {'kwargs': {}, 'class': 'oidcservice.oidc.access_token.AccessToken'}, 'registration': {'kwargs': {}, 'class': 'oidcservice.oidc.registration.Registration'}, 'end_session': {'kwargs': {}, 'class': 'oidcservice.oidc.end_session.EndSession'}}, 'redirect_uris': ['https://127.0.0.1:8090/authz_cb/flop'], 'keys': {'url': {'https://127.0.0.1:5000': 'https://127.0.0.1:5000/static/jwks.json'}}}}, 'httplib': None, 'state_db': <oidcservice.state_interface.InMemoryStateDataBase object at 0x7fad7a297dd8>}
Ah, reading the OIDC-op logs it's obvious :-/ In the client registration there MUST be a jwks or a jwks_uri claim. There ain't. So the OP doesn't get any keys from the RP. Now, the question is why the RP isn't registering keys.
Ok I get it to have jwks_uri paramenter into registration request, this way in RP:
CLIENTS:
flop:
client_preferences: *id001
issuer: https://127.0.0.1:5000/
keys:
url:
'https://127.0.0.1:5000' : https://127.0.0.1:5000/static/jwks.json
jwks_uri: https://127.0.0.1:8090/static/jwks.json
redirect_uris: ['https://127.0.0.1:8090/authz_cb/flop']
services: *id002
Now I can see it in oidcendpoint.registration#212
and op log tell me oidcendpoint.oidc.registration DEBUG found 2 keys for client_id=ZXbrP1P0aYUG
. Where these are:
{"keys": [{"kid": "OVRhTkUxY0hmb284VTRCNTBwSXlsN0lMNldPX3pYUkk1RjB3SDg3Tm9naw", "e": "AQAB", "kty": "RSA", "use": "sig", "n": "9_wL2eQdFfc41L52Dm_YvBV2jT6_41jC8LsseNe6L5-wA6hSeX12zv72SwzulQ7TldQVNEG3heTKlWXWcFFyQZlzplhyZn_RsTho8lgqnXDV-jWdysSK9y3NyxWMJhgeAcWy7HUQUrUezS8vob91mpewk5pLpMmbnDTQdGD_iKYechF7XQqSekzJqO8j5d2p7-Wnz06iByRdSG82MKHhQXwN1y9Y3TVDwZ8wgO8f9lYOfeQMRvQih9R2w-1ceiwuxgSMB-0-EpTWkdZokq_ybzeNaCTwBzYVBgScYkEL3BoIhkh09uWh4YU2QUely6K5RRxWBg1CdpRTdSOoK6L1uw"}, {"kid": "YjI2VTQ3UnZiUlVFR19id1dtTnR6LUM4OG9nNHFyd3F6QVlrR3l6Nk83aw", "y": "U8XAhxQTWoDViyN8XapSSV9DE0jo9hidVI6sMXWxjTE", "kty": "EC", "crv": "P-256", "x": "VgCYJIANpfDHcWdyy3UBwDby1uKcrs8eTW4grOS0Ssk", "use": "sig"}]}
But the exception 'RSAKey' object has no attribute 'key'
still persists. So I found the error, it was the format of cookie_sign_jwk.json
, in fact the exception raises into oidcendpoint.cookie.
#60 (sign_enc_payload):
cookie_dealer:
class: oidcendpoint.cookie.CookieDealer
kwargs:
sign_jwk: 'private/cookie_sign_jwk.json'
I can close this issue and deal with a documentation on the Readme about the creation of this file via cryptojwt
.
I think that It would be good if the following resource: https://github.com/rohe/ojou_course/blob/master/presentation/JWx.pdf
can be linked into cryptojwt documentation. As it come, good enough for primers
running a RP test instance as follow:
JWTConnect-Python-OidcRP/chrp$ ./rp.py -t -k conf
its conf is
I get this exception (OidcRP):
Oidc-op side I have this log
the logs oidc-op tell us
2019-08-28 14:56:54,805 oidcendpoint.oidc.registration DEBUG found 0 keys for client_id=eD4fg038iVSc
.