From 88a1b46927b4a3c9707adb4f71e4504dd47d6912 Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Tue, 28 Sep 2021 00:46:12 -0400 Subject: [PATCH 1/7] ADD Github OAuth Remote App URLs --- api/anubis/utils/auth/oauth.py | 18 ++++++++++++++++++ api/anubis/views/public/auth.py | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/api/anubis/utils/auth/oauth.py b/api/anubis/utils/auth/oauth.py index 05f561a6e..23b4fa024 100644 --- a/api/anubis/utils/auth/oauth.py +++ b/api/anubis/utils/auth/oauth.py @@ -14,3 +14,21 @@ consumer_key=config.OAUTH_CONSUMER_KEY, consumer_secret=config.OAUTH_CONSUMER_SECRET, ) + +OAUTH_REMOTE_APP_GITHUB = oauth.remote_app( + "github", + base_url="https://github.com/login/oauth/", + authorize_url="https://github.com/login/oauth/authorize", + request_token_url=None, + request_token_params={ + "client_id": config.OAUTH_GITHUB_CLIENT_KEY, + "scope": "read:user" + }, + access_token_url="https://github.com/login/oauth/access_token", + access_token_params={ + "client_id": config.OAUTH_GITHUB_CLIENT_KEY, + "client_secret": config.OAUTH_GITHUB_CLIENT_SECRET, + }, + consumer_key=config.OAUTH_GITHUB_CLIENT_KEY, + consumer_secret=config.OAUTH_GITHUB_CLIENT_SECRET, +) \ No newline at end of file diff --git a/api/anubis/views/public/auth.py b/api/anubis/views/public/auth.py index 3c10d2dbe..995ac12ad 100644 --- a/api/anubis/views/public/auth.py +++ b/api/anubis/views/public/auth.py @@ -14,9 +14,15 @@ from anubis.lms.courses import get_course_context from anubis.lms.submissions import fix_dangling from anubis.utils.auth.oauth import OAUTH_REMOTE_APP as provider +from anubis.utils.auth.oauth import OAUTH_REMOTE_APP_GITHUB as github_provider auth_ = Blueprint("public-auth", __name__, url_prefix="/public/auth") oauth_ = Blueprint("public-oauth", __name__, url_prefix="/public") +github_oauth_ = Blueprint( + "public-github-oauth", + __name__, + url_prefix="/public/github" +) @auth_.route("/login") @@ -89,6 +95,19 @@ def public_oauth(): return r +@github_oauth_.route("/oauth") +@require_user() +def public_github_oauth(): + """ + This is the endpoint Github oauth sends the user to after + authentication. Here we need to verify the oauth response, + and update user's Github username to the database. + + :return: + """ + pass + + @auth_.route("/whoami") def public_whoami(): """ From 36fc8dd8ef3957e7dbf731161692c1e35f51cf2b Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Tue, 28 Sep 2021 01:34:28 -0400 Subject: [PATCH 2/7] ADD Github OAuth Blueprint --- api/anubis/config.py | 4 ++++ api/anubis/views/public/__init__.py | 2 ++ api/anubis/views/public/auth.py | 12 ++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/api/anubis/config.py b/api/anubis/config.py index 74072eeb5..ee15842a5 100644 --- a/api/anubis/config.py +++ b/api/anubis/config.py @@ -44,6 +44,10 @@ def __init__(self): self.OAUTH_CONSUMER_KEY = os.environ.get("OAUTH_CONSUMER_KEY", default="DEBUG") self.OAUTH_CONSUMER_SECRET = os.environ.get("OAUTH_CONSUMER_SECRET", default="DEBUG") + # Github OAuth + self.OAUTH_GITHUB_CLIENT_KEY = os.environ.get("OAUTH_GITHUB_CLIENT_KEY", default="DEBUG") + self.OAUTH_GITHUB_CLIENT_SECRET = os.environ.get("OAUTH_GITHUB_CLIENT_SECRET", default="DEBUG") + # Logger self.LOGGER_NAME = os.environ.get("LOGGER_NAME", default="anubis-api") diff --git a/api/anubis/views/public/__init__.py b/api/anubis/views/public/__init__.py index c367b5833..e90e0ef35 100644 --- a/api/anubis/views/public/__init__.py +++ b/api/anubis/views/public/__init__.py @@ -1,6 +1,7 @@ def register_public_views(app): from anubis.views.public.auth import auth_ from anubis.views.public.auth import oauth_ + from anubis.views.public.auth import github_oauth_ from anubis.views.public.ide import ide from anubis.views.public.repos import repos_ from anubis.views.public.webhook import webhook @@ -17,6 +18,7 @@ def register_public_views(app): views = [ auth_, oauth_, + github_oauth_, ide, repos_, webhook, diff --git a/api/anubis/views/public/auth.py b/api/anubis/views/public/auth.py index 995ac12ad..122607e4d 100644 --- a/api/anubis/views/public/auth.py +++ b/api/anubis/views/public/auth.py @@ -95,17 +95,25 @@ def public_oauth(): return r +@github_oauth_.route("/link") +@require_user() +def public_github_link(): + return github_provider.authorize( + callback="http://localhost:3000/api/public/github/oauth" + ) + + @github_oauth_.route("/oauth") @require_user() def public_github_oauth(): """ - This is the endpoint Github oauth sends the user to after + This is the endpoint Github OAuth sends the user to after authentication. Here we need to verify the oauth response, and update user's Github username to the database. :return: """ - pass + return github_provider.authorized_response() @auth_.route("/whoami") From 379d5c8d1305e8cd068ff0daa3f3829f2f88f3a7 Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Wed, 29 Sep 2021 01:57:41 -0400 Subject: [PATCH 3/7] ADD Github User API Request and Github Username Update Logic --- api/anubis/utils/auth/oauth.py | 1 - api/anubis/views/public/auth.py | 28 +++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/api/anubis/utils/auth/oauth.py b/api/anubis/utils/auth/oauth.py index 23b4fa024..ff2a9a835 100644 --- a/api/anubis/utils/auth/oauth.py +++ b/api/anubis/utils/auth/oauth.py @@ -21,7 +21,6 @@ authorize_url="https://github.com/login/oauth/authorize", request_token_url=None, request_token_params={ - "client_id": config.OAUTH_GITHUB_CLIENT_KEY, "scope": "read:user" }, access_token_url="https://github.com/login/oauth/access_token", diff --git a/api/anubis/views/public/auth.py b/api/anubis/views/public/auth.py index 122607e4d..f874b19ee 100644 --- a/api/anubis/views/public/auth.py +++ b/api/anubis/views/public/auth.py @@ -1,6 +1,7 @@ import base64 import json import os +import requests from flask import Blueprint, make_response, redirect, request @@ -113,7 +114,32 @@ def public_github_oauth(): :return: """ - return github_provider.authorized_response() + + # Get the authorized response from Github OAuth + resp = github_provider.authorized_response() + if resp is None or "access_token" not in resp: + return "Access Denied" + + # Setup headers and url + github_api_headers = { + "authorization": "bearer " + resp["access_token"], + "accept": "application/vnd.github.v3+json" + } + github_api_url = "https://api.github.com/user" + + # Request Github User API + github_user_info = requests.get( + github_api_url, + headers=github_api_headers, + ).json() + + # Set github username and commit + current_user.github_username = github_user_info["login"] + db.session.add(current_user) + db.session.commit() + + # Notify them with status + return success_response({"status": "github username updated"}) @auth_.route("/whoami") From 8b99857731540ba94f889863cb2b6d637c6a4c97 Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Thu, 30 Sep 2021 01:10:04 -0400 Subject: [PATCH 4/7] CHG Variable names to accomodate new naming structure --- api/anubis/config.py | 4 ++-- api/anubis/utils/auth/oauth.py | 8 ++++---- api/anubis/views/public/__init__.py | 4 ++-- api/anubis/views/public/auth.py | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/api/anubis/config.py b/api/anubis/config.py index ee15842a5..134ccfebf 100644 --- a/api/anubis/config.py +++ b/api/anubis/config.py @@ -41,8 +41,8 @@ def __init__(self): self.CACHE_TYPE = 'NullCache' # OAuth - self.OAUTH_CONSUMER_KEY = os.environ.get("OAUTH_CONSUMER_KEY", default="DEBUG") - self.OAUTH_CONSUMER_SECRET = os.environ.get("OAUTH_CONSUMER_SECRET", default="DEBUG") + self.OAUTH_NYU_CONSUMER_KEY = os.environ.get("OAUTH_NYU_CONSUMER_KEY", default="DEBUG") + self.OAUTH_NYU_CONSUMER_SECRET = os.environ.get("OAUTH_NYU_CONSUMER_SECRET", default="DEBUG") # Github OAuth self.OAUTH_GITHUB_CLIENT_KEY = os.environ.get("OAUTH_GITHUB_CLIENT_KEY", default="DEBUG") diff --git a/api/anubis/utils/auth/oauth.py b/api/anubis/utils/auth/oauth.py index ff2a9a835..7206a74c3 100644 --- a/api/anubis/utils/auth/oauth.py +++ b/api/anubis/utils/auth/oauth.py @@ -3,16 +3,16 @@ from anubis.config import config oauth = OAuth() -OAUTH_REMOTE_APP = oauth.remote_app( +OAUTH_REMOTE_APP_NYU = oauth.remote_app( "nyu", base_url="https://auth.nyu.edu/oauth2/", authorize_url="https://auth.nyu.edu/oauth2/authorize", request_token_url=None, request_token_params={"scope": "openid"}, access_token_url="https://auth.nyu.edu/oauth2/token", - access_token_params={"client_id": config.OAUTH_CONSUMER_KEY}, - consumer_key=config.OAUTH_CONSUMER_KEY, - consumer_secret=config.OAUTH_CONSUMER_SECRET, + access_token_params={"client_id": config.OAUTH_NYU_CONSUMER_KEY}, + consumer_key=config.OAUTH_NYU_CONSUMER_KEY, + consumer_secret=config.OAUTH_NYU_CONSUMER_SECRET, ) OAUTH_REMOTE_APP_GITHUB = oauth.remote_app( diff --git a/api/anubis/views/public/__init__.py b/api/anubis/views/public/__init__.py index e90e0ef35..bc64aea7c 100644 --- a/api/anubis/views/public/__init__.py +++ b/api/anubis/views/public/__init__.py @@ -1,6 +1,6 @@ def register_public_views(app): from anubis.views.public.auth import auth_ - from anubis.views.public.auth import oauth_ + from anubis.views.public.auth import nyu_oauth_ from anubis.views.public.auth import github_oauth_ from anubis.views.public.ide import ide from anubis.views.public.repos import repos_ @@ -17,7 +17,7 @@ def register_public_views(app): views = [ auth_, - oauth_, + nyu_oauth_, github_oauth_, ide, repos_, diff --git a/api/anubis/views/public/auth.py b/api/anubis/views/public/auth.py index f874b19ee..14615c8a1 100644 --- a/api/anubis/views/public/auth.py +++ b/api/anubis/views/public/auth.py @@ -14,11 +14,11 @@ from anubis.utils.http import error_response, success_response from anubis.lms.courses import get_course_context from anubis.lms.submissions import fix_dangling -from anubis.utils.auth.oauth import OAUTH_REMOTE_APP as provider +from anubis.utils.auth.oauth import OAUTH_REMOTE_APP_NYU as nyu_provider from anubis.utils.auth.oauth import OAUTH_REMOTE_APP_GITHUB as github_provider auth_ = Blueprint("public-auth", __name__, url_prefix="/public/auth") -oauth_ = Blueprint("public-oauth", __name__, url_prefix="/public") +nyu_oauth_ = Blueprint("public-oauth", __name__, url_prefix="/public") github_oauth_ = Blueprint( "public-github-oauth", __name__, @@ -30,7 +30,7 @@ def public_login(): if is_debug(): return "AUTH" - return provider.authorize( + return nyu_provider.authorize( callback="https://anubis.osiris.services/api/public/oauth" ) @@ -42,7 +42,7 @@ def public_logout(): return r -@oauth_.route("/oauth") +@nyu_oauth_.route("/oauth") def public_oauth(): """ This is the endpoint NYU oauth sends the user to after @@ -59,13 +59,13 @@ def public_oauth(): next_url = request.args.get("next") or "/courses" # Get the authorized response from NYU oauth - resp = provider.authorized_response() + resp = nyu_provider.authorized_response() if resp is None or "access_token" not in resp: return "Access Denied" # This is the data we get from NYU's oauth. It has basic information # on who is logging in - user_data = provider.get("userinfo?schema=openid", token=(resp["access_token"],)) + user_data = nyu_provider.get("userinfo?schema=openid", token=(resp["access_token"],)) # Load the netid name from the response netid = user_data.data["netid"] From 7c4e778188a405917c4766be1d75557d0ef4e15a Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Thu, 30 Sep 2021 01:36:06 -0400 Subject: [PATCH 5/7] ADD Exception handling for Github User API request --- api/anubis/views/public/auth.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/api/anubis/views/public/auth.py b/api/anubis/views/public/auth.py index 14615c8a1..dd68f02a4 100644 --- a/api/anubis/views/public/auth.py +++ b/api/anubis/views/public/auth.py @@ -127,19 +127,22 @@ def public_github_oauth(): } github_api_url = "https://api.github.com/user" - # Request Github User API - github_user_info = requests.get( - github_api_url, - headers=github_api_headers, - ).json() - - # Set github username and commit - current_user.github_username = github_user_info["login"] - db.session.add(current_user) - db.session.commit() - - # Notify them with status - return success_response({"status": "github username updated"}) + try: + # Request Github User API + github_user_info = requests.get( + github_api_url, + headers=github_api_headers, + ).json() + + # Set github username and commit + current_user.github_username = github_user_info["login"] + db.session.add(current_user) + db.session.commit() + + # Notify them with status + return success_response({"status": "github username updated"}) + except: + return error_response({"status": "fail to update github username"}) @auth_.route("/whoami") From 26de00ca12a700d20060f813ed6c73da7d9380b7 Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Thu, 30 Sep 2021 15:13:52 -0400 Subject: [PATCH 6/7] CHG k8s yaml file to accomodate environment variables change --- k8s/chart/templates/api.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/k8s/chart/templates/api.yml b/k8s/chart/templates/api.yml index b49731149..bea0a67d6 100644 --- a/k8s/chart/templates/api.yml +++ b/k8s/chart/templates/api.yml @@ -65,16 +65,26 @@ spec: secretKeyRef: name: api key: secret-key - - name: "OAUTH_CONSUMER_KEY" + - name: "OAUTH_NYU_CONSUMER_KEY" valueFrom: secretKeyRef: name: oauth - key: consumer-key - - name: "OAUTH_CONSUMER_SECRET" + key: nyu-consumer-key + - name: "OAUTH_NYU_CONSUMER_SECRET" valueFrom: secretKeyRef: name: oauth - key: consumer-secret + key: nyu-consumer-secret + - name: "OAUTH_GITHUB_CLIENT_KEY" + valueFrom: + secretKeyRef: + name: oauth + key: github-client-key + - name: "OAUTH_GITHUB_CLIENT_SECRET" + valueFrom: + secretKeyRef: + name: oauth + key: github-client-secret - name: "DATABASE_URI" valueFrom: secretKeyRef: From 95e2e77649944431bc41bfece767e38c88f5c4c3 Mon Sep 17 00:00:00 2001 From: Maxwell Yang Date: Thu, 30 Sep 2021 15:28:58 -0400 Subject: [PATCH 7/7] CHG Github OAuth callback url to the one used in production --- api/anubis/views/public/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/anubis/views/public/auth.py b/api/anubis/views/public/auth.py index dd68f02a4..59f844628 100644 --- a/api/anubis/views/public/auth.py +++ b/api/anubis/views/public/auth.py @@ -3,7 +3,7 @@ import os import requests -from flask import Blueprint, make_response, redirect, request +from flask import Blueprint, make_response, redirect, request, url_for from anubis.models import User, db from anubis.utils.auth.http import require_user, require_admin @@ -100,7 +100,7 @@ def public_oauth(): @require_user() def public_github_link(): return github_provider.authorize( - callback="http://localhost:3000/api/public/github/oauth" + callback="https://anubis.osiris.services/api/public/github/oauth" )