Skip to content

Commit

Permalink
1.3.0 (#106)
Browse files Browse the repository at this point in the history
* Cleaned venv from useless packages (#103)

* Cleaned venv from useless packages

* Added pytz required in celery_beat

* fix

* Updated CHANGELOG.md

* Registered UserAdmin for authentication app in admin.py

* Configuration panel (#104)

* [refactor] Added enums in new costants.py file for "choices" fields in the models

* [refactor] Added default config values in the django settings (certego.py file)

* Added default configs in settings

* Updated CHANGELOG.md

* [test-view] Ignore alerts order for views return API

* Fixed linters paths

* Changed "null=True" to "blank=True" for Charfields

* changes for flake8 linter

* Revoed E231 flake8 rule for certego.py file

* removed comment

* Updated CHANGELOG.md

* [CI] Updated to compose v2

* fix

* Alerts fields utilities (#105)

* Added method to get the alert name label, for tagging

* Added ipython for develop

* Added new fields in login_raw_data for more info about previous login

* Updated CHANGELOG.md

* Version 1.3.0
  • Loading branch information
Lorygold authored Dec 17, 2024
1 parent 78d1bb3 commit 542727c
Show file tree
Hide file tree
Showing 26 changed files with 509 additions and 121 deletions.
4 changes: 2 additions & 2 deletions .github/actions/services/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ runs:
shell:
bash

- name: Execute docker-compose up
- name: Execute docker compose up
run: |
CLI=docker-compose
CLI="docker compose"
if [[ ${{ inputs.use_postgres }} != 'false' ]]; then
CLI="${CLI} -f postgres.yml"
fi
Expand Down
6 changes: 5 additions & 1 deletion .github/configurations/python_linters/.flake8
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ ignore =

exclude =
*/migrations/*,
Dockerfile
Dockerfile

per-file-ignores =
# imported but unused
certego.py: E231
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
## 1.3.x
### 1.3.0
#### Feature
* Added configuration panel in order to set custom preferences
* Added more fields in the Alert.login_raw_data dict in order to have more info about previous location for imp_travel detection
### Changes
* Set default settings values in the *settings.certego.py* file
* Moved Enums into *costants.py* file

## 1.2.x
### 1.2.12
#### Bugfix
* Cleaned venv from useless packages
* Added pytz in requirements because it's needed by celery_beat
* Registered UserAdmin in authentication
### 1.2.11
#### Bugfix
* Fixed the update of the login.updated field
* Added logging for the clear_models_periodically function
### 1.2.10
#### Changes
* Added settings into the Config model (instead of into the settings.py file)
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ How to create and submit a PR:
If you didn't install pre-commit, it is necessary to run linters manually:
* Flake8
```bash
flake8 . --show-source --config ../.github/configurations/.flake8
flake8 . --show-source --config ../.github/configurations/python_linters/.flake8
```
* Black
```bash
black --config ../.github/configurations/.black .
black --config ../.github/configurations/python_linters/.black .
```
* Isort
```bash
isort --sp ../.github/configurations/.isort.cfg --profile black .
isort --sp ../.github/configurations/python_linters/.isort.cfg --profile black .
```
3. **IF** your changes include differences in the template view, **include sceenshots of the before and after**.
Expand Down
8 changes: 7 additions & 1 deletion buffalogs/authentication/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
from django.contrib import admin

# Register your models here.
from .models import User


@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ("id", "username", "email", "is_staff", "is_verified", "created_at", "updated_at", "avatar")
search_fields = ("id", "username", "email", "avatar")
3 changes: 0 additions & 3 deletions buffalogs/authentication/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,3 @@ def __str__(self):
def tokens(self):
refresh = RefreshToken.for_user(self)
return {"refresh": str(refresh), "access": str(refresh.access_token)}


# Create your models here.
11 changes: 11 additions & 0 deletions buffalogs/buffalogs/settings/certego.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
CERTEGO_BUFFALOGS_POSTGRES_PORT = os.environ.get("BUFFALOGS_POSTGRES_PORT", "5432")
CERTEGO_BUFFALOGS_ELASTIC_INDEX = os.environ.get("BUFFALOGS_ELASTIC_INDEX", "weblog-*,cloud-*,fw-proxy-*,filebeat-*")
CERTEGO_BUFFALOGS_SECRET_KEY = os.environ.get("BUFFALOGS_SECRET_KEY", "django-insecure-am9z-fi-x*aqxlb-@abkhb@pu!0da%0a77h%-8d(dwzrrktwhu")
CERTEGO_BUFFALOGS_IGNORED_USERS = ["Not Available", "N/A"]
CERTEGO_BUFFALOGS_ENABLED_USERS = []
CERTEGO_BUFFALOGS_ALLOWED_COUNTRIES = []
CERTEGO_BUFFALOGS_IGNORED_IPS = ["127.0.0.1"]
CERTEGO_BUFFALOGS_VIP_USERS = []
CERTEGO_BUFFALOGS_DISTANCE_KM_ACCEPTED = 100
CERTEGO_BUFFALOGS_VEL_TRAVEL_ACCEPTED = 300
CERTEGO_BUFFALOGS_USER_MAX_DAYS = 60
CERTEGO_BUFFALOGS_LOGIN_MAX_DAYS = 30
CERTEGO_BUFFALOGS_ALERT_MAX_DAYS = 30
CERTEGO_BUFFALOGS_IP_MAX_DAYS = 30

if CERTEGO_BUFFALOGS_ENVIRONMENT == ENVIRONMENT_DOCKER:

Expand Down
Binary file modified buffalogs/celerybeat-schedule
Binary file not shown.
89 changes: 89 additions & 0 deletions buffalogs/impossible_travel/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from enum import Enum


class UserRiskScoreType(Enum):
"""Possible types of user risk scores, based on number of alerts that they have triggered
* No risk: the user has triggered 0 alerts
* Low: the user has triggered 1 or 2 alerts
* Medium: the user has triggered 3 or 4 alerts
* High: the user has triggered more than 4 alerts
"""

NO_RISK = "No risk"
LOW = "Low"
MEDIUM = "Medium"
HIGH = "High"

@classmethod
def choices(cls):
return tuple((i.name, i.value) for i in cls)

@classmethod
def get_risk_level(cls, value):
# map risk value
if value == 0:
return cls.NO_RISK.value
elif 1 <= value <= 2:
return cls.LOW.value
elif 3 <= value <= 4:
return cls.MEDIUM.value
elif value >= 5:
return cls.HIGH.value
else:
raise ValueError("Risk value not valid")


class AlertDetectionType(Enum):
"""Types of possible alert detections
* NEW_DEVICE: Login from a new user-agent used by the user
* IMP_TRAVEL: Alert if the user logs into the system from a significant distance () within a range of time that cannot be covered by conventional means of transport
* NEW_COUNTRY: The user made a login from a country where they have never logged in before
* USER_RISK_THRESHOLD:
* LOGIN_ANONYMIZER_IP:
* ATYPICAL_COUNTRY
"""

NEW_DEVICE = "Login from new device"
IMP_TRAVEL = "Impossible Travel detected"
NEW_COUNTRY = "Login from new country"
USER_RISK_THRESHOLD = "User risk threshold alert"
LOGIN_ANONYMIZER_IP = "Login from anonymizer IP"
ATYPICAL_COUNTRY = "Login from atypical country"

@classmethod
def choices(cls):
return tuple((i.name, i.value) for i in cls)

@classmethod
def get_label_from_value(cls, value):
for item in cls:
if item.value == value:
return item.name
return None


class AlertFilterType(Enum):
"""Types of possible detection filter applied on alerts to be ignored
* ISP_FILTER: exclude from the detection a list of whitelisted ISP
* IS_MOBILE_FILTER: if Config.ignore_mobile_logins flag is checked, exclude from the detection the mobile devices
* IS_VIP_FILTER: if Config.alert_is_vip_only flag is checked, only the vip users (in the Config.vip_users list) send alerts
* ALLOWED_COUNTRY_FILTER: if the country of the login is in the Config.allowed_countries list, the alert isn't sent
* IGNORED_USER_FILTER: if the user is in the Config.ignored_users list OR the user is not in the Config.enabled_users list, the alert isn't sent
* ALERT_MINIMUM_RISK_SCORE_FILTER: if the user hasn't, at least, a User.risk_score equals to the one sets in Config.alert_minimum_risk_score,
* FILTERED_ALERTS: if the alert type (AlertDetectionType) is in the Config.filtered_alerts, the alert isn't sent
"""

ISP_FILTER = "isp_filter"
IS_MOBILE_FILTER = "is_mobile_filter"
IS_VIP_FILTER = "is_vip_filter"
ALLOWED_COUNTRY_FILTER = "allowed_country_filter"
IGNORED_USER_FILTER = "ignored_user_filter"
ALERT_MINIMUM_RISK_SCORE_FILTER = "alert_minimum_risk_score_filter"
FILTERED_ALERTS = "filtered_alerts"

@classmethod
def choices(cls):
return tuple((i.name, i.value) for i in cls)
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Generated by Django 5.1.4 on 2024-12-13 10:25

import django.contrib.postgres.fields
import impossible_travel.models
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
(
"impossible_travel",
"0010_config_alert_max_days_config_distance_accepted_and_more",
),
]

operations = [
migrations.AddField(
model_name="alert",
name="filter_type",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(
blank=True,
choices=[
("ISP_FILTER", "isp_filter"),
("IS_MOBILE_FILTER", "is_mobile_filter"),
("IS_VIP_FILTER", "is_vip_filter"),
("ALLOWED_COUNTRY_FILTER", "allowed_country_filter"),
("IGNORED_USER_FILTER", "ignored_user_filter"),
(
"ALERT_MINIMUM_RISK_SCORE_FILTER",
"alert_minimum_risk_score_filter",
),
("FILTERED_ALERTS", "filtered_alerts"),
],
max_length=50,
),
blank=True,
default=list,
help_text="List of filters that disabled the related alert",
size=None,
),
),
migrations.AddField(
model_name="alert",
name="is_filtered",
field=models.BooleanField(
default=False,
help_text="Show if the alert has been filtered because of some filter (listed in the filter_type field)",
),
),
migrations.AddField(
model_name="config",
name="alert_is_vip_only",
field=models.BooleanField(
default=False,
help_text="Flag to send alert only related to the users in the vip_users list",
),
),
migrations.AddField(
model_name="config",
name="alert_minimum_risk_score",
field=models.CharField(
choices=[
("NO_RISK", "No risk"),
("LOW", "Low"),
("MEDIUM", "Medium"),
("HIGH", "High"),
],
default="No risk",
help_text="Select the risk_score that users should have at least to send alert",
max_length=30,
),
),
migrations.AddField(
model_name="config",
name="enabled_users",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=50),
blank=True,
default=impossible_travel.models.get_default_enabled_users,
help_text="List of selected users on which the detection will perform",
size=None,
),
),
migrations.AddField(
model_name="config",
name="filtered_alerts_types",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(
blank=True,
choices=[
("NEW_DEVICE", "Login from new device"),
("IMP_TRAVEL", "Impossible Travel detected"),
("NEW_COUNTRY", "Login from new country"),
("USER_RISK_THRESHOLD", "User risk threshold alert"),
("LOGIN_ANONYMIZER_IP", "Login from anonymizer IP"),
("ATYPICAL_COUNTRY", "Login from atypical country"),
],
max_length=50,
),
default=list,
help_text="List of alerts' types to exclude from the alerting",
size=None,
),
),
migrations.AddField(
model_name="config",
name="ignore_mobile_logins",
field=models.BooleanField(
default=False,
help_text="Flag to ignore mobile devices from the detection",
),
),
migrations.AlterField(
model_name="alert",
name="name",
field=models.CharField(
choices=[
("NEW_DEVICE", "Login from new device"),
("IMP_TRAVEL", "Impossible Travel detected"),
("NEW_COUNTRY", "Login from new country"),
("USER_RISK_THRESHOLD", "User risk threshold alert"),
("LOGIN_ANONYMIZER_IP", "Login from anonymizer IP"),
("ATYPICAL_COUNTRY", "Login from atypical country"),
],
max_length=30,
),
),
migrations.AlterField(
model_name="config",
name="allowed_countries",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=20),
blank=True,
default=impossible_travel.models.get_default_allowed_countries,
help_text="List of countries to exclude from the detection, because 'trusted' for the customer",
size=None,
),
),
migrations.AlterField(
model_name="config",
name="ignored_ips",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=50),
blank=True,
default=impossible_travel.models.get_default_ignored_ips,
help_text="List of IPs to remove from the detection",
size=None,
),
),
migrations.AlterField(
model_name="config",
name="ignored_users",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=50),
blank=True,
default=impossible_travel.models.get_default_ignored_users,
help_text="List of users to be ignored from the detection",
size=None,
),
),
migrations.AlterField(
model_name="config",
name="vip_users",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=50),
blank=True,
default=impossible_travel.models.get_default_vip_users,
help_text="List of users considered more sensitive",
size=None,
),
),
migrations.AlterField(
model_name="user",
name="risk_score",
field=models.CharField(
choices=[
("NO_RISK", "No risk"),
("LOW", "Low"),
("MEDIUM", "Medium"),
("HIGH", "High"),
],
default="No risk",
max_length=30,
),
),
]
Loading

0 comments on commit 542727c

Please sign in to comment.