Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test MeB OAuth provider #518

Merged
merged 3 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion consul_config.py.ctmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down
6 changes: 3 additions & 3 deletions critiquebrainz/frontend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion critiquebrainz/frontend/login/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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={
Expand Down
8 changes: 4 additions & 4 deletions critiquebrainz/frontend/views/test/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ def test_login_oauth(self, mock_requests):
""" Tests that creating a new user, update MB username and login to CB updates MB username in CB db """
row_id = 1111

mock_requests.post("https://musicbrainz.org/oauth2/token", json={
mock_requests.post("https://musicbrainz.org/new-oauth2/token", json={
"access_token": "UF7GvG2pl70jTogIwOhD32BhI_aIevPF",
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "GjSCBBjp4fnbE0AKo3uFu9qq9K2fFm4u"
})

mock_requests.get("https://musicbrainz.org/oauth2/userinfo", json={
mock_requests.get("https://musicbrainz.org/new-oauth2/userinfo", json={
"sub": "old-user-name",
"metabrainz_user_id": row_id
})
Expand All @@ -46,7 +46,7 @@ def test_login_oauth(self, mock_requests):
self.client.get(url_for("login.logout"))

# change MB username without changing display name, musicbrainz id in database should update
mock_requests.get("https://musicbrainz.org/oauth2/userinfo", json={
mock_requests.get("https://musicbrainz.org/new-oauth2/userinfo", json={
"sub": "new-user-name",
"metabrainz_user_id": row_id
})
Expand All @@ -68,7 +68,7 @@ def test_login_oauth(self, mock_requests):
db_users.update(user["id"], {"display_name": "custom-display-name"})

# change MB username, musicbrainz id in database should not update because display name is different
mock_requests.get("https://musicbrainz.org/oauth2/userinfo", json={
mock_requests.get("https://musicbrainz.org/new-oauth2/userinfo", json={
"sub": "another-new-user-name",
"metabrainz_user_id": row_id
})
Expand Down
50 changes: 40 additions & 10 deletions critiquebrainz/ws/oauth/provider.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions custom_config.py.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ SECRET_KEY = "CHANGE_THIS"
#MUSICBRAINZ_USERAGENT = "CritiqueBrainz Custom"
MUSICBRAINZ_CLIENT_ID = ""
MUSICBRAINZ_CLIENT_SECRET = ""
MUSICBRAINZ_OAUTH_URL = "https://musicbrainz.org/new-oauth2"

# Server with Spotify mappings
# https://github.com/metabrainz/mbspotify
Expand Down
1 change: 1 addition & 0 deletions default_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
MUSICBRAINZ_USERAGENT = "CritiqueBrainz"
MUSICBRAINZ_CLIENT_ID = ""
MUSICBRAINZ_CLIENT_SECRET = ""
MUSICBRAINZ_OAUTH_URL = ""

# Spotify
SPOTIFY_CLIENT_ID = ""
Expand Down
3 changes: 0 additions & 3 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# Docker Compose file for development
version: "3.4"

volumes:
cb_home:
cb_postgres:
Expand Down
5 changes: 2 additions & 3 deletions docker/push.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
# and push it to the Docker Hub, with an optional tag (by default "beta").
#
# Usage:
# $ ./push.sh [env] [tag]
# $ ./push.sh [tag]

cd "$(dirname "${BASH_SOURCE[0]}")/../"

ENV=${1:-beta}
TAG=${2:-beta}
TAG=${1:-beta}
docker build -t metabrainz/critiquebrainz:$TAG \
--build-arg GIT_COMMIT_SHA=$(git rev-parse HEAD) .
docker push metabrainz/critiquebrainz:$TAG
Loading