def _sendEmail(self): """ Prepares the e-mail by gathering all relevant information and then sends it out. :return: A tuple of success and status_message :rtype: bool, string """ otp = self._getNextOtp() email_address = self._email_address if not email_address: raise Exception("No e-mail address was defined for this token.") owner = get_token_owner(self) message = self._getEmailMessage(user=owner) if "<otp>" not in message: message = message + "<otp>" message = message.replace("<otp>", otp) message = message.replace("<serial>", self.getSerial()) subject = self._getEmailSubject(user=owner) subject = subject.replace("<otp>", otp) subject = subject.replace("<serial>", self.getSerial()) email_provider = loadProviderFromPolicy(provider_type='email', user=owner) status, status_message = email_provider.submitMessage(email_address, subject=subject, message=message) return status, status_message
def _submit_to_provider(self, otp_value): """ submit the voice message - former method name was checkPin :param otp_value: One time password to transfer to voice provider :return: Tuple of success and result message """ owner = get_token_owner(self) message = get_voice_message(owner, owner.realm) language = get_voice_language(owner, owner.realm) voice_provider = loadProviderFromPolicy( provider_type='voice', realm=owner.realm, user=owner) success, result = voice_provider.submitVoiceMessage( calleeNumber=self.get_mobile_number(owner), messageTemplate=message, otp=otp_value, locale=language) return success, result
def _sendEmail(self): """ Prepares the e-mail by gathering all relevant information and then sends it out. :return: A tuple of success and status_message :rtype: bool, string """ otp = self._getNextOtp() owner = get_token_owner(self) email_address = self._get_email_address(owner) if not email_address: raise Exception("No e-mail address was defined for this token.") message = self._getEmailMessage(user=owner) subject = self._getEmailSubject(user=owner) replacements = {} replacements["otp"] = otp replacements["serial"] = self.getSerial() # ------------------------------------------------------------------ -- # add user detail to replacements, so we are aware of surename++ if owner and owner.login: user_detail = owner.getUserInfo() if "cryptpass" in user_detail: del user_detail["cryptpass"] replacements.update(user_detail) # ------------------------------------------------------------------ -- try: email_provider = loadProviderFromPolicy(provider_type="email", user=owner) status, status_message = email_provider.submitMessage( email_address, subject=subject, message=message, replacements=replacements, ) except Exception as exx: LOG.error("Failed to submit EMail: %r", exx) raise return status, status_message
def createChallenge(self, transaction_id, options): """ entry hook for the challenge logic. when this function is called a challenge with an transaction was created. :param transaction_id: A unique transaction id used to identity the challenge object :param options: additional options as a dictionary :raises TokenStateError: If token state is not 'active' or 'pairing_response_received' :returns: A tuple (success, message, data, attributes) with success being a boolean indicating if the call to this method was successful, message being a string that is passed to the user, attributes being additional output data (unused in here) """ valid_states = ['pairing_response_received', 'active'] self.ensure_state_is_in(valid_states) # ------------------------------------------------------------------- -- # inside the challenge url we sent a callback url for the client # which is defined by an authentication policy owner = get_token_owner(self) if owner and owner.login and owner.realm: realms = [owner.realm] else: realms = self.getRealms() callback_policy_name = 'pushtoken_challenge_callback_url' callback_url = get_single_auth_policy(callback_policy_name, user=owner, realms=realms) if not callback_url: raise Exception(_('Policy pushtoken_challenge_callback_url must ' 'have a value')) # ------------------------------------------------------------------- -- # load and configure provider # the realm logic was taken from the # provider loading in the smstoken class # TODO: refactor & centralize logic realm = None if realms: realm = realms[0] push_provider = loadProviderFromPolicy(provider_type='push', realm=realm, user=owner) # ------------------------------------------------------------------- -- if self.current_state == 'pairing_response_received': content_type = CONTENT_TYPE_PAIRING message = '' challenge_url, sig_base = self.create_challenge_url(transaction_id, content_type, callback_url) else: content_type_as_str = options.get('content_type') try: # pylons silently converts all ints in json # to unicode :( content_type = int(content_type_as_str) except: raise ValueError('Unrecognized content type: %s' % content_type_as_str) # --------------------------------------------------------------- -- if content_type == CONTENT_TYPE_SIGNREQ: message = options.get('data') challenge_url, sig_base = self.create_challenge_url( transaction_id, content_type, callback_url, message=message) # --------------------------------------------------------------- -- elif content_type == CONTENT_TYPE_LOGIN: message = options.get('data') login, __, host = message.partition('@') challenge_url, sig_base = self.create_challenge_url( transaction_id, content_type, callback_url, login=login, host=host) else: raise ValueError('Unrecognized content type: %s' % content_type) # ------------------------------------------------------------------- -- # send the challenge_url to the push notification proxy token_info = self.getTokenInfo() gda = token_info['gda'] log.debug("pushing notification: %r : %r", challenge_url, gda) success, response = push_provider.push_notification(challenge_url, gda) if not success: raise Exception('push mechanism failed. response was %r' % response) # ------------------------------------------------------------------- -- # we save sig_base in the challenge data, because we need it in # checkOtp to verify the signature b64_sig_base = b64encode(sig_base) data = {'sig_base': b64_sig_base} if self.current_state == 'pairing_response_received': self.change_state('pairing_challenge_sent') # ------------------------------------------------------------------- -- # don't pass the challenge_url as message to the user return (True, '', data, {})
def sendSMS(self, message=None, transactionid=None): ''' send sms :param message: the sms submit message - could contain placeholders like <otp> or <serial> :type message: string :return: submitted message :rtype: string ''' log.debug("[sendSMS] begin. process the submitting of " "the sms message %r" % (message)) ret = None if not message: message = "<otp>" if not SMSPROVIDER_IMPORTED: raise Exception("The SMSProvider could not be imported. Maybe you " "didn't install the package (Debian " "linotp-smsprovider or PyPI SMSProvider)") phone = self.getPhone() otp = self.getNextOtp() serial = self.getSerial() if '<otp>' not in message: log.error('Message unconfigured: prepending <otp> to message') if isinstance(message, basestring): message = "<otp> %s" % message else: message = "<otp> %r" % message message = message.replace("<otp>", otp) message = message.replace("<serial>", serial) if transactionid: message = message.replace("<transactionid>", transactionid) log.debug("[sendSMS] sending SMS to phone number %s " % phone) owner = get_token_owner(self) sms_provider = loadProviderFromPolicy(provider_type='sms', user=owner) if not sms_provider: raise Exception('unable to load provider') log.debug("[sendSMS] submitMessage: %r, to phone %r", message, phone) ret = sms_provider.submitMessage(phone, message) if not ret: raise Exception("Failed to submit message") log.debug("[sendSMS] message submitted") # # after submit set validity time self.setValidUntil() # return OTP for selftest purposes log.debug("[sendSMS] end. sms message submitted: message %r" % (message)) return ret, message
def sendSMS(self, message=None, transactionid=None): ''' send sms :param message: the sms submit message - could contain placeholders like <otp> or <serial> :type message: string :return: submitted message :rtype: string ''' log.debug("[sendSMS] begin. process the submitting of " "the sms message %r" % (message)) ret = None if not message: message = "<otp>" if not SMSPROVIDER_IMPORTED: raise Exception("The SMSProvider could not be imported. Maybe you " "didn't install the package (Debian " "linotp-smsprovider or PyPI SMSProvider)") phone = self.getPhone() otp = self.getNextOtp() serial = self.getSerial() if '<otp>' not in message: log.error('Message unconfigured: prepending <otp> to message') if isinstance(message, basestring): message = "<otp> %s" % message else: message = "<otp> %r" % message message = message.replace("<otp>", otp) message = message.replace("<serial>", serial) if transactionid: message = message.replace("<transactionid>", transactionid) log.debug("[sendSMS] sending SMS to phone number %s " % phone) realm = None realms = self.getRealms() if realms: realm = realms[0] # we require the token owner to get the phone number and the provider owner = get_token_owner(self) if not owner or not owner.login: log.warning("Missing required token owner") sms_provider = loadProviderFromPolicy(provider_type='sms', realm=realm, user=owner) if not sms_provider: raise Exception('unable to load provider') log.debug("[sendSMS] submitMessage: %r, to phone %r", message, phone) ret = sms_provider.submitMessage(phone, message) if not ret: raise Exception("Failed to submit message") log.debug("[sendSMS] message submitted") # # after submit set validity time self.setValidUntil() # return OTP for selftest purposes log.debug("[sendSMS] end. sms message submitted: message %r" % (message)) return ret, message
def createChallenge(self, transaction_id, options): """ entry hook for the challenge logic. when this function is called a challenge with an transaction was created. :param transaction_id: A unique transaction id used to identity the challenge object :param options: additional options as a dictionary :raises TokenStateError: If token state is not 'active' or 'pairing_response_received' :returns: A tuple (success, message, data, attributes) with success being a boolean indicating if the call to this method was successful, message being a string that is passed to the user, attributes being additional output data (unused in here) """ _ = context['translate'] valid_states = ['active', 'pairing_response_received', # we support re activation # as long as the token is not active 'pairing_challenge_sent', ] self.ensure_state_is_in(valid_states) # ------------------------------------------------------------------- -- # inside the challenge url we sent a callback url for the client # which is defined by an authentication policy owner = get_token_owner(self) if owner and owner.login and owner.realm: realms = [owner.realm] else: realms = self.getRealms() callback_policy_name = 'pushtoken_challenge_callback_url' callback_url = get_single_auth_policy(callback_policy_name, user=owner, realms=realms) if not callback_url: raise Exception(_('Policy pushtoken_challenge_callback_url must ' 'have a value')) # ------------------------------------------------------------------- -- # load and configure provider # the realm logic was taken from the # provider loading in the smstoken class # TODO: refactor & centralize logic realm = None if realms: realm = realms[0] push_provider = loadProviderFromPolicy(provider_type='push', realm=realm, user=owner) # ------------------------------------------------------------------- -- if self.current_state in ['pairing_response_received', 'pairing_challenge_sent']: content_type = CONTENT_TYPE_PAIRING message = '' challenge_url, sig_base = self.create_challenge_url(transaction_id, content_type, callback_url) elif self.current_state in ['active']: content_type_as_str = options.get( 'content_type', CONTENT_TYPE_SIGNREQ) try: # pylons silently converts all ints in json # to unicode :( content_type = int(content_type_as_str) except: raise ValueError('Unrecognized content type: %s' % content_type_as_str) # --------------------------------------------------------------- -- if content_type == CONTENT_TYPE_SIGNREQ: message = options.get('data') challenge_url, sig_base = self.create_challenge_url( transaction_id, content_type, callback_url, message=message) # --------------------------------------------------------------- -- elif content_type == CONTENT_TYPE_LOGIN: message = options.get('data') login, __, host = message.partition('@') challenge_url, sig_base = self.create_challenge_url( transaction_id, content_type, callback_url, login=login, host=host) else: raise ValueError('Unrecognized content type: %s' % content_type) # ------------------------------------------------------------------- -- # send the challenge_url to the push notification proxy token_info = self.getTokenInfo() gda = token_info['gda'] log.debug("pushing notification: %r : %r", challenge_url, gda) success, response = push_provider.push_notification( challenge_url, gda, transaction_id) if not success: raise Exception('push mechanism failed. response was %r' % response) # ------------------------------------------------------------------- -- # we save sig_base in the challenge data, because we need it in # checkOtp to verify the signature b64_sig_base = b64encode(sig_base) data = {'sig_base': b64_sig_base} if self.current_state == 'pairing_response_received': self.change_state('pairing_challenge_sent') # ------------------------------------------------------------------- -- # don't pass the challenge_url as message to the user return (True, '', data, {})