Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/implement-active-directory-auth'…
Browse files Browse the repository at this point in the history
… into staging
  • Loading branch information
campb303 committed Feb 12, 2021
2 parents ca62502 + f48de17 commit 5b2d5c0
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ yarn-error.log*
__pycache__/
venv-manager.log
/api/.env
/api/webqueueapi.egg-info
*.egg*
62 changes: 57 additions & 5 deletions api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
jwt_required, get_jwt_identity, jwt_refresh_token_required,
set_refresh_cookies, unset_refresh_cookies
)
from werkzeug.security import check_password_hash
import os, dotenv
from easyad import EasyAD
from ldap.filter import escape_filter_chars
# pylint says this is an error but it works so ¯\_(ツ)_/¯
from ldap import INVALID_CREDENTIALS as LDAP_INVALID_CREDENTIALS
import ECNQueue

# Load envrionment variables for ./.env
Expand Down Expand Up @@ -47,6 +50,57 @@



def user_is_valid(username: str, password: str) -> bool:
"""Checks if user is valid and in webqueue2 login group.
Args:
username (str): Career account username.
password (str): Career account passphrase.
Returns:
bool: True if user is valid, otherwise False.
"""

# Check for empty arguments
if (username == "" or password == ""):
return False

# Initialize EasyAD
config = {
"AD_SERVER": "boilerad.purdue.edu",
"AD_DOMAIN": "boilerad.purdue.edu"
}
ad = EasyAD(config)

# Prepare search critiera for Active Directory
credentials = {
"username": escape_filter_chars(username),
"password": password
}
attributes = [ 'cn', "memberOf" ]
filter_string = f'(&(objectClass=user)(|(sAMAccountName={username})))'

# Do user search
try:
user = ad.search(credentials=credentials, attributes=attributes, filter_string=filter_string)[0]
except LDAP_INVALID_CREDENTIALS:
return False

# Isolate group names
# Example:
# 'CN=00000227-ECNStuds,OU=BoilerADGroups,DC=BoilerAD,DC=Purdue,DC=edu' becomes
# `00000227-ECNStuds`
user_groups = [ group.split(',')[0].split('=')[1] for group in user["memberOf"] ]

# Check group membership
webqueue_login_group = "00000227-ECN-webqueue"
if webqueue_login_group not in user_groups:
return False

return True



class Login(Resource):
def post(self) -> tuple:
"""Validates username/password and returns both access and refresh tokens.
Expand Down Expand Up @@ -76,10 +130,8 @@ def post(self) -> tuple:
if field not in data.keys():
return ({ "message": f"{field} missing from request body"}, 422)

if data["username"] != os.environ.get("SHARED_USERNAME"):
return ({ "message": "Username invalid"}, 401)
if not check_password_hash(os.environ.get("SHARED_PASSWORD_HASH"), data["password"]):
return ({ "message": "Password invalid"}, 401)
if not user_is_valid(data["username"], data["password"]):
return ({ "message": "Username or password is invalid"}, 401)

access_token = create_access_token(data["username"])
refresh_token = create_refresh_token(data["username"])
Expand Down
10 changes: 8 additions & 2 deletions api/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# The Python virtual environment should be managed via the venv-manager utility, not directly by pip.
# See: https://pip.pypa.io/en/stable/reference/pip_install/#example-requirements-file

# General Utilities
Expand All @@ -10,10 +11,15 @@ python-dotenv
Flask-RESTful
python-dateutil
Flask-JWT-Extended
# Prevent upgrade to 2.x until Flask-JWT-Extended is updated to support it
# Flask-JWT-Extended doesn't support PyJWT 2.x as of 3.25.0
# Prevent upgrade to PyJWT 2.x until Flask-JWT-Extended is updated to support it.
# Check: https://github.com/vimalloc/flask-jwt-extended/tags
PyJWT == 1.*
# Specify pyldap version for custom build. This is not installed by pip.
pyldap == 3.3.1
easyad

# API Documentation
mkdocs
mkdocs
mkdocs-material
mkautodoc
5 changes: 1 addition & 4 deletions src/components/ItemTable/ItemTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ export default function ItemTable({ data, rowCanBeSelected }) {
{ Header: 'Department', accessor: 'department' },
{ Header: 'Building', accessor: 'building' },
{ Header: 'Date Received', accessor: 'dateReceived', sortInverted: true, Cell: ({ value }) => <RelativeTime value={value} /> },
{ Header: 'Last Updated', accessor: 'lastUpdated', },
{ Header: 'Department', accessor: 'department' },
{ Header: 'Building', accessor: 'building' },
{ Header: 'Date Received', accessor: 'dateReceived', },

], []);
const tableInstance = useTable(
{
Expand Down
Loading

0 comments on commit 5b2d5c0

Please sign in to comment.