Commit 624184c8 authored by Philip ABBET's avatar Philip ABBET
Browse files

Merge branch 'security_accounts' into 'master'

Security accounts

See merge request !224
parents f4a4fad8 919b7ad8
Pipeline #11735 failed with stage
in 1 minute and 4 seconds
This diff is collapsed.
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from django.conf.urls import *
from . import api
urlpatterns = [
url(
r'^$',
api.GodfatherListView.as_view(),
name='list_supervisee'
),
url(
r'^(?P<supervisee_name>[\w\W]+)/validate/$',
api.GodfatherAddSuperviseeView.as_view(),
name='validate_supervisee'
),
url(
r'^(?P<supervisee_name>[\w\W]+)/remove/$',
api.GodfatherRemoveSuperviseeView.as_view(),
name='remove_supervisee'
),
url(
r'^(?P<supervisor_name>[\w\W]+)/add/$',
api.SuperviseeAddGodfatherView.as_view(),
name='add_supervisor'
),
url(
r'^revalidate/$',
api.SuperviseeReValidationView.as_view(),
name='revalidate_account'
),
]
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# encoding: utf-8
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from django.core.management.base import BaseCommand, CommandError
from datetime import date
import datetime
from django.contrib.auth.models import User
from django.conf import settings
from ...models import SupervisionTrack
from ...models import Profile
from ....ui.registration.models import RegistrationProfile
import sys
import random
class Command(BaseCommand):
help = 'Block rejected users after rejection date with no valid supervisor'
def add_arguments(self, parser):
parser.add_argument('--noinput', action='store_false', dest='interactive', default=False,
help=('Tells Django to NOT prompt the user for input of any kind.'))
def handle(self, *args, **options):
block = True
if options['interactive']:
try:
answer = self.get_input_data('Block rejected user(s) that have not been validated by a supervisor? (y/n)? ', 'y').lower()
except KeyboardInterrupt:
self.stderr.write("\nOperation canceled.")
sys.exit(1)
if answer != 'y':
self.stdout.write('Block users operation canceled')
sys.exit(1)
if block:
rejected_profiles = Profile.objects.filter(status=Profile.REJECTED)
count = 0
for rejected_profile in rejected_profiles:
user = rejected_profile.user
if user.profile.rejection_date < datetime.datetime.now():
count +=1
user.profile.status = Profile.BLOCKED
user.profile.rejection_date = None
user.is_active = False
if user.profile.supervision_key != None:
supervisiontrack = SupervisionTrack.objects.get(supervision_key=rejected_profile.supervision_key)
if supervisiontrack.is_valid == False and supervisiontrack.start_date is None:
user.profile.supervision_key = None
supervisiontrack.delete()
user.profile.save()
user.save()
self.stdout.write('{} Rejected user(s) successfully blocked/'.format(count) + '{} Total user(s) checked'.format(rejected_profiles.count()))
def get_input_data(self, message, default=None):
"""
Override this method if you want to customize data inputs or
validation exceptions.
"""
raw_value = raw_input(message)
if default and raw_value == '':
raw_value = default
return raw_value
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# encoding: utf-8
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from django.core.management.base import BaseCommand, CommandError
from datetime import date
import datetime
from django.contrib.auth.models import User
from django.conf import settings
from ...models import SupervisionTrack
from ...models import Profile
from ....ui.registration.models import RegistrationProfile
import sys
import random
class Command(BaseCommand):
help = 'Clean blocked users expired requests for supervisor validation'
def add_arguments(self, parser):
parser.add_argument('--noinput', action='store_false', dest='interactive', default=False,
help=('Tells Django to NOT prompt the user for input of any kind.'))
def handle(self, *args, **options):
block = True
if options['interactive']:
try:
answer = self.get_input_data('Clean blocked user(s) that have not been validated by a supervisor? (y/n)? ', 'y').lower()
except KeyboardInterrupt:
self.stderr.write("\nOperation canceled.")
sys.exit(1)
if answer != 'y':
self.stdout.write('Clean blocked users operation canceled')
sys.exit(1)
if block:
blocked_profiles = Profile.objects.filter(status=Profile.BLOCKED)
count = 0
for blocked_profile in blocked_profiles:
user = blocked_profile.user
if user.profile.rejection_date is not None:
if user.profile.rejection_date < datetime.datetime.now():
count +=1
user.profile.status = Profile.BLOCKED
user.profile.rejection_date = None
user.is_active = False
if user.profile.supervision_key != None:
supervisiontrack = SupervisionTrack.objects.get(supervision_key=blocked_profile.supervision_key)
if supervisiontrack.is_valid == False and supervisiontrack.start_date is None:
user.profile.supervision_key = None
supervisiontrack.delete()
user.profile.save()
user.save()
self.stdout.write('{} Blocked user(s) successfully cleaned from expired supervision/'.format(count) + '{} Total user(s) checked'.format(blocked_profiles.count()))
def get_input_data(self, message, default=None):
"""
Override this method if you want to customize data inputs or
validation exceptions.
"""
raw_value = raw_input(message)
if default and raw_value == '':
raw_value = default
return raw_value
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# encoding: utf-8
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from django.core.management.base import BaseCommand, CommandError
from datetime import date
import datetime
from django.contrib.auth.models import User
from django.conf import settings
from ...models import SupervisionTrack
from ...models import Profile
from ....ui.registration.models import RegistrationProfile
import sys
import random
class Command(BaseCommand):
help = 'Cleanup outdated invalid users'
def add_arguments(self, parser):
parser.add_argument('--noinput', action='store_false', dest='interactive', default=False,
help=('Tells Django to NOT prompt the user for input of any kind.'))
def handle(self, *args, **options):
clean = True
if options['interactive']:
try:
answer = self.get_input_data('Delete user(s) that have not been validated by a supervisor? (y/n)? ', 'y').lower()
except KeyboardInterrupt:
self.stderr.write("\nOperation canceled.")
sys.exit(1)
if answer != 'y':
self.stdout.write('Cleanup canceled')
sys.exit(1)
if clean:
invalid_userprofiles_new_users = Profile.objects.filter(status=Profile.NEWUSER)
invalid_userprofiles_waiting_validation = Profile.objects.filter(status=Profile.WAITINGVALIDATION)
count = 0
for invalid_profile in invalid_userprofiles_new_users:
user = invalid_profile.user
supervisiontrack = SupervisionTrack.objects.get(supervision_key=invalid_profile.supervision_key)
registration_profile = RegistrationProfile.objects.get(user=invalid_profile.user)
expiration_date = datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS)
if user.profile.registration_date + expiration_date <= datetime.datetime.now():
count += 1
user.delete()
invalid_profile.delete()
supervisiontrack.delete()
registration_profile.delete()
for invalid_profile in invalid_userprofiles_waiting_validation:
user = invalid_profile.user
supervisiontrack = SupervisionTrack.objects.get(supervision_key=invalid_profile.supervision_key)
registration_profile = RegistrationProfile.objects.get(user=invalid_profile.user)
expiration_date = datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS_FROM_GODFATHER)
if user.profile.registration_date + expiration_date <= datetime.datetime.now():
count += 1
user.delete()
invalid_profile.delete()
supervisiontrack.delete()
registration_profile.delete()
self.stdout.write('{} Invalid user(s) successfully cleaned/'.format(count) + '{} Total user(s) checked'.format(invalid_userprofiles_new_users.count()+invalid_userprofiles_waiting_validation.count()))
def get_input_data(self, message, default=None):
"""
Override this method if you want to customize data inputs or
validation exceptions.
"""
raw_value = raw_input(message)
if default and raw_value == '':
raw_value = default
return raw_value
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# encoding: utf-8
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from django.core.management.base import BaseCommand, CommandError
from datetime import date
import datetime
from django.db.models import Q
from django.contrib.auth.models import User
from django.conf import settings
from django.core.mail import send_mail
from django.template import loader
from django.template import Context
from ...models import SupervisionTrack
from ...models import Profile
from ....ui.registration.models import RegistrationProfile
import sys
import random
from urlparse import urlparse
class Command(BaseCommand):
help = 'Check users for yearly revalidation'
def add_arguments(self, parser):
parser.add_argument('--noinput', action='store_false', dest='interactive', default=False,
help=('Tells Django to NOT prompt the user for input of any kind.'))
def handle(self, *args, **options):
yearrevalidate = True
if options['interactive']:
try:
answer = self.get_input_data('Check user(s) for yearly revalidation by a supervisor? (y/n)? ', 'y').lower()
except KeyboardInterrupt:
self.stderr.write("\nOperation canceled.")
sys.exit(1)
if answer != 'y':
self.stdout.write('Check users yearly revalidation operation canceled')
sys.exit(1)
if yearrevalidate:
torevalidate_profiles = Profile.objects.filter(Q(status=Profile.ACCEPTED)|Q(status=Profile.YEARREVALIDATION))
now = datetime.datetime.now()
blocked_count = 0
warned_count = 0
for torevalidate_profile in torevalidate_profiles:
user = torevalidate_profile.user
if user.profile.is_godfather == False:
#Not godfather
if user.profile.supervision_key != None:
supervisiontrack = SupervisionTrack.objects.get(supervision_key=torevalidate_profile.supervision_key)
if supervisiontrack.is_valid:
#Check expiration date
expiration_date_delta = datetime.timedelta(days=settings.ACCOUNT_BLOCKAGE_AFTER_FIRST_REJECTION_DAYS)
if supervisiontrack.expiration_date < now + expiration_date_delta:
#check if need to block account
if now > supervisiontrack.expiration_date:
blocked_count += 1
#terminate supervision
supervisiontrack.expiration_date = now
supervisiontrack.is_valid = False
#block user
user.profile.status = Profile.BLOCKED
user.profile.rejection_date = None
user.profile.supervision_key = None
user.is_active = False
#save all changes
supervisiontrack.save()
user.profile.save()
user.save()
else:
#send the warning information
#set user to YEARREVALIDATION
if user.profile.status == Profile.ACCEPTED:
user.profile.status = Profile.YEARREVALIDATION
user.profile.save()
#send email to user
for expiration_reminder in settings.EXPIRATION_REMINDERS_REVALIDATION:
if supervisiontrack.expiration_date.date() - now.date() == datetime.timedelta(days=expiration_reminder):
warned_count += 1
parsed_url = urlparse(settings.URL_PREFIX)
server_address = '%s://%s' % (parsed_url.scheme, parsed_url.hostname)
c = Context({ 'user': user,
'expiration_date': supervisiontrack.expiration_date.date(),
})
try:
t = loader.get_template('registration/mail.account_revalidation.subject.txt')
subject = t.render(c)
# Note: e-mail subject *must not* contain newlines
subject = settings.EMAIL_SUBJECT_PREFIX + ''.join(subject.splitlines())
t = loader.get_template('registration/mail.account_revalidation.message.txt')
message = t.render(c)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [supervisiontrack.supervisee.email])
except:
pass
else:
#Is godfather
#TODO implement this procedure
pass
self.stdout.write('{} blocked user(s) and '.format(blocked_count)+'{} warned user(s)/'.format(warned_count) + '{} Total user(s) that need revalidation'.format(torevalidate_profiles.count()))
def get_input_data(self, message, default=None):
"""
Override this method if you want to customize data inputs or
validation exceptions.
"""
raw_value = raw_input(message)
if default and raw_value == '':
raw_value = default
return raw_value
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2017-05-08 17:00
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('accounts', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Profile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.CharField(choices=[(b'A', b'Accepted'), (b'R', b'Rejected'), (b'W', b'Waiting Validation'), (b'B', b'Blocked')], default=b'B', max_length=1)),
('is_godfather', models.BooleanField(default=False)),
('supervisees', models.ManyToManyField(blank=True, related_name='users', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2017-05-18 12:32
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
<