Skip to content
Snippets Groups Projects
Commit e642ca0b authored by Victor Löfgren's avatar Victor Löfgren Committed by Carl Schönfelder
Browse files

Resolve "Whitelist jwt"

parent a29a04ba
No related branches found
No related tags found
1 merge request!121Resolve "Whitelist jwt"
Pipeline #43133 passed
Showing
with 78 additions and 63 deletions
......@@ -45,15 +45,3 @@ def create_app(config_name="configmodule.DevelopmentConfig"):
return response
return app, sio
def identity(payload):
user_id = payload["identity"]
return models.User.query.filter_by(id=user_id)
@jwt.token_in_blacklist_loader
def check_if_token_in_blacklist(decrypted_token):
jti = decrypted_token["jti"]
return models.Blacklist.query.filter_by(jti=jti).first() is not None
from functools import wraps
import app.core.http_codes as http_codes
from flask_jwt_extended import verify_jwt_in_request
from flask_jwt_extended.utils import get_jwt_claims
......
import app.core.http_codes as codes
import app.database.controller as dbc
from app.apis import item_response, list_response, protect_route
from app.core.dto import QuestionAnswerDTO
......
......@@ -5,10 +5,10 @@ import app.database.controller as dbc
from app.apis import item_response, protect_route, text_response
from app.core import sockets
from app.core.codes import verify_code
from app.core.dto import AuthDTO, CodeDTO
from flask_jwt_extended import (create_access_token, create_refresh_token,
get_jwt_identity, get_raw_jwt,
jwt_refresh_token_required)
from app.core.dto import AuthDTO
from app.database.models import Whitelist
from flask_jwt_extended import create_access_token, get_jti, get_raw_jwt
from flask_jwt_extended.utils import get_jti
from flask_restx import Resource, inputs, reqparse
api = AuthDTO.api
......@@ -32,7 +32,12 @@ def get_user_claims(item_user):
def get_code_claims(item_code):
return {"view": item_code.view_type.name, "competition_id": item_code.competition_id, "team_id": item_code.team_id, "code": item_code.code}
return {
"view": item_code.view_type.name,
"competition_id": item_code.competition_id,
"team_id": item_code.team_id,
"code": item_code.code,
}
@api.route("/test")
......@@ -56,18 +61,16 @@ class AuthSignup(Resource):
return item_response(schema.dump(item_user))
@api.route("/delete/<ID>")
@api.param("ID")
@api.route("/delete/<user_id>")
@api.param("user_id")
class AuthDelete(Resource):
@protect_route(allowed_roles=["Admin"])
def delete(self, ID):
item_user = dbc.get.user(ID)
def delete(self, user_id):
item_user = dbc.get.user(user_id)
dbc.delete.whitelist_to_blacklist(Whitelist.user_id == user_id)
dbc.delete.default(item_user)
if int(ID) == get_jwt_identity():
jti = get_raw_jwt()["jti"]
dbc.add.blacklist(jti)
return text_response(f"User {ID} deleted")
return text_response(f"User {user_id} deleted")
@api.route("/login")
......@@ -82,9 +85,10 @@ class AuthLogin(Resource):
api.abort(codes.UNAUTHORIZED, "Invalid email or password")
access_token = create_access_token(item_user.id, user_claims=get_user_claims(item_user))
refresh_token = create_refresh_token(item_user.id)
# refresh_token = create_refresh_token(item_user.id)
response = {"id": item_user.id, "access_token": access_token, "refresh_token": refresh_token}
response = {"id": item_user.id, "access_token": access_token}
dbc.add.whitelist(get_jti(access_token), item_user.id)
return response
......@@ -98,7 +102,7 @@ class AuthLoginCode(Resource):
api.abort(codes.UNAUTHORIZED, "Invalid code")
item_code = dbc.get.code_by_code(code)
if item_code.view_type_id != 4:
if item_code.competition_id not in sockets.presentations:
api.abort(codes.UNAUTHORIZED, "Competition not active")
......@@ -107,6 +111,7 @@ class AuthLoginCode(Resource):
item_code.id, user_claims=get_code_claims(item_code), expires_delta=timedelta(hours=8)
)
dbc.add.whitelist(get_jti(access_token), competition_id=item_code.competition_id)
response = {
"competition_id": item_code.competition_id,
"view": item_code.view_type.name,
......@@ -122,9 +127,12 @@ class AuthLogout(Resource):
def post(self):
jti = get_raw_jwt()["jti"]
dbc.add.blacklist(jti)
Whitelist.query.filter(Whitelist.jti == jti).delete()
dbc.utils.commit()
return text_response("Logout")
"""
@api.route("/refresh")
class AuthRefresh(Resource):
@protect_route(allowed_roles=["*"])
......@@ -137,3 +145,4 @@ class AuthRefresh(Resource):
dbc.add.blacklist(old_jti)
response = {"access_token": access_token}
return response
"""
import app.database.controller as dbc
from app.apis import item_response, list_response, protect_route
from app.core import http_codes as codes
from app.core.dto import CodeDTO
from app.database.models import Code
from flask_restx import Resource
......
import time
import app.database.controller as dbc
from app.apis import item_response, list_response, protect_route
from app.core.dto import CompetitionDTO
......
......@@ -2,7 +2,7 @@
The core submodule contains everything important to the server that doesn't
fit neatly in either apis or database.
"""
import app.database.models as models
from app.database import Base, ExtendedQuery
from flask_bcrypt import Bcrypt
from flask_jwt_extended.jwt_manager import JWTManager
......@@ -13,3 +13,9 @@ db = SQLAlchemy(model_class=Base, query_class=ExtendedQuery)
bcrypt = Bcrypt()
jwt = JWTManager()
ma = Marshmallow()
@jwt.token_in_blacklist_loader
def check_if_token_in_blacklist(decrypted_token):
jti = decrypted_token["jti"]
return models.Blacklist.query.filter_by(jti=jti).first() is not None
......@@ -4,7 +4,6 @@ Contains all functions purely related to creating and verifying a code.
import random
import re
import string
CODE_LENGTH = 6
ALLOWED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
......
......@@ -2,10 +2,9 @@
Contains functions related to file handling, mainly saving and deleting images.
"""
from PIL import Image, ImageChops
from PIL import Image
from flask import current_app, has_app_context
import os
import datetime
from flask_uploads import IMAGES, UploadSet
if has_app_context():
......
......@@ -2,7 +2,7 @@
This module contains the parsers used to parse the data gotten in api requests.
"""
from flask_restx import inputs, reqparse
from flask_restx import reqparse
class Sentinel:
......
......@@ -3,8 +3,6 @@ This module contains schemas used to convert database objects into
dictionaries.
"""
from marshmallow.decorators import pre_load
from marshmallow.decorators import pre_dump, post_dump
import app.database.models as models
from app.core import ma
from marshmallow_sqlalchemy import fields
......
......@@ -6,9 +6,8 @@ connected to the same presentation.
import logging
from typing import Dict
import app.database.controller as dbc
from app.core import db
from app.database.models import Code, Competition, Slide, Team, ViewType
from app.database.models import Code, Slide, ViewType
from flask.globals import request
from flask_jwt_extended import verify_jwt_in_request
from flask_jwt_extended.utils import get_jwt_claims
......
......@@ -3,15 +3,11 @@ The database submodule contaisn all functionality that has to do with the
database. It can add, get, delete, edit, search and copy items.
"""
import json
from flask_restx import abort
from flask_sqlalchemy import BaseQuery
from flask_sqlalchemy.model import Model
from sqlalchemy import Column, DateTime, Text
from sqlalchemy import Column, DateTime
from sqlalchemy.sql import func
from sqlalchemy.types import TypeDecorator
from sqlalchemy import event
class Base(Model):
......
......@@ -6,13 +6,12 @@ import os
import app.core.http_codes as codes
from app.core import db
from app.database.controller import get, search, utils
from app.database.controller import get, utils
from app.database.models import (
Blacklist,
City,
Code,
Competition,
Component,
ComponentType,
ImageComponent,
Media,
......@@ -28,14 +27,12 @@ from app.database.models import (
TextComponent,
User,
ViewType,
Whitelist,
)
from flask.globals import current_app
from flask_restx import abort
from PIL import Image
from sqlalchemy import exc
from sqlalchemy.orm import with_polymorphic
from sqlalchemy.orm import relation
from sqlalchemy.orm.session import sessionmaker
from flask import current_app
from app.database.types import ID_IMAGE_COMPONENT, ID_QUESTION_COMPONENT, ID_TEXT_COMPONENT
......@@ -197,6 +194,12 @@ def blacklist(jti):
return db_add(Blacklist(jti))
def whitelist(jti, user_id=None, competition_id=None):
""" Adds a whitelist to the database. """
return db_add(Whitelist(jti, user_id, competition_id))
def mediaType(name):
""" Adds a media type to the database. """
......
......@@ -5,9 +5,8 @@ This file contains functionality to delete data to the database.
import app.core.http_codes as codes
import app.database.controller as dbc
from app.core import db
from app.database.models import Blacklist, City, Competition, Role, Slide, User
from app.database.models import Whitelist
from flask_restx import abort
from sqlalchemy import exc
def default(item):
......@@ -20,6 +19,19 @@ def default(item):
abort(codes.INTERNAL_SERVER_ERROR, f"Item of type {type(item)} could not be deleted")
def whitelist_to_blacklist(filters):
"""
Remove whitelist by condition(filters) and insert those into blacklist
Example: When delete user all whitelisted tokens for that user should be blacklisted
"""
whitelist = Whitelist.query.filter(filters).all()
for item in whitelist:
dbc.add.blacklist(item.jti)
Whitelist.query.filter(filters).delete()
dbc.utils.commit()
def component(item_component):
""" Deletes component. """
......
......@@ -27,17 +27,19 @@ def all(db_type):
return db_type.query.all()
def one(db_type, id):
def one(db_type, id, required=True):
""" Get lazy db-item in the table that has the same id. """
return db_type.query.filter(db_type.id == id).first_extended()
return db_type.query.filter(db_type.id == id).first_extended(required=required)
### Codes ###
def code_by_code(code):
""" Gets the code object associated with the provided code. """
return Code.query.filter(Code.code == code.upper()).first_extended( True, "A presentation with that code does not exist")
return Code.query.filter(Code.code == code.upper()).first_extended(
True, "A presentation with that code does not exist"
)
def code_list(competition_id):
......
......@@ -2,7 +2,7 @@
This file contains functionality to find data to the database.
"""
from app.database.models import Competition, Media, Question, Slide, Team, User
from app.database.models import Competition, Media, Question, Slide, User
def image(filename, page=0, page_size=15, order=1, order_by=None):
......
......@@ -7,7 +7,6 @@ from app.core import db
from app.core.codes import generate_code_string
from app.database.models import Code
from flask_restx import abort
from sqlalchemy import exc
def move_slides(item_competition, start_order, end_order):
......
......@@ -12,10 +12,21 @@ from app.database.types import ID_IMAGE_COMPONENT, ID_QUESTION_COMPONENT, ID_TEX
STRING_SIZE = 254
class Whitelist(db.Model):
id = db.Column(db.Integer, primary_key=True)
jti = db.Column(db.String, unique=True)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
competition_id = db.Column(db.Integer, db.ForeignKey("competition.id"), nullable=True)
def __init__(self, jti, user_id=None, competition_id=None):
self.jti = jti
self.user_id = user_id
self.competition_id = competition_id
class Blacklist(db.Model):
id = db.Column(db.Integer, primary_key=True)
jti = db.Column(db.String, unique=True)
expire_date = db.Column(db.Integer, nullable=True)
def __init__(self, jti):
self.jti = jti
......
......@@ -12,7 +12,7 @@ class Config:
JWT_BLACKLIST_ENABLED = True
JWT_BLACKLIST_TOKEN_CHECKS = ["access", "refresh"]
JWT_ACCESS_TOKEN_EXPIRES = timedelta(days=2)
JWT_REFRESH_TOKEN_EXPIRES = timedelta(days=30)
# JWT_REFRESH_TOKEN_EXPIRES = timedelta(days=30)
UPLOADED_PHOTOS_DEST = os.path.join(os.getcwd(), "app", "static", "images")
THUMBNAIL_SIZE = (120, 120)
SECRET_KEY = os.urandom(24)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment