Changeset 15606


Ignore:
Timestamp:
24 Sep 2019, 17:21:28 (5 years ago)
Author:
Henrik Bettermann
Message:

Parents access implementation (part 1)

Location:
main/waeup.kofa/trunk/src/waeup/kofa
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py

    r15422 r15606  
    364364                        self.request.principal.id]
    365365                    rel_link = '/students/%s' % self.request.principal.id
    366                     if student.personal_data_expired:
    367                         rel_link = '/students/%s/edit_personal' % (
    368                             self.request.principal.id)
    369                         self.flash(
    370                           _('Your personal data record is outdated. Please update.'),
    371                           type='warning')
     366                    if student.getParentsPassword():
     367                        # Add logging message
     368                        student.writeLogMessage(self, 'Parents logged in')
     369                        # Replace role if parents have logged in
     370                        role_manager = IPrincipalRoleManager(student)
     371                        role_manager.removeRoleFromPrincipal(
     372                            'waeup.local.StudentRecordOwner', student.student_id)
     373                        notify(LocalRoleSetEvent(
     374                            student, 'waeup.local.StudentRecordOwner',
     375                            student.student_id, granted=False))
     376                        role_manager.assignRoleToPrincipal(
     377                            'waeup.local.Parents', student.student_id)
     378                        notify(LocalRoleSetEvent(
     379                            student, 'waeup.local.Parents',
     380                            student.student_id, granted=True))
     381                    else:
     382                        # Redirect to personal page if data are outdated
     383                        if student.personal_data_expired:
     384                            rel_link = '/students/%s/edit_personal' % (
     385                                self.request.principal.id)
     386                            self.flash(
     387                              _('Your personal data record is outdated. Please update.'),
     388                              type='warning')
    372389                    self.redirect(self.application_url() + rel_link)
    373390                    return
     
    402419                return
    403420            # Display appropriate flash message if credentials are correct
    404             # but student has been deactivated or a temporary password
    405             # has been set.
     421            # but student has been deactivated or a temporary or parents
     422            # password has been set.
    406423            login = self.request.form['form.login']
    407424            if len(login) == 8 and login in grok.getSite()['students']:
     
    413430                    # The student entered valid credentials.
    414431                    # First we check if a temporary password has been set.
    415                     delta = timedelta(minutes=10)
    416                     now = datetime.utcnow()
    417                     temp_password_dict = getattr(student, 'temp_password', None)
    418                     if temp_password_dict is not None and \
    419                         now < temp_password_dict.get('timestamp', now) + delta:
     432                    if student.getTempPassword():
    420433                        self.flash(
    421434                            _('Your account has been temporarily deactivated.'),
     435                            type='warning')
     436                        return
     437                    # Next we check if a parents password has been set.
     438                    if student.getParentsPassword():
     439                        self.flash(
     440                            _('Your account has been temporarily deactivated '
     441                              'because your parents have logged in.'),
    422442                            type='warning')
    423443                        return
  • main/waeup.kofa/trunk/src/waeup/kofa/doctests/permissions.txt

    r15163 r15606  
    4242
    4343    >>> len(list(get_waeup_roles(also_local=True)))
    44     52
     44    53
    4545
    4646
  • main/waeup.kofa/trunk/src/waeup/kofa/students/authentication.py

    r13394 r15606  
    112112    def checkPassword(self, password):
    113113        """Check whether the given `password` matches the one stored by
    114         students or the temporary password set by officers.
     114        students, the temporary password was set by officers or
     115        the parents_password was set by parents.
    115116        We additionally check if student account has been suspended
    116117        or if the portal is blocked.
     
    128129        if temp_password:
    129130            return passwordmanager.checkPassword(temp_password, password)
     131        parents_password = self.context.getParentsPassword()
     132        if parents_password:
     133            return passwordmanager.checkPassword(parents_password, password)
    130134        if not getattr(self.context, 'password', None):
    131135            # unset/empty passwords do never match
  • main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py

    r15423 r15606  
    226226    password = Attribute('Encrypted password')
    227227    temp_password = Attribute('Dictionary with user name, timestamp and encrypted password')
     228    parents_password = Attribute('Dictionary with student_id, timestamp and encrypted password')
    228229
    229230    suspended = schema.Bool(
     
    314315        is not expired. Return the temporary password if valid,
    315316        None otherwise. Unset the temporary password if expired.
     317        """
     318
     319    def setParentsPassword(password):
     320        """Set a parents password (LDAP-compatible) SSHA encoded for
     321        parents.
     322        """
     323
     324    def getParentsPassword():
     325        """Check if a parents password has been set and if it
     326        is not expired.
     327
     328        Return the parents password if valid,
     329        None otherwise. Unset the parents password if expired.
    316330        """
    317331
  • main/waeup.kofa/trunk/src/waeup/kofa/students/permissions.py

    r15333 r15606  
    122122                     'waeup.handleAccommodation',
    123123                     'waeup.editStudyLevel')
     124
     125class Parents(grok.Role):
     126    """Parents temporarily get access to view the records of their children.
     127    """
     128    grok.name('waeup.local.Parents')
     129    grok.title(u'Parents')
     130    grok.permissions('waeup.viewStudent')
    124131
    125132# Site Roles
  • main/waeup.kofa/trunk/src/waeup/kofa/students/student.py

    r15416 r15606  
    3131from zope.securitypolicy.interfaces import IPrincipalRoleManager
    3232from zope.schema.interfaces import ConstraintNotSatisfied
    33 
     33from zope.event import notify
     34
     35from waeup.kofa.authentication import LocalRoleSetEvent
    3436from waeup.kofa.image import KofaImageFile
    3537from waeup.kofa.imagestorage import DefaultFileStoreHandler
     
    6769        self.password = None
    6870        self.temp_password = None
     71        self.parents_password = None
    6972        return
    7073
     
    9699                # Unset temporary password if expired
    97100                self.temp_password = None
     101        return None
     102
     103    def setParentsPassword(self, password):
     104        """Set a temporary password (LDAP-compatible) SSHA encoded for
     105        parents.
     106        """
     107        passwordmanager = getUtility(IPasswordManager, 'SSHA')
     108        self.parents_password = {}
     109        self.parents_password[
     110            'password'] = passwordmanager.encodePassword(password)
     111        self.parents_password['timestamp'] = datetime.utcnow() # offset-naive datetime
     112
     113    def getParentsPassword(self):
     114        """Check if a parents password has been set and if it
     115        is not expired.
     116
     117        Return the parents password if valid,
     118        None otherwise. Unset the parents password and replace roles
     119        if expired.
     120        """
     121        parents_password_dict = getattr(self, 'parents_password', None)
     122        if parents_password_dict is not None:
     123            delta = timedelta(minutes=self.temp_password_minutes)
     124            now = datetime.utcnow()
     125            if now < parents_password_dict.get('timestamp') + delta:
     126                return parents_password_dict.get('password')
     127            else:
     128                # Unset parents password if expired
     129                self.parents_password = None
     130                # Replace roles if expired
     131                role_manager = IPrincipalRoleManager(self)
     132                role_manager.removeRoleFromPrincipal(
     133                    'waeup.local.Parents', self.student_id)
     134                notify(LocalRoleSetEvent(
     135                    self, 'waeup.local.Parents',
     136                    self.student_id, granted=False))
     137                role_manager.assignRoleToPrincipal(
     138                    'waeup.local.StudentRecordOwner', self.student_id)
     139                notify(LocalRoleSetEvent(
     140                    self, 'waeup.local.StudentRecordOwner',
     141                    self.student_id, granted=True))
    98142        return None
    99143
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_authentication.py

    r9334 r15606  
    8989        return None
    9090
     91    def getParentsPassword(self):
     92        parents_password_dict = getattr(self, 'parents_password', None)
     93        if parents_password_dict is not None:
     94            delta = timedelta(minutes=self.temp_password_minutes)
     95            now = datetime.utcnow()
     96            if now < parents_password_dict.get('timestamp') + delta:
     97                return parents_password_dict.get('password')
     98            else:
     99                # Unset temporary password if expired
     100                self.parents_password = None
     101        return None
     102
     103
    91104
    92105class MinimalPAU(PluggableAuthentication):
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py

    r15545 r15606  
    46714671            self.assertTrue(
    46724672                'Uploaded file contains illegal data' in self.browser.contents)
     4673
     4674class ParentsUITests(StudentsFullSetup):
     4675    # Tests for UI actions when acting as parents.
     4676
     4677    def test_login_as_parents(self):
     4678        # Sstudent login still works after all the changes made
     4679        self.browser.open(self.login_path)
     4680        self.browser.getControl(name="form.login").value = self.student_id
     4681        self.browser.getControl(name="form.password").value = 'spwd'
     4682        self.browser.getControl("Login").click()
     4683        self.assertTrue('You logged in' in self.browser.contents)
     4684        self.browser.open(self.edit_personal_path)
     4685        self.browser.getLink("Logout").click()
     4686        self.assertTrue('You have been logged out' in self.browser.contents)
     4687        # We set parents password
     4688        self.app['students'][self.student_id].setParentsPassword('ppwd')
     4689        self.browser.open(self.login_path)
     4690        # Student can't login with original password
     4691        self.browser.getControl(name="form.login").value = self.student_id
     4692        self.browser.getControl(name="form.password").value = 'spwd'
     4693        self.browser.getControl("Login").click()
     4694        self.assertEqual(self.browser.url, self.login_path)
     4695        self.assertTrue('Your account has been temporarily deactivated '
     4696            'because your parents have logged in.' in self.browser.contents)
     4697        # Parents can login with their password
     4698        self.browser.open(self.login_path)
     4699        self.browser.getControl(name="form.login").value = self.student_id
     4700        self.browser.getControl(name="form.password").value = 'ppwd'
     4701        self.browser.getControl("Login").click()
     4702        self.assertTrue(
     4703            'You logged in.' in self.browser.contents)
     4704        self.assertTrue(
     4705            '<a href="http://localhost/app/students/K1000000">Base Data</a>'
     4706            in self.browser.contents)
     4707        # They do not see all links ...
     4708        self.assertFalse(
     4709            '<a href="http://localhost/app/students/K1000000/history">History</a>'
     4710            in self.browser.contents)
     4711        # ... and can't change anything
     4712        self.assertRaises(
     4713            Unauthorized, self.browser.open, self.edit_personal_path)
     4714        # If the password has expired, parents are logged out and the
     4715        # student can login again with the original password
     4716        delta = timedelta(minutes=11)
     4717        self.app['students'][self.student_id].parents_password[
     4718            'timestamp'] = datetime.utcnow() - delta
     4719        self.app['students'][self.student_id]._p_changed = True
     4720        self.assertRaises(
     4721            Unauthorized, self.browser.open, self.student_path)
     4722        # Parents login is written to log file
     4723        logfile = os.path.join(
     4724            self.app['datacenter'].storage, 'logs', 'students.log')
     4725        logcontent = open(logfile).read()
     4726        self.assertTrue(
     4727            'K1000000 - browser.pages.LoginPage - K1000000 - Parents logged in'
     4728            in logcontent)
  • main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py

    r15422 r15606  
    905905            student, 'application_slip')
    906906        targets = []
     907        if student.getParentsPassword():
     908            targets += [
     909                {'url': student_url, 'title': 'Base Data'},
     910                {'url': student_url + '/studycourse', 'title': _('Study Course')},
     911                {'url': student_url + '/payments', 'title': _('Payments')},
     912                ]
     913            return targets
    907914        if app_slip:
    908915            targets = [{'url': student_url + '/application_slip',
Note: See TracChangeset for help on using the changeset viewer.