zamzterz/Flask-pyoidc

How to use pyoicd with multiple blueprints

Closed this issue · 5 comments

My Flask project is growing and I want to split my major blueprint up into smaller components.
Is it possible to use pyoidc for this?

When I register multiple blueprints, an exception occurs immediately:

  File "C:\Users\az27355\Miniconda3\envs\backoffice_nova\lib\site-packages\flask\app.py", line 1283, in add_url_rule
    "existing endpoint function: %s" % endpoint
AssertionError: View function mapping is overwriting an existing endpoint function: redirect_uri
# init.py
   [...]
    app = Flask(__name__, instance_relative_config=False)
    with app.app_context():
        from .main import main_routes, sub_routes, kmd_nova_routes  # import routes after initializing db object

        app.register_blueprint(main_routes.main_bp)
        app.register_blueprint(sub_routes.sub_bp)
        app.register_blueprint(kmd_nova_routes.nova_bp)

        return app
# in each blueprint
    [...]
    auth = OIDCAuthentication({PROVIDER_NAME1: PROVIDER_CONFIG})
    auth.init_app(current_app)
    [...]

It should be possible. But only one OIDCAuthentication instance and and one call auth.init_app should be made, i.e. it shouldn't be done in each blueprint.

See for example #81 for one way to structure it.

I was looking at #81 but I didn't understand it, and in the last post by OP (esune) it sounds like he abandoned the issue.

So I made this minimal, reproducible example:
https://github.com/andanders/pyoidc_blueprints

However is it sane? Is it safe? Is it close enough to best practices?
You can clone, fill config.py and run.

Additional questions:

  • As you can see in the configuration I'm using SERVER_NAME instad of OIDC_REDIRECT_URI simply because I couldn't get the latter to work.
  • In __init__.py I wonder if it is better to do
    auth.init_app(app)
    app.auth = auth

inside or outside with app.app_context():. Functionally it seems to do the same.

Unfortunately I don't have time right now to check your example in detail, but I did take a quick look: the code looks reasonable to me, and if it works after your testing I'd say it's safe. 🙂

For your additional questions:

  • What problem did you encounter when using OIDC_REDIRECT_URI? Any error message, stacktrace, etc.? It expects a different value than SERVER_NAME, namely the full URL for the endpoint to be used, see the example app.
  • OIDCAuthentication.init_app shouldn't be necessary to run within app.app_context() so can run it outside of it.

I figured out the problem with OIDC_REDIRECT_URI : I was using an incorrect URL.
It works with OIDC_REDIRECT_URI = 'http://localhost:5000/redirect_uri'
I also had to delete the SERVER_NAME.

however I get an Internal Server Error in my production environment when I log out:

App constructed with Arg 'env' = 'None'
[2020-09-15 13:15:47,518] ERROR in app: Exception on /logout [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.7/site-packages/flask_pyoidc/flask_pyoidc.py", line 242, in wrapper
    if flask.request.args['state'] != flask.session.pop('end_session_state'):
  File "/usr/local/lib/python3.7/site-packages/werkzeug/datastructures.py", line 269, in pop
    rv = super(UpdateDictMixin, self).pop(key)
KeyError: 'end_session_state'

Great that you got the redirect URI part working!

Your new error seems unrelated to this issue, so could you please create a new issue for it? 🙂
And please include all details you have about it - does the error always happen, how does your final config look like, etc.