def enrollment_complete(self, enrollment, data): with transaction.atomic(): assert enrollment.status == Enrollment.STATUS_IN_PROGRESS assert not enrollment.is_expired() # mark the enrollment as failed enrollment.status = Enrollment.STATUS_FAILED private_details, err = self.get_enrollment_private_details_model( enrollment.private_details) if err: logger.error( 'failed to retrieve private details for OTP enrollment `{0}`: {1}' .format(enrollment.pk, err)) return False, err # create the provisioning uri totp = pyotp.TOTP(s=private_details['secret'], digits=private_details['digits'], interval=private_details['interval']) ok = totp.verify(data['token'], valid_window=self._configuration['valid_window']) if not ok: logger.error( 'failed to verify OTP `{0}` as valid for enrollment `{1}`'. format(data['token'], enrollment.pk)) return False, errors.MFASecurityError( 'token mismatch: `{0}` is not a valid OTP token for enrollment `{1}`' .format(data['token'], enrollment.pk)) # extract the device details details = OTPDeviceDetails( data={ 'issuer_name': private_details['issuer_name'], 'digits': private_details['digits'], 'interval': private_details['interval'], 'secret': private_details['secret'], 'valid_window': private_details['valid_window'], 'algorithm': private_details['algorithm'] }) if not details.is_valid(): logger.info( 'could not validate OTP device details: {0}'.format( details.errors)) # create the device device = Device() device.name = 'OTP [{0}]'.format(enrollment.username) device.kind = enrollment.device_selection.kind device.enrollment = enrollment # save the device details device.details = details.validated_data return device, None
def enrollment_complete(self, enrollment, data): assert enrollment.status == Enrollment.STATUS_IN_PROGRESS assert not enrollment.is_expired() # compare given token to privately stored token private_details = EmailDeviceEnrollmentPrivateDetails( data=enrollment.private_details) if not private_details.is_valid(): return None, errors.MFAInconsistentStateError( 'enrollment private details is invalid: {0}'.format( private_details.errors)) # if the token don't match, fail. if private_details.validated_data['token'] != data['token']: return None, errors.MFASecurityError( 'token mismatch, expected `{0}` however received `{1}`'.format( private_details.validated_data['token'], data['token'])) # extract the device details details = EmailDeviceDetails( data={'address': private_details.validated_data['address']}) assert details.is_valid() # create the device device = Device() device.name = u'Email [@{0}]'.format( EmailDeviceKindModule.mask_address( private_details.validated_data['address'])) device.kind = enrollment.device_selection.kind device.enrollment = enrollment # save the device details device.details = details.validated_data return device, None