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

Add support for file scan storage, API keys, and updated page functionality #31

Merged
merged 16 commits into from
Mar 22, 2023
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
2 changes: 0 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ ENV ENV=production

# Set Runtime Variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV RUNTIME_VERSION=v2.4.2
ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH /app

COPY ./app/requirements.txt .
RUN pip install -r requirements.txt


COPY ./app .

# Copy the production UI assets into the new base image.
Expand Down
179 changes: 93 additions & 86 deletions README.md

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging
import os
import sys
from typing import Optional

from dotenv import load_dotenv
from flask import Flask
Expand All @@ -19,16 +20,16 @@
from models import db


def create_app():
def create_app() -> Flask:
"""Start and serve app assets and API endpoints"""
load_dotenv()

uiFolder = os.environ.get("STATIC_ASSET_FOLDER")
if uiFolder is None:
uiFolder = "react-app"
ui_folder: Optional[str] = os.environ.get("STATIC_ASSET_FOLDER", None)
if ui_folder is None:
ui_folder = "react-app"

app = Flask(__name__, static_folder=uiFolder)
app.logger.info("Serving app static assets from %s", uiFolder)
app: Flask = Flask(__name__, static_folder=ui_folder)
app.logger.info("Serving app static assets from %s", ui_folder)

if app.config["ENV"] == "production":
app.config.from_object("config.config.ProductionConfig")
Expand Down Expand Up @@ -59,9 +60,9 @@ def create_app():
if __name__ == "__main__":
logging.basicConfig(stream=sys.stdout, level=logging.INFO)

mainApp = create_app()
main_app: Flask = create_app()

serve(TransLogger(mainApp, setup_console_handler=False), host="0.0.0.0", port=8080)
serve(TransLogger(main_app, setup_console_handler=False), host="0.0.0.0", port=8080)

# uncomment below for local flask app development with hot reloading
#mainApp.run(host='0.0.0.0', port=80, threaded=True)
main_app.run(host="0.0.0.0", port=80, threaded=True)
47 changes: 36 additions & 11 deletions app/blueprints/auth.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
"""
Authentication controller
"""
from datetime import datetime, timedelta
from random import choice
from string import ascii_letters, digits

import datetime
from flask import Blueprint, current_app, request, session, jsonify
from jsonschema import validate, ValidationError
from flask import Blueprint, current_app, jsonify, request, session
from jsonschema import ValidationError, validate

from database import db
from services.auth import check_credentials
from models import User
from models import ApiKey, User
from services.auth import auth_required, check_credentials

auth = Blueprint("auth", __name__, url_prefix="/auth")

Expand All @@ -22,7 +24,30 @@
}


@auth.route("logout")
@auth.route("/apikey", methods=["GET"])
@auth_required
def get_api_key(user):
dbUser = db.session.query(User).filter_by(user_cn=user.user_cn).first()
if not dbUser:
return jsonify({"error": "User not found"}), 404
existing_key = db.session.query(ApiKey).filter_by(user_cn=user.user_cn).first()
if existing_key:
if existing_key.expiration > datetime.now():
return jsonify({"api_key": existing_key.key}), 200
else:
db.session.delete(existing_key)
db.session.commit()
key = "".join(choice(ascii_letters + digits) for _ in range(32))
expiration = datetime.now() + timedelta(
days=int(current_app.config["API_KEY_EXPIRATION"])
)
api_key = ApiKey(key=key, user_cn=user.user_cn, expiration=expiration)
db.session.add(api_key)
db.session.commit()
return jsonify({"api_key": key}), 201


@auth.route("/logout")
def logout():
"""Clears user session and returns logout message"""
session.clear()
Expand All @@ -40,23 +65,23 @@ def login():
instance={"username": username, "password": password}, schema=loginSchema
)
except ValidationError as err:
current_app.logger.error("Failed login validation: %s", err)
# current_app.logger.error("Failed login validation: %s", err)
return jsonify({"error": "Failed to validate username/password"}), 400

current_app.logger.info("received login attempt for user %s", username)
# current_app.logger.info("received login attempt for user %s", username)
success, ldapUser = check_credentials(username, password)
if not success:
return jsonify({"error": "incorrect username/password combination"}), 401

current_app.logger.info("ldap auth suceeded for user %s", ldapUser["user_cn"])
# current_app.logger.info("ldap auth suceeded for user %s", ldapUser["user_cn"])
session["user_cn"] = ldapUser["user_cn"]
session["first_name"] = ldapUser["first_name"]
session["last_name"] = ldapUser["last_name"]

# upsert the user record with the new last logged in time
try:
dbUser = db.session.query(User).filter_by(user_cn=session["user_cn"]).first()
loginTime = str(datetime.datetime.utcnow())
loginTime = str(datetime.utcnow())
if dbUser is not None:
dbUser.last_login = loginTime
dbUser.login_count += 1
Expand All @@ -78,7 +103,7 @@ def login():
session["user_id"] = dbUser.id
session["logged_in"] = True
except Exception as err:
current_app.logger.error("Failed connection to database: %s", err)
# current_app.logger.error("Failed connection to database: %s", err)
return jsonify({"error": "Failed to connect to database"}), 400

return (
Expand Down
Loading