-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Organizations: show audit logs #8588
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
Changes from 10 commits
5bd1f63
31d2e66
5c4a3a9
56b8129
f06ad81
2a63958
f97970c
6075b57
10ddab7
7ab1acc
60ffb95
47b7cb9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
Security Log | ||
============ | ||
|
||
Security logs allow you to see what has happened recently in your organization or account. | ||
We store the IP address and the browser's User-Agent_ on each event, | ||
so that you can confirm this access was from the intended person. | ||
|
||
.. _User-Agent: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent | ||
|
||
User security log | ||
----------------- | ||
|
||
We store user security logs from the last 90 days, and track the following events: | ||
|
||
- Authentication on the dashboard | ||
- Authentication on documentation pages (:doc:`/commercial/index` only) | ||
|
||
Authentication failures and successes are both tracked. | ||
|
||
To access your logs: | ||
|
||
- Click on :guilabel:`Username` dropdown | ||
- Click on :guilabel:`Settings` | ||
- Click on :guilabel:`Security Log` | ||
|
||
Organization security log | ||
------------------------- | ||
|
||
.. note:: | ||
|
||
This feature exists only on :doc:`/commercial/index`. | ||
|
||
We store logs according to your plan, | ||
check our `pricing page <https://readthedocs.com/pricing/>`__ for more details. | ||
We track the following events: | ||
|
||
- Authentication on documentation pages from your organization | ||
- User access to every documentation page from your organization (**Enterprise plans only**) | ||
|
||
Authentication failures and successes are both tracked. | ||
|
||
To access your organization logs: | ||
|
||
- Click on :guilabel:`Organizations` from your user dropdown | ||
- Click on your organization | ||
- Click on :guilabel:`Settings` | ||
- Click on :guilabel:`Security Log` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,12 @@ | ||
"""Filters used in our views.""" | ||
|
||
from django.utils.translation import ugettext_lazy as _ | ||
from django_filters import CharFilter, ChoiceFilter, FilterSet | ||
from django_filters import ( | ||
CharFilter, | ||
ChoiceFilter, | ||
DateFromToRangeFilter, | ||
FilterSet, | ||
) | ||
|
||
from readthedocs.audit.models import AuditLog | ||
|
||
|
@@ -18,7 +23,23 @@ class UserSecurityLogFilter(FilterSet): | |
(AuditLog.AUTHN_FAILURE, _('Authentication failure')), | ||
], | ||
) | ||
date = DateFromToRangeFilter(field_name='created') | ||
|
||
class Meta: | ||
model = AuditLog | ||
fields = ['ip', 'project', 'action'] | ||
fields = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this wasn't needed, as these values are defined as attributes, but you still need to declare |
||
|
||
|
||
class OrganizationSecurityLogFilter(UserSecurityLogFilter): | ||
|
||
action = ChoiceFilter( | ||
field_name='action', | ||
lookup_expr='exact', | ||
choices=[ | ||
(AuditLog.AUTHN, _('Authentication success')), | ||
(AuditLog.AUTHN_FAILURE, _('Authentication failure')), | ||
(AuditLog.PAGEVIEW, _('Page view')), | ||
(AuditLog.DOWNLOAD, _('Download')), | ||
], | ||
) | ||
user = CharFilter(field_name='log_user_username', lookup_expr='exact') | ||
stsewd marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
{% load i18n %} | ||
|
||
{% comment %} | ||
If `omit_user` is given, the username attached to the log isn't shown. | ||
This is useful when listing logs for the same user. | ||
{% endcomment %} | ||
|
||
<div class="module-list"> | ||
<div class="module-list-wrapper"> | ||
<ul> | ||
{% for log in object_list %} | ||
<li class="module-item"> | ||
{% if log.action == AuditLog.AUTHN %} | ||
{% if omit_user %} | ||
{% blocktrans trimmed with action=log.action method=log.auth_backend_display %} | ||
<a href="?action={{ action }}" title="{{ method }}">Authenticated</a> | ||
{% endblocktrans %} | ||
{% elif log.log_user_id %} | ||
{% blocktrans trimmed with action=log.action user=log.log_user_username method=log.auth_backend_display %} | ||
<a href="?user={{ user }}"> | ||
<code>{{ user }}</code> | ||
</a> | ||
<a href="?action={{ action }}" title="{{ method }}">authenticated</a> | ||
{% endblocktrans %} | ||
{% else %} | ||
{% blocktrans trimmed with action=log.action method=log.auth_backend_display %} | ||
User <a href="?action={{ action }}" title="{{ method }}">authenticated</a> | ||
{% endblocktrans %} | ||
{% endif %} | ||
{% elif log.action == AuditLog.AUTHN_FAILURE %} | ||
{% blocktrans trimmed with action=log.action method=log.auth_backend_display %} | ||
<a href="?action={{ action }}" title="{{ method }}">Authentication failed</a> | ||
{% endblocktrans %} | ||
{% elif log.action == AuditLog.PAGEVIEW %} | ||
{% if log.log_user_id %} | ||
{% blocktrans trimmed with action=log.action user=log.log_user_username path=log.resource %} | ||
<a href="?user={{ user }}"> | ||
<code>{{ user }}</code> | ||
</a> | ||
<a href="?action={{ action }}" title="{{ path }}">visited</a> a page | ||
{% endblocktrans %} | ||
{% else %} | ||
{% blocktrans trimmed with action=log.action user=log.log_user_username path=log.resource %} | ||
A user <a href="?action={{ action }}" title="{{ path }}">visited</a> a page | ||
{% endblocktrans %} | ||
{% endif %} | ||
{% elif log.action == AuditLog.DOWNLOAD %} | ||
{% if log.log_user_id %} | ||
{% blocktrans trimmed with action=log.action user=log.log_user_username path=log.resource %} | ||
<a href="?user={{ user }}"> | ||
<code>{{ user }}</code> | ||
</a> | ||
<a href="?action={{ action }}" title="{{ path }}">downloaded</a> a document | ||
{% endblocktrans %} | ||
{% else %} | ||
{% blocktrans trimmed with action=log.action user=log.log_user_username path=log.resource %} | ||
A user <a href="?action={{ action }}" title="{{ path }}">downloaded</a> a document | ||
{% endblocktrans %} | ||
{% endif %} | ||
{% endif %} | ||
|
||
{% trans "from" %} | ||
|
||
<a href="?ip={{ log.ip }}" title="{{ log.browser }}"> | ||
<code>{{ log.ip }}</code> | ||
</a> | ||
|
||
{# If the authentication was on a doc domain. #} | ||
{% if log.log_project_id %} | ||
{% trans "on" %} | ||
{% if log.project %} | ||
<a href="{% url 'projects_detail' log.log_project_slug %}"> | ||
<code>{{ log.log_project_slug }}</code> | ||
</a> | ||
{% else %} | ||
{# The original project has been deleted, don't link to it. #} | ||
<code title="{{ log.resource }}">{{ log.log_project_slug }}</code> | ||
{% endif %} | ||
{% endif %} | ||
|
||
<span class="quiet right" title="{{ log.created|date:"DATETIME_FORMAT" }}"> | ||
{% blocktrans trimmed with log.created|timesince as date %} | ||
{{ date }} ago | ||
{% endblocktrans %} | ||
</span> | ||
</li> | ||
{% empty %} | ||
<li class="module-item"> | ||
<p class="quiet"> | ||
{% trans 'No activity logged yet' %} | ||
</p> | ||
</li> | ||
{% endfor %} | ||
</ul> | ||
</div> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{% extends "organizations/admin/base.html" %} | ||
|
||
{% load i18n %} | ||
{% load pagination_tags %} | ||
|
||
{% block title %}{% trans "Organization Security Log" %}{% endblock %} | ||
|
||
{% block organization-admin-security-log %}active{% endblock %} | ||
|
||
{% block edit_content_header %} {% trans "Organization Security Log" %} {% endblock %} | ||
|
||
{% block edit_content %} | ||
|
||
{% if not enabled %} | ||
{% include 'projects/includes/feature_disabled.html' with organization=organization %} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be passing in something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could pass the feature type and check from the other template what plan is required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, not a huge priority though. 👍 |
||
{% endif %} | ||
|
||
<p class="help_text"> | ||
{% blocktrans trimmed with docs_url='https://docs.readthedocs.io/page/security-log.html#organization-security-log' %} | ||
The <a href="{{ docs_url }}">organization security log</a> allows you to see what has happened recently in your organization. | ||
{% endblocktrans %} | ||
|
||
{% if enabled %} | ||
{% if days_limit and days_limit > 0 %} | ||
{% blocktrans trimmed with days_limit=days_limit %} | ||
Showing logs from the last {{ days_limit }} days. | ||
You can upgrade your plan to increase the time period that is stored. | ||
{% endblocktrans %} | ||
{% else %} | ||
{% trans "Showing logs from all time." %} | ||
{% endif %} | ||
{% endif %} | ||
</p> | ||
|
||
{% autopaginate object_list 15 %} | ||
|
||
<div class="module"> | ||
<div class="button-bar"> | ||
<ul> | ||
<li> | ||
<a class="button" | ||
href="?download=true&{{ request.GET.urlencode }}"> | ||
{% trans "Download" %} | ||
</a> | ||
</li> | ||
</ul> | ||
</div> | ||
|
||
{% include "audit/list_logs.html" with omit_user=False %} | ||
</div> | ||
{% paginate %} | ||
{% endblock %} |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this vary by plan on .com? If so, we should probably put this in a small table comparing each site. I dislike having the tabs where you have to click to see the Commercial one, so a small table seems best?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User securtiy logs are 90 days for both, we could respect the max period set by the organizations they belong on .com, but I have some questions if that happens, should we show those type of logs to org owners as well? #8620 (comment)