Skip to content

Commit

Permalink
Merge pull request #41 from CESNET/bugfix/session
Browse files Browse the repository at this point in the history
Bugfix/session
  • Loading branch information
jirivrany authored Sep 23, 2024
2 parents 52cae97 + 1da865d commit cc478f5
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 79 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ Last part of the system is Guarda service. This systemctl service is running in
* [Local database instalation notes](./docs/DB_LOCAL.md)

## Change Log
- 0.8.0 - API keys update. **Run migration scripts to update your DB**. Keys can now have expiration date and readonly flag. Admin can create special keys for certain machinnes.
- 0.8.1 application is using Flask-Session stored in DB using SQL Alchemy driver. This can be configured for other
drivers, however server side session is required for the application proper function.
- 0.8.0 - API keys update. **Run migration scripts to update your DB**. Keys can now have expiration date and readonly flag. Admin can create special keys for certain machines.
- 0.7.3 - New possibility of external auth proxy.
- 0.7.2 - Dashboard and Main menu are now customizable in config. App is ready to be packaged using setup.py.
- 0.7.0 - ExaAPI now have two options - HTTP or RabbitMQ. ExaAPI process has been renamed, update of ExaBGP process value is needed for this version.
Expand Down
2 changes: 1 addition & 1 deletion flowapp/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.8.0"
__version__ = "0.8.1"
34 changes: 18 additions & 16 deletions flowapp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
from flask_migrate import Migrate
from flask_session import Session

from .__about__ import __version__
from .instance_config import InstanceConfig
Expand All @@ -14,30 +15,34 @@
db = SQLAlchemy()
migrate = Migrate()
csrf = CSRFProtect()
ext = SSO()
sess = Session()


def create_app():
def create_app(config_object=None):
app = Flask(__name__)
# Map SSO attributes from ADFS to session keys under session['user']
#: Default attribute map

# SSO configuration
SSO_ATTRIBUTE_MAP = {
"eppn": (True, "eppn"),
"cn": (False, "cn"),
}
app.config.setdefault("SSO_ATTRIBUTE_MAP", SSO_ATTRIBUTE_MAP)
app.config.setdefault("SSO_LOGIN_URL", "/login")

# db.init_app(app)
# extension init
migrate.init_app(app, db)
csrf.init_app(app)

# Load the default configuration for dashboard and main menu
app.config.from_object(InstanceConfig)
if config_object:
app.config.from_object(config_object)

app.config.setdefault("VERSION", __version__)
app.config.setdefault("SSO_ATTRIBUTE_MAP", SSO_ATTRIBUTE_MAP)
app.config.setdefault("SSO_LOGIN_URL", "/login")

# This attaches the *flask_sso* login handler to the SSO_LOGIN_URL,
ext = SSO(app=app)
# Init SSO
ext.init_app(app)

from flowapp import models, constants, validators
from .views.admin import admin
Expand Down Expand Up @@ -85,7 +90,7 @@ def logout():

@app.route("/ext-login")
def ext_login():
header_name = app.config.get("AUTH_HEADER_NAME", 'X-Authenticated-User')
header_name = app.config.get("AUTH_HEADER_NAME", "X-Authenticated-User")
if header_name not in request.headers:
return render_template("errors/401.html")

Expand Down Expand Up @@ -148,9 +153,7 @@ def internal_error(exception):
def utility_processor():
def editable_rule(rule):
if rule:
validators.editable_range(
rule, models.get_user_nets(session["user_id"])
)
validators.editable_range(rule, models.get_user_nets(session["user_id"]))
return True
return False

Expand All @@ -176,20 +179,19 @@ def inject_dashboard():
def format_datetime(value):
if value is None:
return app.config.get("MISSING_DATETIME_MESSAGE", "Never")

format = "y/MM/dd HH:mm"
return babel.dates.format_datetime(value, format)

def _register_user_to_session(uuid: str):
print(f"Registering user {uuid} to session")
user = db.session.query(models.User).filter_by(uuid=uuid).first()
session["user_uuid"] = user.uuid
session["user_email"] = user.uuid
session["user_name"] = user.name
session["user_id"] = user.id
session["user_roles"] = [role.name for role in user.role.all()]
session["user_orgs"] = ", ".join(
org.name for org in user.organization.all()
)
session["user_orgs"] = ", ".join(org.name for org in user.organization.all())
session["user_role_ids"] = [role.id for role in user.role.all()]
session["user_org_ids"] = [org.id for org in user.organization.all()]
roles = [i > 1 for i in session["user_role_ids"]]
Expand Down
51 changes: 12 additions & 39 deletions flowapp/views/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ def reactivate_rule(rule_type, rule_id):
form.net_ranges = get_user_nets(session["user_id"])

if rule_type > 2:
form.action.choices = [
(g.id, g.name) for g in db.session.query(Action).order_by("name")
]
form.action.choices = [(g.id, g.name) for g in db.session.query(Action).order_by("name")]
form.action.data = model.action_id

if rule_type == 1:
Expand Down Expand Up @@ -256,9 +254,7 @@ def group_delete():
"{} / {}".format(session["user_email"], session["user_orgs"]),
)

db.session.query(model_name).filter(model_name.id.in_(to_delete)).delete(
synchronize_session=False
)
db.session.query(model_name).filter(model_name.id.in_(to_delete)).delete(synchronize_session=False)
db.session.commit()

flash("Rules {} deleted".format(to_delete), "alert-success")
Expand Down Expand Up @@ -309,9 +305,7 @@ def group_update():
form = form_name(request.form)
form.net_ranges = get_user_nets(session["user_id"])
if rule_type_int > 2:
form.action.choices = [
(g.id, g.name) for g in db.session.query(Action).order_by("name")
]
form.action.choices = [(g.id, g.name) for g in db.session.query(Action).order_by("name")]
if rule_type_int == 1:
form.community.choices = get_user_communities(session["user_role_ids"])

Expand Down Expand Up @@ -429,9 +423,7 @@ def ipv4_rule():

if model:
model.expires = round_to_ten_minutes(form.expires.data)
flash_message = (
"Existing IPv4 Rule found. Expiration time was updated to new value."
)
flash_message = "Existing IPv4 Rule found. Expiration time was updated to new value."
else:
model = Flowspec4(
source=form.source.data,
Expand Down Expand Up @@ -473,17 +465,12 @@ def ipv4_rule():
else:
for field, errors in form.errors.items():
for error in errors:
print(
"Error in the %s field - %s"
% (getattr(form, field).label.text, error)
)
print("Error in the %s field - %s" % (getattr(form, field).label.text, error))

default_expires = datetime.now() + timedelta(days=7)
form.expires.data = default_expires

return render_template(
"forms/ipv4_rule.html", form=form, action_url=url_for("rules.ipv4_rule")
)
return render_template("forms/ipv4_rule.html", form=form, action_url=url_for("rules.ipv4_rule"))


@rules.route("/add_ipv6_rule", methods=["GET", "POST"])
Expand All @@ -507,9 +494,7 @@ def ipv6_rule():

if model:
model.expires = round_to_ten_minutes(form.expires.data)
flash_message = (
"Existing IPv4 Rule found. Expiration time was updated to new value."
)
flash_message = "Existing IPv4 Rule found. Expiration time was updated to new value."
else:
model = Flowspec6(
source=form.source.data,
Expand Down Expand Up @@ -550,17 +535,12 @@ def ipv6_rule():
else:
for field, errors in form.errors.items():
for error in errors:
print(
"Error in the %s field - %s"
% (getattr(form, field).label.text, error)
)
print("Error in the %s field - %s" % (getattr(form, field).label.text, error))

default_expires = datetime.now() + timedelta(days=7)
form.expires.data = default_expires

return render_template(
"forms/ipv6_rule.html", form=form, action_url=url_for("rules.ipv6_rule")
)
return render_template("forms/ipv6_rule.html", form=form, action_url=url_for("rules.ipv6_rule"))


@rules.route("/add_rtbh_rule", methods=["GET", "POST"])
Expand All @@ -586,9 +566,7 @@ def rtbh_rule():

if model:
model.expires = round_to_ten_minutes(form.expires.data)
flash_message = (
"Existing RTBH Rule found. Expiration time was updated to new value."
)
flash_message = "Existing RTBH Rule found. Expiration time was updated to new value."
else:
model = RTBH(
ipv4=form.ipv4.data,
Expand Down Expand Up @@ -622,17 +600,12 @@ def rtbh_rule():
else:
for field, errors in form.errors.items():
for error in errors:
print(
"Error in the %s field - %s"
% (getattr(form, field).label.text, error)
)
print("Error in the %s field - %s" % (getattr(form, field).label.text, error))

default_expires = datetime.now() + timedelta(days=7)
form.expires.data = default_expires

return render_template(
"forms/rtbh_rule.html", form=form, action_url=url_for("rules.rtbh_rule")
)
return render_template("forms/rtbh_rule.html", form=form, action_url=url_for("rules.rtbh_rule"))


@rules.route("/export")
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
Flask>=2.0.2
Flask<3
Flask-SQLAlchemy>=2.2
Flask-SSO>=0.4.0
Flask-WTF>=1.0.0
Flask-Migrate>=3.0.0
Flask-Script>=2.0.0
Flask-Session
PyJWT>=2.4.0
PyMySQL>=1.0.0
pytest>=7.0.0
requests>=2.20.0
babel>=2.7.0
mysqlclient>=2.0.0
email_validator>=1.1
pika>=1.3.0
mysqlclient>=2.0.0
42 changes: 22 additions & 20 deletions run.example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,42 @@
This is an example of how to run the application.
First copy the file as run.py (or whatever you want)
Then edit the file to match your needs.
From version 0.8.1 the application is using Flask-Session
stored in DB using SQL Alchemy driver. This can be configured for other
drivers, however server side session is required for the application.
In general you should not need to edit this example file.
Only if you want to configure the application main menu and
dashboard. Or in case that you want to add extensions etc.
dashboard.
Or in case that you want to add extensions etc.
"""

from os import environ

from flowapp import create_app, db
from flowapp import create_app, db, sess
import config


# Call app factory
app = create_app()

# Configurations
env = environ.get('EXAFS_ENV', 'Production')
env = environ.get("EXAFS_ENV", "Production")

if env == 'devel':
app.config.from_object(config.DevelopmentConfig)
app.config.update(
DEVEL=True
)
# Call app factory
if env == "devel":
app = create_app(config.DevelopmentConfig)
else:
app.config.from_object(config.ProductionConfig)
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
DEVEL=False
)
app = create_app(config.ProductionConfig)

# init database object
db.init_app(app)

# init session
app.config.update(SESSION_TYPE="sqlalchemy")
app.config.update(SESSION_SQLALCHEMY=db)
sess.init_app(app)


# run app
if __name__ == '__main__':
app.run(host='::', port=8080, debug=True)
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000, debug=True)

0 comments on commit cc478f5

Please sign in to comment.