|
1 | 1 | import httpx |
| 2 | +from httpx import Response |
| 3 | + |
| 4 | +from solid_oidc_client import SolidOidcClient, SolidAuthSession, MemStore |
| 5 | +import flask |
| 6 | + |
| 7 | +from multiprocessing import Process, Queue |
| 8 | + |
| 9 | +from typing import Dict |
2 | 10 |
|
3 | 11 |
|
4 | 12 | class Auth: |
@@ -27,3 +35,74 @@ def login(self, idp, username, password): |
27 | 35 |
|
28 | 36 | if not self.is_login: |
29 | 37 | raise Exception('Cannot login.') |
| 38 | + |
| 39 | + |
| 40 | +class OidcAuth: |
| 41 | + |
| 42 | + OAUTH_CALLBACK_PATH = '/oauth/callback' |
| 43 | + OAUTH_CALLBACK_URI = f"http://localhost:8080{OAUTH_CALLBACK_PATH}" |
| 44 | + |
| 45 | + def __init__(self): |
| 46 | + self.client = httpx.Client() |
| 47 | + self.session = None |
| 48 | + self._server_process = None |
| 49 | + |
| 50 | + @property |
| 51 | + def is_login(self) -> bool: |
| 52 | + return self.session is not None |
| 53 | + |
| 54 | + def fetch(self, method, url, options: Dict) -> Response: |
| 55 | + if 'headers' not in options: |
| 56 | + options['headers'] = {} |
| 57 | + |
| 58 | + if self.session: |
| 59 | + auth_headers = self.session.get_auth_headers(url, method) |
| 60 | + options['headers'].update(auth_headers) |
| 61 | + |
| 62 | + r = self.client.request(method, url, **options) |
| 63 | + return r |
| 64 | + |
| 65 | + def _start_server(self, solid_oidc_client: SolidOidcClient, q: Queue): |
| 66 | + process = Process(target=_run_flask_server, args=(solid_oidc_client, q)) |
| 67 | + self._server_process = process |
| 68 | + process.start() |
| 69 | + |
| 70 | + def _stop_server(self): |
| 71 | + self._server_process.terminate() |
| 72 | + |
| 73 | + def login(self, idp): |
| 74 | + solid_oidc_client = SolidOidcClient(storage=MemStore()) |
| 75 | + solid_oidc_client.register_client(idp, [OidcAuth.OAUTH_CALLBACK_URI]) |
| 76 | + login_url = solid_oidc_client.create_login_uri('/', OidcAuth.OAUTH_CALLBACK_URI) |
| 77 | + q = Queue(1) |
| 78 | + self._start_server(solid_oidc_client, q) |
| 79 | + |
| 80 | + print(f"Please visit this URL to log-in: {login_url}") |
| 81 | + |
| 82 | + session = SolidAuthSession.deserialize(q.get()) |
| 83 | + self.session = session |
| 84 | + |
| 85 | + self._stop_server() |
| 86 | + |
| 87 | + |
| 88 | +def _run_flask_server(solid_oidc_client: SolidOidcClient, q: Queue): |
| 89 | + app = flask.Flask(__name__) |
| 90 | + |
| 91 | + @app.get('/oauth/callback') |
| 92 | + def login_callback(): |
| 93 | + code = flask.request.args['code'] |
| 94 | + state = flask.request.args['state'] |
| 95 | + |
| 96 | + session = solid_oidc_client.finish_login( |
| 97 | + code=code, |
| 98 | + state=state, |
| 99 | + callback_uri=OidcAuth.OAUTH_CALLBACK_URI, |
| 100 | + ) |
| 101 | + |
| 102 | + q.put(session.serialize()) |
| 103 | + |
| 104 | + return flask.Response( |
| 105 | + f"Logged in as {session.get_web_id()}. You can close your browser now.", |
| 106 | + mimetype='text/html') |
| 107 | + |
| 108 | + app.run('localhost', 8080) |
0 commit comments