diff --git a/consul_config.py.ctmpl b/consul_config.py.ctmpl index 4f588c6e5..e0c8b4a29 100644 --- a/consul_config.py.ctmpl +++ b/consul_config.py.ctmpl @@ -21,10 +21,11 @@ MUSICBRAINZ_HOSTNAME = '''{{template "KEY" "musicbrainz/hostname"}}''' MUSICBRAINZ_USERAGENT = '''{{template "KEY" "musicbrainz/useragent"}}''' MUSICBRAINZ_CLIENT_ID = '''{{template "KEY" "musicbrainz/client_id"}}''' MUSICBRAINZ_CLIENT_SECRET = '''{{template "KEY" "musicbrainz/client_secret"}}''' +MUSICBRAINZ_OAUTH_URL = '''{{template "KEY" "musicbrainz/oauth_url"}}''' {{if service "pgbouncer-master"}} {{with index (service "pgbouncer-master") 0}} -SQLALCHEMY_DATABASE_URI = "postgresql://critiquebrainz:critiquebrainz@{{.Address}}:{{.Port}}/critiquebrainz_db" +SQLALCHEMY_DATABASE_URI = "postgresql://{{template "KEY" "critiquebrainz/dbuser"}}:{{template "KEY" "critiquebrainz/dbpass"}}@{{.Address}}:{{.Port}}/{{template "KEY" "critiquebrainz/dbname"}}" BB_DATABASE_URI = "postgresql://{{template "KEY" "bookbrainz/dbuser"}}:{{template "KEY" "bookbrainz/dbpass"}}@{{.Address}}:{{.Port}}/{{template "KEY" "bookbrainz/dbname"}}" {{end}} {{end}} diff --git a/critiquebrainz/frontend/__init__.py b/critiquebrainz/frontend/__init__.py index b96029cf6..40b4df05b 100644 --- a/critiquebrainz/frontend/__init__.py +++ b/critiquebrainz/frontend/__init__.py @@ -110,9 +110,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=app.config['MUSICBRAINZ_OAUTH_URL'] + "/authorize", + access_token_url=app.config['MUSICBRAINZ_OAUTH_URL'] + "/token", + base_url=app.config['MUSICBRAINZ_OAUTH_URL'], ) # APIs diff --git a/critiquebrainz/frontend/login/provider.py b/critiquebrainz/frontend/login/provider.py index 5404271d6..2189af0a6 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('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/ws/oauth/provider.py b/critiquebrainz/ws/oauth/provider.py index 75584924d..313cce5ba 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,24 +185,53 @@ def generate_token(self, client_id, refresh_token, user_id, scope=None): return access_token, 'Bearer', self.token_expire, refresh_token + def introspect_meb_token(self, access_token): + response = requests.post( + current_app.config["MUSICBRAINZ_OAUTH_URL"] + "/introspect", + data={ + "client_id": current_app.config["MUSICBRAINZ_CLIENT_ID"], + "client_secret": current_app.config["MUSICBRAINZ_CLIENT_SECRET"], + "token": access_token, + "token_type_hint": "access_token", + } + ) + return response.json() + 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] - token = self.fetch_access_token(access_token) - if token is None: - raise exceptions.InvalidToken - if token["expires"] < datetime.now(): - raise exceptions.InvalidToken + if access_token.startswith("meba_"): + token = self.introspect_meb_token(access_token) + if not token["active"]: + raise exceptions.InvalidToken + if datetime.fromtimestamp(token["expires_at"]) < datetime.now(): + raise exceptions.InvalidToken - for scope in scopes: - if scope not in db_oauth_token.get_scopes(token["id"]): + token_scopes = token["scope"] + for scope in scopes: + if scope not in token_scopes: + raise exceptions.InvalidToken + + user = User(db_users.get_by_mbid(token["sub"])) + return user + else: + token = self.fetch_access_token(access_token) + if token is None: + raise exceptions.InvalidToken + if token["expires"] < datetime.now(): raise exceptions.InvalidToken - user = User(db_users.get_by_id(token["user_id"])) - return user + + token_scopes = db_oauth_token.get_scopes(token["id"]) + for scope in scopes: + if scope not in token_scopes: + raise exceptions.InvalidToken + + user = User(db_users.get_by_id(token["user_id"])) + return user def require_auth(self, *scopes): def decorator(f): diff --git a/custom_config.py.example b/custom_config.py.example index a33d6e168..121a59098 100644 --- a/custom_config.py.example +++ b/custom_config.py.example @@ -27,6 +27,7 @@ SECRET_KEY = "CHANGE_THIS" #MUSICBRAINZ_USERAGENT = "CritiqueBrainz Custom" MUSICBRAINZ_CLIENT_ID = "" MUSICBRAINZ_CLIENT_SECRET = "" +MUSICBRAINZ_OAUTH_URL = "" # Server with Spotify mappings # https://github.com/metabrainz/mbspotify diff --git a/default_config.py b/default_config.py index 11bd5e28d..b56a35777 100644 --- a/default_config.py +++ b/default_config.py @@ -63,6 +63,7 @@ MUSICBRAINZ_USERAGENT = "CritiqueBrainz" MUSICBRAINZ_CLIENT_ID = "" MUSICBRAINZ_CLIENT_SECRET = "" +MUSICBRAINZ_OAUTH_URL = "" # Spotify SPOTIFY_CLIENT_ID = "" diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 5d7576a04..e4a1a1d43 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: