From 1ecc1ae0b250f5130092d14d8c11c808247fd65b Mon Sep 17 00:00:00 2001 From: Kartik Ohri Date: Sat, 27 Apr 2024 01:29:06 +0530 Subject: [PATCH] Add support for MeB.org OAuth provider Use the newly developed MeB.org OAuth provider for handling login. Also, add support for writing reviews, voting and retrieving profile if the appropriate scopes are granted to tokens issued by the MeB.org provider. To distinguish the origin of the tokens, the fact that MeB.org issued tokens start with `meba_` can be used. --- Dockerfile.webpack | 4 +++- critiquebrainz/frontend/__init__.py | 6 ++--- critiquebrainz/frontend/login/provider.py | 2 +- critiquebrainz/frontend/views/oauth.py | 2 +- critiquebrainz/ws/oauth/provider.py | 29 ++++++++++++++++++++++- docker/docker-compose.dev.yml | 7 ++---- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Dockerfile.webpack b/Dockerfile.webpack index 340e4be85..91df32730 100644 --- a/Dockerfile.webpack +++ b/Dockerfile.webpack @@ -3,5 +3,7 @@ FROM node:20 RUN mkdir /code WORKDIR /code -COPY package.json package-lock.json webpack.config.js /code/ +COPY package.json package-lock.json /code/ RUN npm install + +COPY webpack.config.js .babelrc /code/ diff --git a/critiquebrainz/frontend/__init__.py b/critiquebrainz/frontend/__init__.py index 0d8038253..d8a69ad76 100644 --- a/critiquebrainz/frontend/__init__.py +++ b/critiquebrainz/frontend/__init__.py @@ -106,9 +106,9 @@ def create_app(debug=None, config_path=None): name='musicbrainz', client_id=app.config['MUSICBRAINZ_CLIENT_ID'], client_secret=app.config['MUSICBRAINZ_CLIENT_SECRET'], - authorize_url="https://musicbrainz.org/oauth2/authorize", - access_token_url="https://musicbrainz.org/oauth2/token", - base_url="https://musicbrainz.org/", + authorize_url="https://test.musicbrainz.org/new-oauth2/authorize", + access_token_url="https://test.musicbrainz.org/new-oauth2/token", + base_url="https://test.musicbrainz.org/", ) # APIs diff --git a/critiquebrainz/frontend/login/provider.py b/critiquebrainz/frontend/login/provider.py index 5404271d6..d7eb62d31 100644 --- a/critiquebrainz/frontend/login/provider.py +++ b/critiquebrainz/frontend/login/provider.py @@ -74,7 +74,7 @@ def get_user(self): data=data, decoder=musicbrainz_auth_session_decoder, ) - data = s.get('oauth2/userinfo').json() + data = s.get('new-oauth2/userinfo').json() musicbrainz_id = data.get('sub') musicbrainz_row_id = data.get('metabrainz_user_id') user = db_users.get_or_create(musicbrainz_row_id, musicbrainz_id, new_user_data={ diff --git a/critiquebrainz/frontend/views/oauth.py b/critiquebrainz/frontend/views/oauth.py index c08e06057..5310bd0e9 100644 --- a/critiquebrainz/frontend/views/oauth.py +++ b/critiquebrainz/frontend/views/oauth.py @@ -35,4 +35,4 @@ def authorize_prompt(): code = oauth.generate_grant(client_id, current_user.id, redirect_uri, scope) return redirect(build_url(redirect_uri, dict(code=code, state=state))) except OAuthError as e: - raise BadRequest(e.desc) \ No newline at end of file + raise BadRequest(e.desc) diff --git a/critiquebrainz/ws/oauth/provider.py b/critiquebrainz/ws/oauth/provider.py index 75584924d..b8510b265 100644 --- a/critiquebrainz/ws/oauth/provider.py +++ b/critiquebrainz/ws/oauth/provider.py @@ -1,7 +1,8 @@ from datetime import datetime, timedelta from functools import wraps -from flask import request +import requests +from flask import request, current_app import critiquebrainz.db.exceptions as db_exceptions import critiquebrainz.db.oauth_client as db_oauth_client @@ -184,12 +185,38 @@ def generate_token(self, client_id, refresh_token, user_id, scope=None): return access_token, 'Bearer', self.token_expire, refresh_token + def get_authorized_user_meb(self, access_token, scopes): + """ Query MeB OAuth provider to check validity of the access token """ + response = requests.post( + f"https://{current_app.config['MUSICBRAINZ_HOSTNAME']}/new-oauth2/introspect", + data={ + "client_id": current_app.config['MUSICBRAINZ_CLIENT_ID'], + "client_secret": current_app.config['MUSICBRAINZ_CLIENT_SECRET'], + "token": access_token, + } + ) + if response.status_code != 200: + raise exceptions.InvalidToken + data = response.json() + if data["active"] is False: + raise exceptions.InvalidToken + for scope in scopes: + if scope not in data["scope"]: + raise exceptions.InvalidToken + user = User(db_users.get_by_mb_row_id(data["metabrainz_user_id"])) + return user + def get_authorized_user(self, scopes): authorization = request.headers.get('Authorization') if self.validate_authorization_header(authorization) is False: raise NotAuthorized access_token = authorization.split()[1] + + # tokens that start with meba_ are issued by MeB OAuth provider + if access_token.startswith("meba_"): + return self.get_authorized_user_meb(access_token, scopes) + token = self.fetch_access_token(access_token) if token is None: raise exceptions.InvalidToken diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 5d7576a04..fddffe6b9 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -1,6 +1,3 @@ -# Docker Compose file for development -version: "3.4" - volumes: cb_home: cb_postgres: @@ -44,7 +41,7 @@ services: image: redis:4.0-alpine musicbrainz_db: - image: metabrainz/musicbrainz-test-database:beta + image: metabrainz/musicbrainz-test-database:production volumes: - ../data/mbdata:/var/lib/postgresql/data/pgdata:z environment: @@ -60,4 +57,4 @@ services: dockerfile: Dockerfile.webpack command: npm run dev volumes: - - ..:/code:z + - ../critiquebrainz:/code/critiquebrainz:z