IdentityPython / JWTConnect-Python-OidcRP

Highlevel interface to the OIDC RP library
Apache License 2.0
89 stars 28 forks source link

[TypeError: 'NoneType' object is not subscriptable] RPHandler.client_configs #9

Closed peppelinux closed 5 years ago

peppelinux commented 5 years ago

OP Setup made with oidc-op.flask_op. Using RP Handler (TIER1), as exposed in the documentation, I get that rph.client_configs is None.

from oidcrp import RPHandler
rph = RPHandler()
issuer_id = "https://127.0.0.1:5000"

Traceback

In [1]: from oidcrp import RPHandler
   ...: rph = RPHandler()
   ...: issuer_id = "https://127.0.0.1:5000"
   ...: info = rph.begin(issuer_id)
   ...: 
   ...: 
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/DEV3/Django-Identity.env/lib/python3.5/site-packages/oidcrp/__init__.py in client_setup(self, iss_id, user)
    305         try:
--> 306             client = self.issuer2rp[iss_id]
    307         except KeyError:

KeyError: 'https://127.0.0.1:5000'

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-1-4b78f790e1d7> in <module>()
      2 rph = RPHandler()
      3 issuer_id = "https://127.0.0.1:5000"
----> 4 info = rph.begin(issuer_id)

~/DEV3/Django-Identity.env/lib/python3.5/site-packages/oidcrp/__init__.py in begin(self, issuer_id, user_id)
    412 
    413         # Get the client instance that has been assigned to this issuer
--> 414         client = self.client_setup(issuer_id, user_id)
    415 
    416         try:

~/DEV3/Django-Identity.env/lib/python3.5/site-packages/oidcrp/__init__.py in client_setup(self, iss_id, user)
    309                 client = temporary_client
    310             else:
--> 311                 client = self.init_client(iss_id)
    312         else:
    313             return client

~/DEV3/Django-Identity.env/lib/python3.5/site-packages/oidcrp/__init__.py in init_client(self, issuer)
    182         :return: A Client instance
    183         """
--> 184         _cnf = self.pick_config(issuer)
    185 
    186         try:

~/DEV3/Django-Identity.env/lib/python3.5/site-packages/oidcrp/__init__.py in pick_config(self, issuer)
    161         :return: A client configuration
    162         """
--> 163         return self.client_configs[issuer]
    164 
    165     def get_session_information(self, key):

TypeError: 'NoneType' object is not subscriptable

It seems that client_configs must be passed in RPHandler.init() otherwise rph.client_configs will be unset and thows this error that blocks every other actions.

rohe commented 5 years ago

Yes, look at flask_rp/application.py there you can see that RPHandler needs quite a set of information.

peppelinux commented 5 years ago

so I ran in JWTConnect-Python-OidcRP python3 -m flask_rp.wsgi fc_conf.py

There would be the possibility to update in the future the documentation to give users an immediate approach, do you agree? We'll do our best.

Now I have this Selezione_626

But when I select an op (flop or filip) I get

Something went wrong:'class'
rohe commented 5 years ago

I usually run ./wsgi.py conf.yaml this from JWTConnect-Python-OidcRP/flask_rp

rohe commented 5 years ago

flop references a local OP. Which you probably dosen't have running. filip is a test OP which quite likely are not up and running at this point in time.

If there was a publicly accessible OP that accepted anonymous client registration we could reference it. But there aren't.

All the public ones (like Google) demands that you pre-register.

peppelinux commented 5 years ago

It seems it wants a .py dict instead of a .yaml file.

python3 -m flask_rp.wsgi conf.yaml
Traceback (most recent call last):
  File "/usr/lib/python3.5/runpy.py", line 184, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.5/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "~/DEV3/OIDC-Project/JWTConnect-Python-OidcRP/flask_rp/wsgi.py", line 29, in <module>
    template_folder=template_dir)
  File "~/DEV3/OIDC-Project/JWTConnect-Python-OidcRP/flask_rp/application.py", line 37, in oidc_provider_init_app
    app.config.from_pyfile(os.path.join(dir_path, config_file))
  File "~/DEV3/Django-Identity.env/lib/python3.5/site-packages/flask/config.py", line 132, in from_pyfile
    exec(compile(config_file.read(), filename, "exec"), d.__dict__)
  File "~/DEV3/OIDC-Project/JWTConnect-Python-OidcRP/flask_rp/conf.yaml", line 1
    BASEURL: "https://127.0.0.1:8090"
           ^
SyntaxError: invalid syntax
peppelinux commented 5 years ago

flop references a local OP. Which you probably dosen't have running.

I have this, using oidc-op

python -m flask_op.server private/conf.yaml
2019-08-28 09:34:22,338 root DEBUG Configured logging using dictionary
2019-08-28 09:34:22,339 oidcop.configure DEBUG Reading session signer from private/session.json
2019-08-28 09:34:22,339 oidcop.configure DEBUG Set server password to b'mGg5fSju9mhS8tybWxBFmQbauUDAYKPmaSTafSy5Nfk'
 * Serving Flask app "oidc_op" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
rohe commented 5 years ago

It should work with a .yaml file. Look at the function oidc_provider_init_app in flask_rp/application.

Hmm, have you updated recently ? The line reference in your stack trace makes me believe you're not running the same code as I am.

rohe commented 5 years ago

We/I should also remove bc_conf.py and fc_conf.py and only keep conf.yaml/(conf.py)

peppelinux commented 5 years ago

Ok I can do this this morning (remove deprecated confs). I'm using the latest master branch in my fork https://github.com/peppelinux/JWTConnect-Python-OidcRP It's quite update.

I proceed with the purge

rohe commented 5 years ago

My bad! Hadn't pushed the latest updates. Done now.

peppelinux commented 5 years ago

right, I coded this meanwhile:

def load_yaml_config(file_name):
    with open(file_name) as fp:
        c = yaml.safe_load(fp)
    return c

def yaml_to_py_stream(file_name):
    d = load_yaml_config(file_name)
    fstream = io.StringIO()
    for i in d:
        section = '{} = {}\n\n'.format(i, json.dumps(d[i], indent=2))
        fstream.write(section)
    fstream.seek(0)
    return fstream

This traduce yaml to a python settings file... But with the latest updates it seems quite useless. I'll put it in oidc-op.utils.

peppelinux commented 5 years ago

I got

2019-08-28 10:58:03,353 oidcendpoint.endpoint DEBUG - registration_endpoint -
2019-08-28 10:58:03,354 oidcendpoint.endpoint INFO Request: b'{"contacts": ["ops@example.com"], "token_endpoint_auth_method": "client_secret_basic", "redirect_uris": ["https://127.0.0.1:8090/authz_cb/flop"], "application_type": "web", "post_logout_redirect_uris": ["https://127.0.0.1:8090"], "grant_types": ["authorization_code"], "response_types": ["code"]}'
2019-08-28 10:58:03,354 oidcop.configure ERROR the JSON object must be str, not 'bytes'

I'm going through this, it's just an encoding exception. a .decode() should be enough.

peppelinux commented 5 years ago

Fixed in oidc-op.flask_op.views.service_endpoint#219 with:

        if request.data:
            req_args = request.data \
                       if isinstance(request.data, str) else \
                       request.data.decode()

Got another exception here:

2019-08-28 11:17:41,396 cryptojwt.key_bundle:ERROR Key bundle update failed: Remote key update from 'https://127.0.0.1:5000/static/jwks.json' failed, HTTP status 404
2019-08-28 11:17:41,396 oidcservice.oidc.provider_info_discovery:DEBUG service_context behaviour: {'scope': ['openid', 'profile', 'email', 'address', 'phone'], 'application_type': 'web', 'token_endpoint_auth_method': 'client_secret_basic', 'response_types': ['code'], 'contacts': ['ops@example.com'], 'application_name': 'rphandler'}
2019-08-28 11:17:41,396 oidcrp.oauth2:DEBUG do_request info: {'url': 'https://127.0.0.1:5000/registration', 'headers': {'Content-Type': 'application/json'}, 'body': '{"grant_types": ["authorization_code"], "application_type": "web", "redirect_uris": ["https://127.0.0.1:8090/authz_cb/flop"], "token_endpoint_auth_method": "client_secret_basic", "response_types": ["code"], "post_logout_redirect_uris": ["https://127.0.0.1:8090"], "contacts": ["ops@example.com"]}', 'method': 'POST'}
2019-08-28 11:17:41,396 oidcrp.oauth2:DEBUG Doing request with: URL:https://127.0.0.1:5000/registration, method:POST, data:{"grant_types": ["authorization_code"], "application_type": "web", "redirect_uris": ["https://127.0.0.1:8090/authz_cb/flop"], "token_endpoint_auth_method": "client_secret_basic", "response_types": ["code"], "post_logout_redirect_uris": ["https://127.0.0.1:8090"], "contacts": ["ops@example.com"]}, https_args:{'Content-Type': 'application/json'}
2019-08-28 11:17:41,398 urllib3.connectionpool:DEBUG Starting new HTTPS connection (1): 127.0.0.1:5000
2019-08-28 11:17:41,410 urllib3.connectionpool:DEBUG https://127.0.0.1:5000 "POST /registration HTTP/1.1" 400 91
2019-08-28 11:17:41,411 oidcrp.oauth2:ERROR Error response (400): {"error_description": "'RSAKey' object has no attribute 'key'", "error": "invalid_request"}
2019-08-28 11:17:41,411 oidcrp.util:DEBUG resp.headers: {'Date': 'Wed, 28 Aug 2019 09:17:41 GMT', 'Server': 'Werkzeug/0.15.5 Python/3.5.2', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '91'}
2019-08-28 11:17:41,411 oidcrp.util:DEBUG resp.txt: {"error_description": "'RSAKey' object has no attribute 'key'", "error": "invalid_request"}
rohe commented 5 years ago

So, check the content of static/jwks.json seems something is wrong with it.

peppelinux commented 5 years ago

Yes, I fixed static/ web resource in oidc-op so jwks.json is now available.

2019-08-28 11:46:39,127 werkzeug INFO 127.0.0.1 - - [28/Aug/2019 11:46:39] "GET /static/jwks.json HTTP/1.1" 200 -

But the previous RSAKey exception still persists, in oidcendpoint.cookie the object sign_key has no attribute .key:

 60  ->     if sign_key:
 61             signer = HMACSigner(algorithm=sign_alg)
 62             mac = signer.sign(bytes_load + bytes_timestamp, sign_key.key)
 63         else:
 64             mac = b''
 65     
(Pdb) sign_key
<cryptojwt.jwk.rsa.RSAKey object at 0x7fb3376bb080>
(Pdb) sign_key.__dict__
{'kty': 'RSA', 'x5c': [], 'e': 'AQAB', 'p': '7lFoGJpzgVnle11WT8adj-bkSKvt8o7ZZMC9IeXM5isMfCgZggJ-7XKn-M2Zqw6SLcfnncF4TgaiUo2vzKD7NpaOVy9pfDoEDpPXHtq7zITh25K_sCtq2M3-Nae4_lrt_MlqrF5jobTbUJUSGcD1VAE55TB84FyJ7Ic2nw6LUNU', 'dp': '', 'priv_key': <cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey object at 0x7fb3376bb1d0>, 'n': 'x2cFaCAhrOmQsH1y4PlBetB1KylQhQ7SmQJw9f4r6jn_gDo1FdsMbZozPlY6-g3h9EvZkeSUbwGLGnZTU_k55UgzFqLhpZC8F6-IbHLpsenKPAFcVz4Uj1Hs4_cK5fiXQXjnoJVK4WB0QyfYsilH-Awd2tYWlIaNxviDrX8jJcI15lcCGNoM1I1PUDQFD-REypp0m7DJ2SD4jEr8F8eYC2IeM_2F-MymrOu3eRI2ndgNDD7f5QWPXwbtUpQm-LXVNBi_IEZ4mKGYQVOY36QlBdO6DY_LD70qANrx55bIVLB3aLh1NO0ewCDHx1Mn71lCr1u2Iew2EvoiwODna-zWYw', 'q': '1jJ0idy5_DREDr2PkpNFWUyd3kNlTsALq8eoy5O4yGzbY2TNAtE6P4PYPHri1dHchbJkgW7HTf2nYpsMsCiH76nANlX41d128MgukURhl9wReTOoNH3vPc2NJVz0sFsQH8khtisyJ9SbQvZVCAtEejQ3FUpgMwhli0GATZKh5lc', 'extra_args': {}, 'x5t': '', 'kid': 'Z3RzQXZpQU02ZXhmeEtYNXIyY2s1OVNRV19xakdLSWNyY1o2VGIyZmtiSQ', 'alg': '', 'd': 'FAa-vkRr3WffxjnzLbEa6HDDM8CEe7iPYhqiqbILSwzkIka2Simjx-Yyu1IBvldimBx-D277kWKAS_oSSF7Bd8uWhfF55BzzJxXUB8BKxDmMvBYO5hwwCGzb89E94PbkigjQiooz6Qq84nnAA7Stq7Xb0byqq-QPnSocX3JjX0lCmfdcX2prQVCH3-CnD8x3HGeudV83dVqq5Kk-nJpWDej7HeDrloOsN6v4eVSv2gQYoNXWkNFIrZZPa7RjPTZD5-woqzu6ukHcHTuD4sIl2ulGgqz5MNNGgWhK6SMsFYooIVZv0ZGF12WktVfxDdn84rm2ewLEIuKjZSUiMPap0Q', 'k': '', 'use': '', 'x5u': '', 'di': '', 'qi': '', 'inactive_since': 0, 'dq': '', 'pub_key': <cryptography.hazmat.backends.openssl.rsa._RSAPublicKey object at 0x7fb3376bb390>}

I'm looking through this, Can it depends on the command I used to generate cookie sign jwk?

python -c 'import json; from cryptojwt.jwk.rsa import new_rsa_key; print(json.dumps(new_rsa_key().to_dict(), indent=2))' > private/cookie_sign_jwk.json
peppelinux commented 5 years ago

Moved to https://github.com/rohe/oidc-op/issues/5