Skip to content

Commit

Permalink
Sms to drift user on password change (#31)
Browse files Browse the repository at this point in the history
* Functionality created to enable sms notification on password change

Added function to Cerebrum/modules/no/uio/sysadm_utils to validate that user is sys_adm(-drift)
Created file changed_password_notifier.py, which holds two classes. One mixin for password change that creates adds a task to task queue,
and one QueueHandler for changed password that creates the task and holds values related to queue.
Created the script contrib/no/uio/new_password_task_processor.py that handles the tasks in TaskQueue for password change and tries to send out sms to given user.
  • Loading branch information
Sverre Stafsengen Broen authored and GitHub Enterprise committed Jun 7, 2023
1 parent 0ba74d9 commit b64998f
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 1 deletion.
74 changes: 74 additions & 0 deletions Cerebrum/modules/no/uio/changed_password_notifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2023 University of Oslo, Norway
#
# This file is part of Cerebrum.
#
# Cerebrum is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Cerebrum 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. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Cerebrum; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""
A file containing two classes that is related to TaskQueue whenever a
password is changed. NotifyChangePasswordMixin is a mixin class for setting a
new password, the functionality within will check if user is a sysadm_account
and add it to queue if that is the case. NotifyPasswordQueueHandler is used for
handling tasks and inherits queue_handler
"""
from Cerebrum import Account
from Cerebrum.Utils import Factory
from Cerebrum.modules.tasks.task_models import Task
from Cerebrum.modules.tasks.task_queue import TaskQueue
from Cerebrum.modules.tasks import queue_handler
from Cerebrum.modules.no.uio.sysadm_utils import is_sysadm_account


class NotifyChangePasswordMixin(Account.Account):
def set_password(self, password):
super(NotifyChangePasswordMixin, self).set_password(password)
if not is_sysadm_account(self):
return
task = ChangedPasswordQueueHandler.create_changed_password_task(
self.account_name)
self.__task = task

def clear(self):
try:
del self.__task
except AttributeError:
pass
super(NotifyChangePasswordMixin, self).clear()

def write_db(self):
try:
task = self.__task
del self.__task
except AttributeError:
task = None
ret = super(NotifyChangePasswordMixin, self).write_db()
if task is not None:
TaskQueue(self._db).push_task(task)
return ret

class ChangedPasswordQueueHandler(queue_handler.QueueHandler):
queue = 'notify-changed-password'
max_attempts = 12

@classmethod
def create_changed_password_task(cls, key, nbf=None):
return Task(
queue=cls.queue,
key=key,
nbf=nbf,
attempts=0,
)
20 changes: 19 additions & 1 deletion Cerebrum/modules/no/uio/sysadm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def get_sysadm_accounts(db, suffix=SYSADM_SUFFIX_DRIFT):
logger.debug('found %d accounts tagged with trait=%s',
len(sysadm_filter), co.trait_sysadm_account)

# filter acocunt list by personal accounts with name *-drift
# filter account list by personal accounts with name *-drift
sysadm_accounts = {
r['account_id']: r
for r in ac.search(name=name_pattern,
Expand Down Expand Up @@ -245,6 +245,24 @@ def create_sysadm_account(db, target_account, suffix, creator_id):
return sysadm_account


def is_sysadm_account(account):
try:
primary_account, suffix = account.account_name.split("-")
except ValueError:
return False

if not suffix:
return False

if suffix not in VALID_SYSADM_SUFFIXES:
return False

if account.const.trait_sysadm_account not in account.get_traits():
return False

return True


def get_forward_to_address(target_account):
""" Get formatted email address for a given target account. """
db = target_account._db
Expand Down
113 changes: 113 additions & 0 deletions contrib/no/uio/new_password_task_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2023 University of Oslo, Norway
#
# This file is part of Cerebrum.
#
# Cerebrum is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Cerebrum 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. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Cerebrum; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""
Script containing functionality for sending sms to persons in
task queue related to password change.
"""

import io
import logging
import argparse
import cereconf
import functools
from os import path

import Cerebrum.logutils
import Cerebrum.logutils.options
from Cerebrum.Utils import Factory
from Cerebrum.utils.sms import SMSSender
from Cerebrum.utils.argutils import add_commit_args
from Cerebrum.modules.tasks.task_queue import TaskQueue
from Cerebrum.modules.tasks.queue_processor import QueueProcessor
from Cerebrum.modules.no.uio.changed_password_notifier import ChangedPasswordQueueHandler

logger = logging.getLogger(__name__)
sms = SMSSender(logger=logger)

def get_message(uname, time):
with io.open(path.join(cereconf.TEMPLATE_DIR,
'changed_password_notifier.template'), 'r',
encoding='UTF-8') as f:
template = f.read()
return template.format(account_name=uname, time= time)

def send_sms(uname, task_iat, phone_number):
if not phone_number:
return False
try:
time_format = "%d.%m.%Y %H:%M:%S"
time = task_iat.strftime(time_format)
message = get_message(uname, time)
return sms(phone_number, message)
except Exception as e:
logger.warning("Failed during execution of sending message")
return False

def task_callback(db, task, dryrun):
ac = Factory.get('Account')(db)
pe = Factory.get('Person')(db)
co = Factory.get('Constants')(db)

ac.find_by_name(task.key)
pe.find(ac.owner_id)

spec = map(lambda (s): (co.human2constant(s), co.human2constant("MOBILE")),
cereconf.SYSTEM_LOOKUP_ORDER)
mobile = pe.sort_contact_info(spec, pe.get_contact_info())

person_in_systems = [int(af['source_system']) for af in
pe.list_affiliations(person_id=pe.entity_id)]
mobile = filter(lambda x: x['source_system'] in person_in_systems,
mobile)[0]['contact_value']

if dryrun:
logger.info('Dryrun for id - %s', task.key)
else:
if not send_sms(ac.account_name, task.iat, mobile):
raise Exception("Sms to " + str(mobile) + " failed with task key - " +
task.key)
return []

def run_tasks(dryrun):
callback = functools.partial(task_callback, dryrun=dryrun)
max_attempts = ChangedPasswordQueueHandler.max_attempts
proc = QueueProcessor(ChangedPasswordQueueHandler(callback),
limit=max_attempts, dryrun=dryrun)
tasks = proc.select_tasks()
for task in tasks:
proc.process_task(task)


def main(inargs=None):
parser = argparse.ArgumentParser(
description="Handle password change tasks and send sms to people affected",
)
add_commit_args(parser)
Cerebrum.logutils.options.install_subparser(parser)

args = parser.parse_args(inargs)
Cerebrum.logutils.autoconf('cronjob', args)
dryrun = not args.commit
run_tasks(dryrun)


if __name__ == '__main__':
main()

0 comments on commit b64998f

Please sign in to comment.