moin
moin copied to clipboard
Add OIDC authentication using Flask-pyoidc.
Here's a PR to add OIDC authentication. It works just fine with Keycloak.
It does not fit into your design pattern because your Moin assumes all authentication methods have a password. OIDC does not. It will NOT login the user in middleware.
Initially there's support for 1 identity provider, but with small changes you can add multiple IDPs.
This change was very hard to make given the architecture of the current system. I left comments where Moin can become a more idiomatic Flask website. Notably:
- getting the user from the session should not depend on the authentication mode
- authentication should happen in a view/controller, not middleware
- the session needs only 2 items: user id, session_token
- model classes should not be touching the session
- the indexer is a pain in the ass to use / it should return objects not dictionaries
These are noted in the codebase with my initials: BCD. Feel free to ignore and delete them.
A web app should not be inventing it's own authentication and session management. Consider using Flask-Login to handle this. (Also consider using Flask-Security-Too.)
setup.py:111:17: E999 SyntaxError: invalid syntax
Also had to uncomment these lines in wikiconfig.py:
OIDC_REDIRECT_URI = 'http://localhost:5000/oidc_redirect_uri'
OIDC_ISSUER="https://localhost:8080/auth/realms/myfolks"
OIDC_CLIENT_ID='example.com/wiki' # best practice is to use domain name and path here
OIDC_CLIENT_SECRET='get this from the idp administrator'
OIDC_LOGOUT_URI='todo'
After setting sso = True in wikiconfig.py:
(moin-venv-python) C:\AA-GIT\BrianD\moin>m run --port 8080
2023-08-31 09:55:24,714 ERROR oic.oauth2.base:138 http_request failed: HTTPSConnectionPool(host='localhost', port=8080):
Max retries exceeded with url: /auth/realms/myfolks/.well-known/openid-configuration (Caused by NewConnectionError('<ur
llib3.connection.HTTPSConnection object at 0x00000213C9EA69E0>: Failed to establish a new connection: [WinError 10061] N
o connection could be made because the target machine actively refused it')), url: https://localhost:8080/auth/realms/my
folks/.well-known/openid-configuration, htargs: {'allow_redirects': True, 'cert': None, 'verify': True, 'timeout': 5.0},
method: GET
Traceback (most recent call last):
File "\\?\C:\AA-GIT\BrianD\moin-venv-python\Scripts\moin-script.py", line 33, in <module>
sys.exit(load_entry_point('moin', 'console_scripts', 'moin')())
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\core.py", line 1078, in main
rv = self.invoke(ctx)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\core.py", line 1688, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\decorators.py", line 92, in new_func
return ctx.invoke(f, obj, *args, **kwargs)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\click\core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask\cli.py", line 911, in run_command
raise e from None
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask\cli.py", line 897, in run_command
app = info.load_app()
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask\cli.py", line 301, in load_app
app = self.create_app()
File "c:\aa-git\briand\moin\src\moin\app.py", line 52, in create_app
return create_app_ext(flask_config_file=config)
File "c:\aa-git\briand\moin\src\moin\app.py", line 158, in create_app_ext
oidc.init_app(app)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask_pyoidc\flask_pyoidc.py", line 86, in init_app
self.clients = {
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask_pyoidc\flask_pyoidc.py", line 87, in <dictcomp>
name: PyoidcFacade(configuration, self._redirect_uri_config.full_uri)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask_pyoidc\pyoidc_facade.py", line 41, in __init__
provider_metadata = provider_configuration.ensure_provider_metadata(self._client)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\flask_pyoidc\provider_configuration.py", line 179, in ensure
_provider_metadata
resp = client.provider_config(self._issuer)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\oic\oauth2\__init__.py", line 1150, in provider_config
r = self.http_request(url, allow_redirects=True)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\oic\oauth2\base.py", line 135, in http_request
req.request(method, url, **_kwargs),
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\requests\sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\requests\sessions.py", line 703, in send
r = adapter.send(request, **kwargs)
File "C:\AA-GIT\BrianD\moin-venv-python\lib\site-packages\requests\adapters.py", line 519, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /a
uth/realms/myfolks/.well-known/openid-configuration (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection o
bject at 0x00000213C9EA69E0>: Failed to establish a new connection: [WinError 10061] No connection could be made because
the target machine actively refused it'))
Start up an open ID connect server on port 8080. I suggest keycloak. Create a realm. Add a user, set a password. Create a client, set a client id. Set the redirect uri that matches your env.
Or use a commercial one like Okta or Auth0.