def _compose_email(self, message="<otp>", subject="Your OTP", mimetype="plain"): """ send email :param message: the email submit message - could contain placeholders like <otp> or <serial> :type message: string :param mimetype: the message MIME type - one of "plain", "html" :type mimetype: basestring :return: submitted message :rtype: string """ ret = None recipient = self._email_address otp = self.get_otp()[2] serial = self.get_serial() message = message.replace("<otp>", otp) message = message.replace("<serial>", serial) tags = create_tag_dict(serial=serial, tokenowner=self.user, tokentype=self.get_tokentype(), recipient={"givenname": self.user.info.get("givenname"), "surname": self.user.info.get("surname")}, escape_html=mimetype.lower() == "html") message = message.format(otp=otp, **tags) subject = subject.replace("<otp>", otp) subject = subject.replace("<serial>", serial) subject = subject.format(otp=otp, **tags) log.debug("sending Email to {0!r}".format(recipient)) # The token specific identifier has priority over the system wide identifier identifier = self.get_tokeninfo("email.identifier") or get_from_config("email.identifier") if identifier: # New way to send email ret = send_email_identifier(identifier, recipient, subject, message, mimetype=mimetype) else: # old way to send email / DEPRECATED mailserver = get_from_config("email.mailserver", "localhost") port = int(get_from_config("email.port", 25)) username = get_from_config("email.username") password = get_from_config("email.password") mail_from = get_from_config("email.mailfrom", "privacyidea@localhost") email_tls = get_from_config("email.tls", default=False, return_bool=True) ret = send_email_data(mailserver, subject, message, mail_from, recipient, username, password, port, email_tls) return ret, message
def _compose_email(self, message="<otp>", subject="Your OTP", mimetype="plain"): """ send email :param message: the email submit message - could contain placeholders like <otp> or <serial> :type message: string :param mimetype: the message MIME type - one of "plain", "html" :type mimetype: basestring :return: submitted message :rtype: string """ ret = None recipient = self._email_address otp = self.get_otp()[2] serial = self.get_serial() message = message.replace("<otp>", otp) message = message.replace("<serial>", serial) message = message.format(otp=otp, serial=serial) subject = subject.replace("<otp>", otp) subject = subject.replace("<serial>", serial) subject = subject.format(otp=otp, serial=serial) log.debug("sending Email to {0!r}".format(recipient)) identifier = get_from_config("email.identifier") if identifier: # New way to send email ret = send_email_identifier(identifier, recipient, subject, message, mimetype=mimetype) else: # old way to send email / DEPRECATED mailserver = get_from_config("email.mailserver", "localhost") port = int(get_from_config("email.port", 25)) username = get_from_config("email.username") password = get_from_config("email.password") mail_from = get_from_config("email.mailfrom", "privacyidea@localhost") email_tls = get_from_config("email.tls", default=False, return_bool=True) ret = send_email_data(mailserver, subject, message, mail_from, recipient, username, password, port, email_tls) return ret, message
def submit_message(self, phone, message): """ Submits the message for phone to the email gateway. Returns true in case of success In case of a failure an exception is raised """ if self.smsgateway: identifier = self.smsgateway.option_dict.get("SMTPIDENTIFIER") recipient = self.smsgateway.option_dict.get("MAILTO").format( otp=message, phone=phone) subject = self.smsgateway.option_dict.get( "SUBJECT", "{phone}").format(otp=message, phone=phone) body = self.smsgateway.option_dict.get("BODY", "{otp}").format(otp=message, phone=phone) else: identifier = self.config.get("IDENTIFIER") server = self.config.get("MAILSERVER") sender = self.config.get("MAILSENDER") recipient = self.config.get("MAILTO") subject = self.config.get("SUBJECT", PHONE_TAG) body = self.config.get("BODY", MSG_TAG) if not (server and recipient and sender) and not (identifier and \ recipient): log.error("incomplete config: %s. MAILTO and (IDENTIFIER or " "MAILSERVER and MAILSENDER) needed" % self.config) raise SMSError(-1, "Incomplete SMS config.") log.debug("submitting message {0!r} to {1!s}".format(body, phone)) recipient = string.replace(recipient, PHONE_TAG, phone) subject = string.replace(subject, PHONE_TAG, phone) subject = string.replace(subject, MSG_TAG, message) body = string.replace(body, PHONE_TAG, phone) body = string.replace(body, MSG_TAG, message) if identifier: r = send_email_identifier(identifier, recipient, subject, body) else: username = self.config.get("MAILUSER") password = self.config.get("MAILPASSWORD") r = send_email_data(server, subject, body, sender, recipient, username, password) if not r: raise SMSError(500, "Failed to deliver SMS to SMTP Gateway.") return True
def do(self, action, options=None): """ This method executes the defined action in the given event. :param action: :param environment: :param options: :return: """ ret = True g = options.get("g") request = options.get("request") logged_in_user = g.logged_in_user user = get_user_from_param(request.all_data) if action.lower() == "sendmail" and logged_in_user.get("role") == \ ROLE.ADMIN and not user.is_empty() and user.login: emailconfig = options.get("emailconfig") if not emailconfig: log.error("Missing parameter 'emailconfig'") raise ParameterError("Missing parameter 'emailconfig'") useremail = user.info.get("email") subject = options.get("subject") or "An action was performed on " \ "your token." body = options.get("body") or DEFAULT_BODY body = body.format( admin=logged_in_user.get("username"), realm=logged_in_user.get("realm"), action=request.path, serial=g.audit_object.audit_data.get("serial"), url=request.url_root, user=user.info.get("givenname") ) try: ret = send_email_identifier(emailconfig, recipient=useremail, subject=subject, body=body) except Exception as exx: log.error("Failed to send email: {0!s}".format(exx)) ret = False if ret: log.info("Sent a notification email to user {0}".format(user)) else: log.warning("Failed to send a notification email to user " "{0}".format(user)) return ret
def create_recoverycode(user, email=None, expiration_seconds=3600, recoverycode=None, base_url=""): """ Create and send a password recovery code :param user: User for whom the password reset code should be sent :type user: User Object :param email: The optional email of the user :param recoverycode: Only used for testing purpose :return: bool """ base_url = base_url.strip("recover") base_url += "#" recoverycode = recoverycode or generate_password(size=24) hash_code = hash_with_pepper(recoverycode) # send this recoverycode # pwreset = PasswordReset(hash_code, username=user.login, realm=user.realm, expiration_seconds=expiration_seconds) pwreset.save() res = False if not user: raise UserError("User required for recovery token.") user_email = user.info.get("email") if email and email.lower() != user_email.lower(): raise UserError("The email does not match the users email.") identifier = get_from_config("recovery.identifier") if identifier: # send email r = send_email_identifier( identifier, user_email, "Your password reset", BODY.format(base_url, user.login, user.realm, recoverycode)) if not r: raise privacyIDEAError("Failed to send email. {0!s}".format(r)) else: raise ConfigAdminError("Missing configuration " "recovery.identifier.") res = True return res
def do(self, action, options=None): """ This method executes the defined action in the given event. :param action: :param options: Contains the flask parameters g, request, response and the handler_def configuration :type options: dict :return: """ ret = True g = options.get("g") request = options.get("request") response = options.get("response") content = json.loads(response.data) handler_def = options.get("handler_def") handler_options = handler_def.get("options", {}) notify_type = handler_options.get("To", NOTIFY_TYPE.TOKENOWNER) try: logged_in_user = g.logged_in_user except Exception: logged_in_user = {} tokenowner = self._get_tokenowner(request) log.debug("Executing event for action {0!s}, user {1!s}," "logged_in_user {2!s}".format(action, tokenowner, logged_in_user)) # Determine recipient recipient = None if notify_type == NOTIFY_TYPE.TOKENOWNER and not tokenowner.is_empty(): recipient = { "givenname": tokenowner.info.get("givenname"), "surname": tokenowner.info.get("surname"), "username": tokenowner.login, "userrealm": tokenowner.realm, "email": tokenowner.info.get("email"), "mobile": tokenowner.info.get("mobile") } elif notify_type == NOTIFY_TYPE.INTERNAL_ADMIN: username = handler_options.get("To "+NOTIFY_TYPE.INTERNAL_ADMIN) internal_admin = get_db_admin(username) recipient = { "givenname": username, "email": internal_admin.email if internal_admin else "" } elif notify_type == NOTIFY_TYPE.ADMIN_REALM: # Send emails to all the users in the specified admin realm admin_realm = handler_options.get("To "+NOTIFY_TYPE.ADMIN_REALM) ulist = get_user_list({"realm": admin_realm}) # create a list of all user-emails, if the user has an email emails = [u.get("email") for u in ulist if u.get("email")] recipient = { "givenname": "admin of realm {0!s}".format(admin_realm), "email": emails } elif notify_type == NOTIFY_TYPE.LOGGED_IN_USER: # Send notification to the logged in user if logged_in_user.get("user") and not logged_in_user.get("realm"): # internal admins have no realm internal_admin = get_db_admin(logged_in_user.get("user")) if internal_admin: recipient = { "givenname": logged_in_user.get("user"), "email": internal_admin.email if internal_admin else "" } else: # Try to find the user in the specified realm user_obj = User(logged_in_user.get("user"), logged_in_user.get("realm")) if user_obj: recipient = { "givenname": user_obj.info.get("givenname"), "surname": user_obj.info.get("surname"), "email": user_obj.info.get("email"), "mobile": user_obj.info.get("mobile") } elif notify_type == NOTIFY_TYPE.EMAIL: email = handler_options.get("To "+NOTIFY_TYPE.EMAIL, "").split(",") recipient = { "email": email } else: log.warning("Was not able to determine the recipient for the user " "notification: {0!s}".format(handler_def)) if recipient: # Collect all data body = handler_options.get("body") or DEFAULT_BODY serial = request.all_data.get("serial") or \ content.get("detail", {}).get("serial") or \ g.audit_object.audit_data.get("serial") registrationcode = content.get("detail", {}).get("registrationcode") tokentype = None if serial: tokens = get_tokens(serial=serial) if tokens: tokentype = tokens[0].get_tokentype() else: token_objects = get_tokens(user=tokenowner) serial = ','.join([tok.get_serial() for tok in token_objects]) body = body.format( admin=logged_in_user.get("username"), realm=logged_in_user.get("realm"), action=request.path, serial=serial, url=request.url_root, user=tokenowner.info.get("givenname"), surname=tokenowner.info.get("surname"), givenname=recipient.get("givenname"), username=tokenowner.login, userrealm=tokenowner.realm, tokentype=tokentype, registrationcode=registrationcode, recipient_givenname=recipient.get("givenname"), recipient_surname=recipient.get("surname") ) # Send notification if action.lower() == "sendmail": emailconfig = handler_options.get("emailconfig") useremail = recipient.get("email") subject = handler_options.get("subject") or \ "An action was performed on your token." try: ret = send_email_identifier(emailconfig, recipient=useremail, subject=subject, body=body) except Exception as exx: log.error("Failed to send email: {0!s}".format(exx)) ret = False if ret: log.info("Sent a notification email to user {0}".format( recipient)) else: log.warning("Failed to send a notification email to user " "{0}".format(recipient)) elif action.lower() == "sendsms": smsconfig = handler_options.get("smsconfig") userphone = recipient.get("mobile") try: ret = send_sms_identifier(smsconfig, userphone, body) except Exception as exx: log.error("Failed to send sms: {0!s}".format(exx)) ret = False if ret: log.info("Sent a notification sms to user {0}".format( recipient)) else: log.warning("Failed to send a notification email to user " "{0}".format(recipient)) return ret
def do(self, action, options=None): """ This method executes the defined action in the given event. :param action: :param options: Contains the flask parameters g, request, response and the handler_def configuration :type options: dict :return: """ ret = True g = options.get("g") request = options.get("request") response = options.get("response") content = self._get_response_content(response) handler_def = options.get("handler_def") handler_options = handler_def.get("options", {}) notify_type = handler_options.get("To", NOTIFY_TYPE.TOKENOWNER) reply_to_type = handler_options.get("reply_to") try: logged_in_user = g.logged_in_user except Exception: logged_in_user = {} tokenowner = self._get_tokenowner(request) log.debug(u"Executing event for action {0!r}, user {1!r}, " u"logged_in_user {2!r}".format(action, tokenowner, logged_in_user)) # Determine recipient recipient = None reply_to = None if reply_to_type == NOTIFY_TYPE.NO_REPLY_TO: reply_to = "" elif reply_to_type == NOTIFY_TYPE.TOKENOWNER and not tokenowner.is_empty( ): reply_to = tokenowner.info.get("email") elif reply_to_type == NOTIFY_TYPE.INTERNAL_ADMIN: username = handler_options.get("reply_to " + NOTIFY_TYPE.INTERNAL_ADMIN) internal_admin = get_db_admin(username) reply_to = internal_admin.email if internal_admin else "" elif reply_to_type == NOTIFY_TYPE.ADMIN_REALM: # Adds all email addresses from a specific admin realm to the reply-to-header admin_realm = handler_options.get("reply_to " + NOTIFY_TYPE.ADMIN_REALM) attr = is_attribute_at_all() ulist = get_user_list({"realm": admin_realm}, custom_attributes=attr) # create a list of all user-emails, if the user has an email emails = [u.get("email") for u in ulist if u.get("email")] reply_to = ",".join(emails) elif reply_to_type == NOTIFY_TYPE.LOGGED_IN_USER: # Add email address from the logged in user into the reply-to header if logged_in_user.get( "username") and not logged_in_user.get("realm"): # internal admins have no realm internal_admin = get_db_admin(logged_in_user.get("username")) if internal_admin: reply_to = internal_admin.email if internal_admin else "" else: # Try to find the user in the specified realm user_obj = User(logged_in_user.get("username"), logged_in_user.get("realm")) if user_obj: reply_to = user_obj.info.get("email") if user_obj else "" elif reply_to_type == NOTIFY_TYPE.EMAIL: email = handler_options.get("reply_to " + NOTIFY_TYPE.EMAIL, "").split(",") reply_to = email[0] else: log.warning("Was not able to determine the email for the reply-to " "header: {0!s}".format(handler_def)) if notify_type == NOTIFY_TYPE.TOKENOWNER and not tokenowner.is_empty(): recipient = { "givenname": tokenowner.info.get("givenname"), "surname": tokenowner.info.get("surname"), "username": tokenowner.login, "userrealm": tokenowner.realm, "email": tokenowner.info.get("email"), "mobile": tokenowner.info.get("mobile") } elif notify_type == NOTIFY_TYPE.INTERNAL_ADMIN: username = handler_options.get("To " + NOTIFY_TYPE.INTERNAL_ADMIN) internal_admin = get_db_admin(username) recipient = { "givenname": username, "email": internal_admin.email if internal_admin else "" } elif notify_type == NOTIFY_TYPE.ADMIN_REALM: # Send emails to all the users in the specified admin realm admin_realm = handler_options.get("To " + NOTIFY_TYPE.ADMIN_REALM) attr = is_attribute_at_all() ulist = get_user_list({"realm": admin_realm}, custom_attributes=attr) # create a list of all user-emails, if the user has an email emails = [u.get("email") for u in ulist if u.get("email")] recipient = { "givenname": "admin of realm {0!s}".format(admin_realm), "email": emails } elif notify_type == NOTIFY_TYPE.LOGGED_IN_USER: # Send notification to the logged in user if logged_in_user.get( "username") and not logged_in_user.get("realm"): # internal admins have no realm internal_admin = get_db_admin(logged_in_user.get("username")) if internal_admin: recipient = { "givenname": logged_in_user.get("username"), "email": internal_admin.email if internal_admin else "" } else: # Try to find the user in the specified realm user_obj = User(logged_in_user.get("username"), logged_in_user.get("realm")) if user_obj: recipient = { "givenname": user_obj.info.get("givenname"), "surname": user_obj.info.get("surname"), "email": user_obj.info.get("email"), "mobile": user_obj.info.get("mobile") } elif notify_type == NOTIFY_TYPE.EMAIL: email = handler_options.get("To " + NOTIFY_TYPE.EMAIL, "").split(",") recipient = {"email": email} else: log.warning("Was not able to determine the recipient for the user " "notification: {0!s}".format(handler_def)) if recipient or action.lower() == "savefile": # In case of "savefile" we do not need a recipient # Collect all data body = handler_options.get("body") or DEFAULT_BODY if body.startswith("file:"): # pragma no cover # We read the template from the file. filename = body[5:] try: with open(filename, "r", encoding="utf-8") as f: body = f.read() except Exception as e: log.warning( u"Failed to read email template from file {0!r}: {1!r}" .format(filename, e)) log.debug(u"{0!s}".format(traceback.format_exc())) subject = handler_options.get("subject") or \ "An action was performed on your token." serial = request.all_data.get("serial") or \ content.get("detail", {}).get("serial") or \ g.audit_object.audit_data.get("serial") registrationcode = content.get("detail", {}).get("registrationcode") pin = content.get("detail", {}).get("pin") googleurl_value = content.get("detail", {}).get("googleurl", {}).get("value") googleurl_img = content.get("detail", {}).get("googleurl", {}).get("img") tokentype = None if serial: tokens = get_tokens(serial=serial) if tokens: tokentype = tokens[0].get_tokentype() else: token_objects = get_tokens(user=tokenowner) serial = ','.join([tok.get_serial() for tok in token_objects]) tags = create_tag_dict( logged_in_user=logged_in_user, request=request, client_ip=g.client_ip, pin=pin, googleurl_value=googleurl_value, recipient=recipient, tokenowner=tokenowner, serial=serial, tokentype=tokentype, registrationcode=registrationcode, escape_html=action.lower() == "sendmail" and handler_options.get("mimetype", "").lower() == "html") body = to_unicode(body).format(googleurl_img=googleurl_img, **tags) subject = subject.format(**tags) # Send notification if action.lower() == "sendmail": emailconfig = handler_options.get("emailconfig") mimetype = handler_options.get("mimetype", "plain") useremail = recipient.get("email") attach_qrcode = handler_options.get("attach_qrcode", False) if attach_qrcode and googleurl_img: # get the image part of the googleurl googleurl = urlopen(googleurl_img) mail_body = MIMEMultipart('related') mail_body.attach(MIMEText(body, mimetype)) mail_img = MIMEImage(googleurl.read()) mail_img.add_header('Content-ID', '<token_image>') mail_img.add_header( 'Content-Disposition', 'inline; filename="{0!s}.png"'.format(serial)) mail_body.attach(mail_img) body = mail_body try: ret = send_email_identifier(emailconfig, recipient=useremail, subject=subject, body=body, reply_to=reply_to, mimetype=mimetype) except Exception as exx: log.error("Failed to send email: {0!s}".format(exx)) ret = False if ret: log.info("Sent a notification email to user {0}".format( recipient)) else: log.warning("Failed to send a notification email to user " "{0}".format(recipient)) elif action.lower() == "savefile": spooldir = get_app_config_value( "PI_NOTIFICATION_HANDLER_SPOOLDIRECTORY", "/var/lib/privacyidea/notifications/") filename = handler_options.get("filename") random = get_alphanum_str(16) filename = filename.format(random=random, **tags).lstrip(os.path.sep) outfile = os.path.normpath(os.path.join(spooldir, filename)) if not outfile.startswith(spooldir): log.error( u'Cannot write outside of spooldir {0!s}!'.format( spooldir)) else: try: with open(outfile, "w") as f: f.write(body) except Exception as err: log.error( u"Failed to write notification file: {0!s}".format( err)) elif action.lower() == "sendsms": smsconfig = handler_options.get("smsconfig") userphone = recipient.get("mobile") try: ret = send_sms_identifier(smsconfig, userphone, body) except Exception as exx: log.error("Failed to send sms: {0!s}".format(exx)) ret = False if ret: log.info("Sent a notification sms to user {0}".format( recipient)) else: log.warning("Failed to send a notification email to user " "{0}".format(recipient)) return ret
def do(self, action, options=None): """ This method executes the defined action in the given event. :param action: :param options: Contains the flask parameters g and request and the handler_def configuration :type options: dict :return: """ ret = True g = options.get("g") request = options.get("request") handler_def = options.get("handler_def") try: logged_in_user = g.logged_in_user except Exception: logged_in_user = {} user = self._get_user(request) log.debug("Executing event for action {0!s}, user {1!s}," "logged_in_user {2!s}".format(action, user, logged_in_user)) user_type = True if logged_in_user.get("role"): # If there is a logged_in_user, it should be the admin user_type = logged_in_user.get("role") == ROLE.ADMIN if not user.is_empty() and user.login and user_type: handler_options = handler_def.get("options", {}) body = handler_options.get("body") or DEFAULT_BODY serial = g.audit_object.audit_data.get("serial") if not serial: token_objects = get_tokens(user=user, maxfail=True) serial = ','.join([tok.get_serial() for tok in token_objects]) body = body.format(admin=logged_in_user.get("username"), realm=logged_in_user.get("realm"), action=request.path, serial=serial, url=request.url_root, user=user.info.get("givenname")) if action.lower() == "sendmail": emailconfig = handler_options.get("emailconfig") useremail = user.info.get("email") subject = handler_options.get("subject") or \ "An action was performed on your token." try: ret = send_email_identifier(emailconfig, recipient=useremail, subject=subject, body=body) except Exception as exx: log.error("Failed to send email: {0!s}".format(exx)) ret = False if ret: log.info( "Sent a notification email to user {0}".format(user)) else: log.warning("Failed to send a notification email to user " "{0}".format(user)) elif action.lower() == "sendsms": smsconfig = handler_options.get("smsconfig") userphone = user.info.get("mobile") try: ret = send_sms_identifier(smsconfig, userphone, body) except Exception as exx: log.error("Failed to send sms: {0!s}".format(exx)) ret = False if ret: log.info( "Sent a notification sms to user {0}".format(user)) else: log.warning("Failed to send a notification email to user " "{0}".format(user)) return ret
def register_post(): """ Register a new user in the realm/userresolver. To do so, the user resolver must be writeable like an SQLResolver. Registering a user in fact creates a new user and also creates the first token for the user. The following values are needed to register the user: * username (mandatory) * givenname (mandatory) * surname (mandatory) * email address (mandatory) * password (mandatory) * mobile phone (optional) * telephone (optional) The user receives a registration token via email to be able to login with his self chosen password and the registration token. :jsonparam username: The login name of the new user. Check if it already exists :jsonparam givenname: The givenname of the new user :jsonparam surname: The surname of the new user :jsonparam email: The email address of the new user :jsonparam password: The password of the new user. This is the resolver password of the new user. :jsonparam mobile: The mobile phone number :jsonparam phone: The phone number (land line) of the new user :return: a json result with a boolean "result": true """ username = getParam(request.all_data, "username", required) surname = getParam(request.all_data, "surname", required) givenname = getParam(request.all_data, "givenname", required) email = getParam(request.all_data, "email", required) password = getParam(request.all_data, "password", required) mobile = getParam(request.all_data, "mobile") phone = getParam(request.all_data, "phone") options = {"g": g, "clientip": request.remote_addr} g.audit_object.log({"info": username}) # Add all params to the options for key, value in request.all_data.items(): if value and key not in ["g", "clientip"]: options[key] = value # 1. determine, in which resolver/realm the user should be created realm = g.policy_object.get_action_values(ACTION.REALM, scope=SCOPE.REGISTER, unique=True) if not realm: # No policy for realm, so we use the default realm realm = get_default_realm else: # we use the first realm in the list realm = realm[0] resolvername = g.policy_object.get_action_values(ACTION.RESOLVER, scope=SCOPE.REGISTER, unique=True) if not resolvername: raise RegistrationError("No resolver specified to register in!") resolvername = resolvername[0] # Check if the user exists user = User(username, realm=realm, resolver=resolvername) if user.exist(): raise RegistrationError("The username is already registered!") # Create user uid = create_user( resolvername, { "username": username, "email": email, "phone": phone, "mobile": mobile, "surname": surname, "givenname": givenname, "password": password }) # 3. create a registration token for this user user = User(username, realm=realm, resolver=resolvername) token = init_token({"type": "registration"}, user=user) # 4. send the registration token to the users email registration_key = token.init_details.get("otpkey") smtpconfig = g.policy_object.get_action_values(ACTION.EMAILCONFIG, scope=SCOPE.REGISTER, unique=True) if not smtpconfig: raise RegistrationError("No SMTP server configuration specified!") smtpconfig = smtpconfig[0] # Send the registration key via email r = send_email_identifier( smtpconfig, email, "Your privacyIDEA registration", "Your registration token is %s" % registration_key) log.debug("Registration email sent to %s" % email) g.audit_object.log({"success": r}) return send_result(r)