Skip to content
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
7 changes: 2 additions & 5 deletions config.example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ class Config:
FLOWSPEC6_MAX_RULES = 9000
RTBH_MAX_RULES = 100000

# Flask debugging
DEBUG = True
# Flask testing
TESTING = False

# Choose your authentication method and set it to True here or
# the production / development config
# SSO auth enabled
Expand Down Expand Up @@ -104,6 +99,8 @@ class DevelopmentConfig(Config):
SQLALCHEMY_DATABASE_URI = "Your Local Database URI"
LOCAL_IP = "127.0.0.1"
LOCAL_IP6 = "::ffff:127.0.0.1"

# Debug and Devel mode enabled
DEBUG = True
DEVEL = True

Expand Down
2 changes: 1 addition & 1 deletion flowapp/__about__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.1.9"
__version__ = "1.2.0"
__title__ = "ExaFS"
__description__ = "Tool for creation, validation, and execution of ExaBGP messages."
__author__ = "CESNET / Jiri Vrany, Petr Adamec, Josef Verich, Jakub Man"
Expand Down
11 changes: 7 additions & 4 deletions flowapp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import os
from flask import Flask, redirect, render_template, session, url_for
from flask import Flask, redirect, render_template, session, url_for, flash

from flask_sso import SSO
from flask_sqlalchemy import SQLAlchemy
Expand Down Expand Up @@ -128,11 +127,15 @@ def select_org(org_id=None):
user = db.session.query(models.User).filter_by(uuid=uuid).first()

if user is None:
return render_template("errors/404.html"), 404 # Handle missing user gracefully
return render_template("errors/404.html"), 404

orgs = user.organization
if org_id:
org = db.session.query(models.Organization).filter_by(id=org_id).first()
# Verify user belongs to this organization
org = user.organization.filter_by(id=org_id).first()
if not org:
flash("You don't have access to this organization", "alert-danger")
return redirect(url_for("index"))
session["user_org_id"] = org.id
session["user_org"] = org.name
return redirect("/")
Expand Down
4 changes: 3 additions & 1 deletion flowapp/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ def decorated(*args, **kwargs):
def user_or_admin_required(f):
"""
decorator for admin/user endpoints
Allows access if the user has at least one role with ID > 1 (user or admin)
Role IDs: 1=view (read-only), 2=user (can create/edit), 3=admin
"""

@wraps(f)
def decorated(*args, **kwargs):
if not all(i > 1 for i in session["user_role_ids"]):
if not any(i > 1 for i in session["user_role_ids"]):
return redirect(url_for("index"))
return f(*args, **kwargs)

Expand Down
4 changes: 2 additions & 2 deletions flowapp/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
MAX_PORT = 65535
MAX_PACKET = 9216

IPV6_NEXT_HEADER = {"tcp": "tcp", "udp": "udp", "icmp": "58", "all": ""}
IPV6_NEXT_HEADER = {"tcp": "tcp", "udp": "udp", "icmp": "58", "gre": "gre", "all": ""}

IPV4_PROTOCOL = {"tcp": "tcp", "udp": "udp", "icmp": "icmp", "all": ""}
IPV4_PROTOCOL = {"tcp": "tcp", "udp": "udp", "icmp": "icmp", "gre": "gre", "all": ""}

IPV4_FRAGMENT = {
"dont": "dont-fragment",
Expand Down
8 changes: 7 additions & 1 deletion flowapp/instance_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,14 @@ class InstanceConfig:
"divide_before": True,
},
{"name": "Add action", "url": "admin.action"},
{"name": "RTBH Communities", "url": "admin.communities"},
{
"name": "RTBH Communities",
"url": "admin.communities",
"divide_before": True,
},
{"name": "Add RTBH Comm.", "url": "admin.community"},
{"name": "AS Paths", "url": "admin.as_paths"},
{"name": "Add AS Path", "url": "admin.as_path"},
],
}
DASHBOARD = {
Expand Down
40 changes: 26 additions & 14 deletions flowapp/templates/macros.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('rules.reactivate_rule', rule_type=rtype_int, rule_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="set expiration">
<i class="bi bi-clock table-icon"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('rules.delete_rule', rule_type=rtype_int, rule_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="delete">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('rules.delete_rule', rule_type=rtype_int, rule_id=rule.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this rule?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="delete">
<i class="bi bi-x-lg"></i>
</button>
</form>
{% endif %}
{% if rule.comment %}
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ rule.comment }}">
Expand Down Expand Up @@ -108,14 +111,20 @@
<a class="btn btn-info btn-sm" href="{{ url_for('rules.reactivate_rule', rule_type=1, rule_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="set expiration">
<i class="bi bi-clock table-icon"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('rules.delete_rule', rule_type=1, rule_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="delete">
<i class="bi bi-x-lg"></i>
</a>
{% if rule.community.id in allowed_communities %}
<a class="btn btn-success btn-sm" href="{{ url_for('rules.delete_and_whitelist', rule_type=1, rule_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="whitelist and delete">
<i class="bi bi-shield-x"></i>
</a>
{% endif %}
<form method="POST" action="{{ url_for('rules.delete_rule', rule_type=1, rule_id=rule.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this rule?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="delete">
<i class="bi bi-x-lg"></i>
</button>
</form>
{% if rule.community.id in allowed_communities %}
<form method="POST" action="{{ url_for('rules.delete_and_whitelist', rule_type=1, rule_id=rule.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to whitelist and delete this rule?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-success btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="whitelist and delete">
<i class="bi bi-shield-x"></i>
</button>
</form>
{% endif %}
{% endif %}
{% if rule.comment %}
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ rule.comment }}">
Expand Down Expand Up @@ -153,9 +162,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('whitelist.reactivate', wl_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="set expiration">
<i class="bi bi-clock table-icon"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('whitelist.delete', wl_id=rule.id) }}" role="button" data-bs-toggle="tooltip" data-bs-placement="top" title="delete">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('whitelist.delete', wl_id=rule.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this whitelist?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="delete">
<i class="bi bi-x-lg"></i>
</button>
</form>
{% endif %}
{% if rule.comment %}
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ rule.comment }}">
Expand Down
9 changes: 6 additions & 3 deletions flowapp/templates/pages/actions.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('admin.edit_action', action_id=action.id) }}" role="button">
<i class="bi bi-pen"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_action', action_id=action.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('admin.delete_action', action_id=action.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this action?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-x-lg"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
Expand Down
9 changes: 6 additions & 3 deletions flowapp/templates/pages/as_paths.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('admin.edit_as_path', path_id=pth.id) }}" role="button">
<i class="bi bi-pen"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_as_path', path_id=pth.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('admin.delete_as_path', path_id=pth.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this AS path?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-x-lg"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
Expand Down
9 changes: 6 additions & 3 deletions flowapp/templates/pages/communities.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('admin.edit_community', community_id=community.id) }}" role="button">
<i class="bi bi-pen"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_community', community_id=community.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('admin.delete_community', community_id=community.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this community?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-x-lg"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
Expand Down
9 changes: 6 additions & 3 deletions flowapp/templates/pages/machine_api_key.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ <h1>Machines and ApiKeys</h1>
{% endif %}
</td>
<td>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_machine_key', key_id=row.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('admin.delete_machine_key', key_id=row.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this key?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-x-lg"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
Expand Down
9 changes: 6 additions & 3 deletions flowapp/templates/pages/orgs.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('admin.edit_organization', org_id=org.id) }}" role="button">
<i class="bi bi-pen"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_organization', org_id=org.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('admin.delete_organization', org_id=org.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this organization?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-x-lg"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
Expand Down
9 changes: 6 additions & 3 deletions flowapp/templates/pages/users.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@
<a class="btn btn-info btn-sm" href="{{ url_for('admin.edit_user', user_id=user.id) }}" role="button">
<i class="bi bi-pen"></i>
</a>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_user', user_id=user.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
<form method="POST" action="{{ url_for('admin.delete_user', user_id=user.id) }}" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this user?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-x-lg"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
Expand Down
6 changes: 0 additions & 6 deletions flowapp/utils/app_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,13 @@ def ext_login():

@app.route("/local-login")
def local_login():
print("Local login started")
if not app.config.get("LOCAL_AUTH", False):
print("Local auth not enabled")
return render_template("errors/401.html")

uuid = app.config.get("LOCAL_USER_UUID", False)
if not uuid:
print("Local user not set")
return render_template("errors/401.html")

print(f"Local login with {uuid}")
return _handle_login(uuid, app)

return app
Expand Down Expand Up @@ -211,9 +207,7 @@ def _register_user_to_session(uuid, db):
"""Register user information to session."""
from flowapp.models import User

print(f"Registering user {uuid} to session")
user = db.session.query(User).filter_by(uuid=uuid).first()
print(f"Got user {user} from DB")
session["user_uuid"] = user.uuid
session["user_email"] = user.uuid
session["user_name"] = user.name
Expand Down
27 changes: 21 additions & 6 deletions flowapp/views/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def add_machine_key():
return render_template("forms/machine_api_key.html", form=form, generated_key=generated)


@admin.route("/delete_machine_key/<int:key_id>", methods=["GET"])
@admin.route("/delete_machine_key/<int:key_id>", methods=["POST"])
@auth_required
@admin_required
def delete_machine_key(key_id):
Expand All @@ -113,6 +113,9 @@ def delete_machine_key(key_id):
:param key_id: integer
"""
model = db.session.get(MachineApiKey, key_id)
if not model:
flash("Key not found", "alert-danger")
return redirect(url_for("admin.machine_keys"))
# delete from db
db.session.delete(model)
db.session.commit()
Expand Down Expand Up @@ -181,7 +184,7 @@ def edit_user(user_id):
)


@admin.route("/user/delete/<int:user_id>", methods=["GET"])
@admin.route("/user/delete/<int:user_id>", methods=["POST"])
@auth_required
@admin_required
def delete_user(user_id):
Expand Down Expand Up @@ -387,11 +390,14 @@ def edit_organization(org_id):
)


@admin.route("/organization/delete/<int:org_id>", methods=["GET"])
@admin.route("/organization/delete/<int:org_id>", methods=["POST"])
@auth_required
@admin_required
def delete_organization(org_id):
org = db.session.get(Organization, org_id)
if not org:
flash("Organization not found", "alert-danger")
return redirect(url_for("admin.organizations"))
aname = org.name
db.session.delete(org)
message = "Organization {} deleted".format(aname)
Expand Down Expand Up @@ -465,11 +471,14 @@ def edit_as_path(path_id):
)


@admin.route("/as-path/delete/<int:path_id>", methods=["GET"])
@admin.route("/as-path/delete/<int:path_id>", methods=["POST"])
@auth_required
@admin_required
def delete_as_path(path_id):
pth = db.session.get(ASPath, path_id)
if not pth:
flash("AS path not found", "alert-danger")
return redirect(url_for("admin.as_paths"))
db.session.delete(pth)
message = f"AS path {pth.prefix} : {pth.as_path} deleted"
alert_type = "alert-success"
Expand Down Expand Up @@ -544,11 +553,14 @@ def edit_action(action_id):
)


@admin.route("/action/delete/<int:action_id>", methods=["GET"])
@admin.route("/action/delete/<int:action_id>", methods=["POST"])
@auth_required
@admin_required
def delete_action(action_id):
action = db.session.get(Action, action_id)
if not action:
flash("Action not found", "alert-danger")
return redirect(url_for("admin.actions"))
aname = action.name
db.session.delete(action)

Expand Down Expand Up @@ -628,11 +640,14 @@ def edit_community(community_id):
)


@admin.route("/community/delete/<int:community_id>", methods=["GET"])
@admin.route("/community/delete/<int:community_id>", methods=["POST"])
@auth_required
@admin_required
def delete_community(community_id):
community = db.session.get(Community, community_id)
if not community:
flash("Community not found", "alert-danger")
return redirect(url_for("admin.communities"))
aname = community.name
db.session.delete(community)
message = "Community {} deleted".format(aname)
Expand Down
Loading