Skip to content

Commit

Permalink
Introduce GitHub OAuth Authentication
Browse files Browse the repository at this point in the history
This implements the long waited GitHub Auth
allows 3 options:
1- Registering with GitHub
2- Linking your existing profile with GitHub
3- Logging in with GitHub

Two variables are needed `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`
instructions are written as comments in the code.
  • Loading branch information
peregrineshahin committed Aug 18, 2024
1 parent 12981ff commit 4499084
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 27 deletions.
4 changes: 4 additions & 0 deletions server/fishtest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,9 @@ def group_finder(username, request):
config.add_route("api_actions", "/api/actions")
config.add_route("api_calc_elo", "/api/calc_elo")

# GitHub OAuth Routes
config.add_route("github_oauth", "/github/oauth")
config.add_route("github_callback", "/github/callback")

config.scan()
return config.make_wsgi_app()
31 changes: 19 additions & 12 deletions server/fishtest/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,25 @@ def size_is_length(x):
size_is_length,
)

user_schema = {
"_id?": ObjectId,
"username": username,
"password": str,
"registration_time": datetime_utc,
"pending": bool,
"blocked": bool,
"email": email,
"groups": [str, ...],
"tests_repo": union("", url),
"machine_limit": uint,
}
user_schema = intersect(
{
"_id?": ObjectId,
"username": username,
"password?": str,
"registration_time": datetime_utc,
"pending": bool,
"blocked": bool,
"email?": email,
"github_id?": str,
"linked_github_username?": str,
"github_access_token?": str,
"groups": [str, ...],
"tests_repo?": union("", url),
"machine_limit": uint,
},
at_least_one_of("email", "github_id"),
at_least_one_of("password", "github_access_token"),
)


worker_schema = {
Expand Down
10 changes: 10 additions & 0 deletions server/fishtest/templates/login.mak
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@

<button type="submit" class="btn btn-primary w-100">Login</button>
</form>

<div class="text-md-center my-4">
<p>Or</p>
<form action="${request.route_url('github_oauth')}" method="post">
<input type="hidden" name="action" value="login">
<button type="submit" class="btn btn-secondary w-100">
<i class="fa-brands fa-github"></i> Log in with GitHub
</button>
</form>
</div>
</div>

<script
Expand Down
9 changes: 9 additions & 0 deletions server/fishtest/templates/signup.mak
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@

<button type="submit" class="btn btn-primary w-100">Register</button>
</form>
<div class="text-md-center my-4">
<p>Or</p>
<form action="${request.route_url('github_oauth')}" method="post">
<input type="hidden" name="action" value="signup">
<button type="submit" class="btn btn-secondary w-100">
<i class="fa-brands fa-github"></i> Sign up with GitHub
</button>
</form>
</div>
</div>

<script
Expand Down
20 changes: 19 additions & 1 deletion server/fishtest/templates/user.mak
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<li class="list-group-item bg-transparent text-break">Registered: ${format_date(user['registration_time'] if 'registration_time' in user else 'Unknown')}</li>
% if not profile:
<li class="list-group-item bg-transparent text-break">Tests Repository:
% if user['tests_repo']:
% if 'tests_repo' in user and user['tests_repo']:
<a class="alert-link" href="${user['tests_repo']}">${extract_repo_from_link(user['tests_repo'])}</a>
% else:
<span>-</span>
Expand All @@ -55,6 +55,14 @@
<li class="list-group-item bg-transparent text-break">
Groups: ${format_group(user['groups'])}
</li>
<li class="list-group-item bg-transparent text-break">
Linked GitHub user:
% if 'linked_github_username' in user and user['linked_github_username']:
<a class="alert-link" href="https://github.com/${user["linked_github_username"]}">GitHub/${user["linked_github_username"]}</a>
% else:
<span>No accounts linked</span>
% endif
</li>
<li class="list-group-item bg-transparent text-break">Machine Limit: ${limit}</li>
<li class="list-group-item bg-transparent text-break">CPU-Hours: ${hours}</li>
</ul>
Expand Down Expand Up @@ -212,6 +220,8 @@
</div>
</div>
<button type="submit" class="btn btn-primary w-100">Save</button>
<div class="text-md-center my-4">
</div>
% elif 'pending' in user and user['pending']:
<div class="alert alert-dark mb-3">
<label class="mb-2 h5">User Approval:</label>
Expand Down Expand Up @@ -273,6 +283,14 @@
% endif
% endif
</form>
% if profile and not 'linked_github_username' in user:
<form action="${request.route_url('github_oauth')}" method="post">
<input type="hidden" name="action" value="link">
<button type="submit" class="btn btn-secondary w-100">
<i class="fa-brands fa-github"></i> Link GitHub Account
</button>
</form>
% endif
</div>

<script
Expand Down
53 changes: 40 additions & 13 deletions server/fishtest/userdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ def get_blocked(self):
def get_user(self, username):
return self.find_by_username(username)

def get_user_by_github_id(self, github_id):
return self.users.find_one({"github_id": github_id})

def get_user_groups(self, username):
user = self.get_user(username)
if user is not None:
Expand All @@ -105,27 +108,51 @@ def add_user_group(self, username, group):
self.users.replace_one({"_id": user["_id"]}, user)
self.clear_cache()

def create_user(self, username, password, email, tests_repo):
def create_user(
self,
username,
password=None,
email="",
tests_repo="",
linked_github_username=None,
github_id=None,
github_access_token=None,
):
try:
if self.find_by_username(username) or self.find_by_email(email):
return False
# insert the new user in the db
user = {
"username": username,
"password": password,
"registration_time": datetime.now(timezone.utc),
"pending": True,
"blocked": False,
"email": email,
"groups": [],
"tests_repo": tests_repo,
"machine_limit": DEFAULT_MACHINE_LIMIT,
}
if github_id is not None and github_access_token is not None:
user = {
"username": username,
"registration_time": datetime.now(timezone.utc),
"pending": True,
"blocked": False,
"github_id": github_id,
"github_access_token": github_access_token,
"linked_github_username": linked_github_username,
"email": email,
"groups": [],
"tests_repo": tests_repo,
"machine_limit": DEFAULT_MACHINE_LIMIT,
}
else:
user = {
"username": username,
"password": password,
"registration_time": datetime.now(timezone.utc),
"pending": True,
"blocked": False,
"email": email,
"groups": [],
"tests_repo": tests_repo,
"machine_limit": DEFAULT_MACHINE_LIMIT,
}

validate_user(user)
self.users.insert_one(user)
self.last_pending_time = 0
self.last_blocked_time = 0

return True
except:
return None
Expand Down
Loading

0 comments on commit 4499084

Please sign in to comment.