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

Restrict Audit Log Button Visibility #1228

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Bugfixes
* The UI footer now stays at the bottom even on pages with little content [see `PR #1204 <https://github.com/FlexMeasures/flexmeasures/pull/1204>`_]
* Correct stroke dash (based on source type) for forecasts made by forecasters included in FlexMeasures [see `PR #1211 <https://www.github.com/FlexMeasures/flexmeasures/pull/1211>`_]
* Show the correct UTC offset for the data's time span as shown under sensor stats in the UI [see `PR #1213 <https://github.com/FlexMeasures/flexmeasures/pull/1213>`_]
* Fixed issue where audit log buttons are visible to users without the necessary permissions. [see `PR #1228 <https://github.com/FlexMeasures/flexmeasures/pull/1228>`_]
* Fix issue with displaying ``deactivate user`` and ``reset password`` buttons for non admin users [see `PR #1220 <https://github.com/FlexMeasures/flexmeasures/pull/1220>`_]


Expand Down
23 changes: 17 additions & 6 deletions flexmeasures/ui/crud/accounts.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from __future__ import annotations

from sqlalchemy import select
from werkzeug.exceptions import Forbidden, Unauthorized
from flask import request, url_for
from flask_classful import FlaskView
from flask_security import login_required
from flask_security.core import current_user

from flexmeasures.auth.policy import user_has_admin_access
from flexmeasures.auth.policy import user_has_admin_access, check_access

from flexmeasures.ui.crud.api_wrapper import InternalApi
from flexmeasures.ui.utils.view_utils import render_flexmeasures_template
from flexmeasures.data.models.audit_log import AuditLog
from flexmeasures.data.models.user import Account
from flexmeasures.data import db

Expand Down Expand Up @@ -45,29 +47,38 @@ def index(self):
def get(self, account_id: str):
"""/accounts/<account_id>"""
include_inactive = request.args.get("include_inactive", "0") != "0"
account = get_account(account_id)
if account["consultancy_account_id"]:
account = db.session.execute(select(Account).filter_by(id=account_id)).scalar()
if account.consultancy_account_id:
consultancy_account = db.session.execute(
select(Account).filter_by(id=account["consultancy_account_id"])
select(Account).filter_by(id=account.consultancy_account_id)
).scalar_one_or_none()
if consultancy_account:
account["consultancy_account_name"] = consultancy_account.name
account.consultancy_account.name = consultancy_account.name
accounts = get_accounts() if user_has_admin_access(current_user, "read") else []

user_can_view_account_auditlog = True
try:
check_access(AuditLog.account_table_acl(account), "read")
except (Forbidden, Unauthorized):
user_can_view_account_auditlog = False

return render_flexmeasures_template(
"crud/account.html",
account=account,
accounts=accounts,
include_inactive=include_inactive,
can_view_account_auditlog=user_can_view_account_auditlog,
)

@login_required
def auditlog(self, account_id: str):
"""/accounts/auditlog/<account_id>"""
account = get_account(account_id)
account = db.session.execute(select(Account).filter_by(id=account_id)).scalar()
audit_log_response = InternalApi().get(
url_for("AccountAPI:auditlog", id=account_id)
)
audit_logs_response = audit_log_response.json()

return render_flexmeasures_template(
"crud/account_audit_log.html",
audit_logs=audit_logs_response,
Expand Down
14 changes: 13 additions & 1 deletion flexmeasures/ui/crud/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@

from flask import request, url_for
from flask_classful import FlaskView
from flask_security.core import current_user
from flask_security import login_required
from flask_wtf import FlaskForm
from wtforms import StringField, FloatField, DateTimeField, BooleanField
from wtforms.validators import DataRequired
from werkzeug.exceptions import Forbidden, Unauthorized
from sqlalchemy import select

from flexmeasures.auth.policy import ADMIN_READER_ROLE, ADMIN_ROLE
from flexmeasures.auth.policy import ADMIN_READER_ROLE, ADMIN_ROLE, check_access
from flexmeasures.auth.decorators import roles_required, roles_accepted
from flexmeasures.data import db
from flexmeasures.data.models.audit_log import AuditLog
from flexmeasures.data.models.user import User, Role, Account
from flexmeasures.data.services.users import (
get_user,
Expand All @@ -38,8 +41,17 @@ class UserForm(FlaskForm):
def render_user(user: User | None, asset_count: int = 0, msg: str | None = None):
user_form = UserForm()
user_form.process(obj=user)

user_view_user_auditlog = True
try:
check_access(AuditLog.user_table_acl(current_user), "read")
except (Forbidden, Unauthorized):
user_view_user_auditlog = False

return render_flexmeasures_template(
"crud/user.html",
can_view_user_auditlog=user_view_user_auditlog,
logged_in_user=current_user,
user=user,
user_form=user_form,
asset_count=asset_count,
Expand Down
4 changes: 4 additions & 0 deletions flexmeasures/ui/templates/admin/logged_in_user.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,18 @@ <h2>User Overview</h2>
</div>
</div>
<div class="col-md-2">
{% if can_view_account_auditlog %}
<form action="/accounts/auditlog/{{ logged_in_user.account.id }}" method="get" class="bt-md-0 mb-3 mt-3">
<button class="btn btn-sm btn-responsive btn-info" type="submit"
title="View history of account actions.">Account audit log</button>
</form>
{% endif %}
{% if can_view_user_auditlog %}
<form action="/users/auditlog/{{ logged_in_user.id }}" method="get" class="mb-md-0 mb-3 mt-3">
<button class="btn btn-sm btn-responsive btn-info" type="submit"
title="View history of user actions.">User audit log</button>
</form>
{% endif %}
</div>

</div>
Expand Down
3 changes: 3 additions & 0 deletions flexmeasures/ui/templates/crud/account.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Account overview {% endblock %} {% block divs %}

<div class="pl-3">
{% if can_view_account_auditlog %}
<form action="/accounts/auditlog/{{ account.id }}" method="get">
<button
class="btn btn-sm btn-responsive btn-info m-4"
Expand All @@ -11,6 +12,8 @@
Audit log
</button>
</form>
{% endif %}

</div>
<div class="container-fluid">
<div class="row">
Expand Down
9 changes: 8 additions & 1 deletion flexmeasures/ui/templates/crud/user.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,14 @@ <h2>User overview</h2>
</div>
</div>
</div>
<div class="col-md-2"></div>
<div class="col-md-2">
{% if can_view_user_auditlog %}
<form action="/users/auditlog/{{ logged_in_user.id }}" method="get" class="mb-md-0 mb-3 mt-3">
<button class="btn btn-sm btn-responsive btn-info" type="submit"
title="View history of user actions.">User audit log</button>
</form>
{% endif %}
</div>
</div>
</div>

Expand Down
24 changes: 24 additions & 0 deletions flexmeasures/ui/views/logged_in_user.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from sqlalchemy import select
from werkzeug.exceptions import Forbidden, Unauthorized
from flask_security.core import current_user
from flask_security import login_required

from flexmeasures.auth.policy import check_access

from flexmeasures.data import db
from flexmeasures.data.models.audit_log import AuditLog
from flexmeasures.data.models.user import Account
from flexmeasures.ui.views import flexmeasures_ui
from flexmeasures.data.services.accounts import (
get_number_of_assets_in_account,
Expand All @@ -18,11 +25,28 @@ def logged_in_user_view():
"""
account_roles = get_account_roles(current_user.account_id)
account_role_names = [account_role.name for account_role in account_roles]
account = db.session.execute(
select(Account).filter_by(id=current_user.account_id)
).scalar()

user_can_view_account_auditlog = True
try:
joshuaunity marked this conversation as resolved.
Show resolved Hide resolved
check_access(AuditLog.account_table_acl(account), "read")
except (Forbidden, Unauthorized):
user_can_view_account_auditlog = False

user_view_user_auditlog = True
try:
check_access(AuditLog.user_table_acl(current_user), "read")
except (Forbidden, Unauthorized):
user_view_user_auditlog = False

return render_flexmeasures_template(
"admin/logged_in_user.html",
logged_in_user=current_user,
roles=",".join([role.name for role in current_user.roles]),
num_assets=get_number_of_assets_in_account(current_user.account_id),
account_role_names=account_role_names,
can_view_account_auditlog=user_can_view_account_auditlog,
can_view_user_auditlog=user_view_user_auditlog,
)
Loading