def activation(code_activation): """ Valider la préinscription d'un utilisateur, puis rediriger vers la page de login :param code_activation: le code d'activation :return: """ if code_activation is not None and code_activation != "": try: mail = helper.unsing_string(code_activation)["mail"] utilisateur = user.find_user_by_mail(mail, actif_only=False) if utilisateur is not None and not utilisateur.actif: if user.activate_user(utilisateur.id): flash(("Bienvenue %s ! Tu peux maintenant t'identifier" % utilisateur.mail), "success") app.logger.info("ACTIVATION - activated the account for utilisateur with id %s", utilisateur.id) else: flash(("Oups ... Erreur d'activation. Merci de contacter l'adminsitrateur."), "success") app.logger.info("ACTIVATION - error activating the account for user with id %s", utilisateur.id) except Exception, e: flash("URL incorrecte, merci de relancer la procédure d'inscription ou de " "contacter un admnistrateur si le problème persiste", "danger") app.logger.error( "ACTIVATION - critical error decoding activation_code. Exception : %s", e.__class__.__name__ )
def inscription(): """ Vue d'enregistrement pour les nouveaux utilisateurs. GET : 1/ Page d'accueil qui permet de se logguer ou créer un utilisateur. On peut se logguer via son compte ou via LinkedIn. 2/ Si l'utilisateur veut créer un compte, il rentre une adresse adresse mail @mines-paris.org / @mines-nancy.org / @mines-saint-etienne.org ainsi qu'un mot de passe. POST : 1/ On vérifie que le form est valable (mots de passe corrects et égaux) 2/ On cherche s'il existe déjà un utilisateur pour l'ancien trouvé -> Si oui 2.1/ Si il existe déjà un utilisateur ACTIF, alors annuler l'inscription 2.2/ Si il existe déjà un utilisateur INACTIF, rediriger vers resend -> Si non -> 3 3/ Création de l'inscription a. On crée la string signée à envoyer b. On crée l'utilisateur c. On envoie le mail de confirmation d. On redirige vers la page de login :return: """ form = user.registration_form(request.form) if current_user.is_authenticated(): return redirect(url_for('annuaire_view')) if request.method == 'POST' and form.validate(): # Chargement des infos du form mail_ancien = form.mail_ancien.data+form.domaine_ancien.data password = form.password.data app.logger.info("REGISTER - Trying to add user for %s", mail_ancien) # Gestion des utilisateurs : si un compte existe déjà, le signaler utilisateur = user.find_user_by_mail(mail_ancien, actif_only=False) if utilisateur is not None: if utilisateur.actif: # Un compte actif existe déjà = interdit d'en re-créer un flash("Un compte existe déjà pour cet ancien !", "warning") app.logger.warning("REGISTER - double register for user with id %s", utilisateur.id) return redirect(url_for("login")) else: # un compte incatif existe déjà = renvoyer le mail de validation app.logger.warning("REGISTER - resend for utilisateur with id %s", utilisateur.id) return render_template("user/resend.html", id_utilisateur=utilisateur.id) else: # Signature du mail user signature = helper.generate_signed_string_from_mail(mail_ancien) # Création de l'utilisateur if user.create_user(mail_ancien, password): # Envoi du mail annuaire.helper.send_activation_mail(mail_ancien, signature) flash("Succès : un mail d'activation vous sera envoyé prochainement", "success") app.logger.info("REGISTER - created preinscription user with mail %s", mail_ancien) return redirect(url_for("login")) else: flash("Échec lors de l'inscription. Merci de contacter l'administrateur", "danger") app.logger.error("REGISTER - problème à la création de l'utilisateur : %s", mail_ancien) return redirect(url_for("login")) linkedin_url = ("https://www.linkedin.com/uas/oauth2/authorization?" "response_type=code&" "client_id=%s&" "scope=%s" "&state=%s" "&redirect_uri=%s" % (app.config['LINKEDIN_KEY'], 'r_basicprofile', helper.generate_csrf_token(), url_for('linkedin_login', _external=True))) return render_template('user/register.html', form=form, linkedin_url=linkedin_url)
def reset_password_activate(activation): """ Vue qui correspond au lien envoyé dans l'e-mail de reset du password. Méthodes : - GET : Afficher le formulaire - POST : Submit et traitement du formulaire Dans tous les cas, on vérifie la validité de la signature : - On arrive à la lire - On arrive à extraire mail et date - Le mail existe dans notre user base - La date est inférieure à datetime.utcnow() Une fois la signature validée, on affiche ou on submit le formulaire. Si pas de code d'activation, le routing de Flask devrait rediriger vers :func:`reset_password()`, mais au cas où, on pète :param str activation: Le code d'activation. Est créé + signé avec itsdangerous. Contient les données de la forme suivante : { "mail" : "*****@*****.**", "date" : "yyyyMMddhhmm" } """ form = user.create_new_password_form() if activation is not None and activation != "": app.logger.info("RESET PASS - Start") try: mail = helper.unsing_string(activation)["mail"] date = dt.datetime.strptime(helper.unsing_string(activation)["date"], DATETIME_FORMAT) utilisateur = user.find_user_by_mail(mail, actif_only=True) app.logger.info("RESET PASS - Trying reset for user : %s, with date (utc) : %s", mail, date) if utilisateur is not None and date > dt.datetime.utcnow(): if request.method == "POST": form = user.create_new_password_form(request.form) if form.validate(): success = user.reset_password_by_id(utilisateur.id, form.new_password.data) if not success: flash("Oops ! Une erreur a eu lieu lors de la mise à jour de ton mot de passe... <br>" "Merci de relancer la procédure, ou de contacter un administrateur " "si le problème persiste", "danger") app.logger.error("RESET PASS - FAIL - update fail fur user with id : %s", utilisateur.id) else: flash("Succès ! Ton mot de passe a été modifié.", "success") app.logger.warning("RESET PASS - FAIL - update fail fur user with id : %s", utilisateur.id) return redirect(url_for('login')) return render_template( "user/password/create_new_password.html", activation=activation, form=form ) elif utilisateur is None: flash("Oops ! Ce code ne correspond à aucun utilisateur... <br>" "Merci de relancer la procédure, ou de contacter un administrateur " "si le problème persiste", "danger") app.logger.error("RESET PASS - FAIL - user does not exist, mail : %s", mail) elif date > dt.datetime.utcnow(): flash("Oops ! Ce code est périmé... " "Pour rappel, les codes ne sont valables que 12h. <br>" "Merci de renvoyer une demande de mot de passe !", "warning") app.logger.error( "RESET PASS - FAIL - The token is too old, for user %s ; " "mail is %s ; max date (utc) is %s", utilisateur.id, mail, date ) else: raise Exception("Strange exception, you shouldn't be here ....") except Exception, e: flash("URL incorrecte, merci de relancer la procédure de changement de mot de passe, " "ou de contacter un admnistrateur si le problème persiste", "danger") app.logger.error( "RESET PASS - critical error decoding activation_code. Exception : %s", e.__class__.__name__ ) return redirect(url_for("reset_password"))
def reset_password(): """ Pour qu'un utilisateur met à jour son mot de passe oublié. L'ancien tape son adresse. Si un utilisateur existe, on génère une signature avec `itsdangerous` (voir :func:`helper.security.generate_signed_string_from_mail_and_date`) Cette signature contient : - Le mail de l'utilisateur - La date max d'utilisation de la signature - Heure UTC - Par défaut : utcnow() + 12h Cette signature "activation" est ensuite envoyée par mail, dans le lien https://truc.com/rest/<activation> Méthodes : - GET : afficher le formulaire - POST : submit le formulaire ATTENTION : le reset de mot de passe est donc stateless, et l'utilisateur peut utiliser le lien autant de fois qu'il le souhaite pendant ses 12h d'activité. """ form = user.request_new_password_form() # Si c'est un POST, on traite le formulaire if request.method == "POST": form = user.request_new_password_form(request.form) # Validation du formulaire if form.validate(): app.logger.info("REQUEST PASS RESET - START - updating pass for user with mail : %s", form.mail_ancien.data) mail_ancien = form.mail_ancien.data+form.domaine_ancien.data utilisateur_confirmed = user.find_user_by_mail(mail_ancien) is not None # Si l'utilisateur n'existe pas dans la base, on redirige vers # la page de création d'un compte, avec un message if not utilisateur_confirmed: flash( "Il semblerait que cet utilisateur n'existe pas dans notre base de données." "<br>As-tu pensé à créer un compte ?", "warning" ) app.logger.error("REQUEST PASS RESET - FAIL - Not exist user with mail : %s", form.mail_ancien.data) return redirect(url_for("inscription")) # Si l'utilisateur existe, on lui envoie un mail # Et on redirige vers "login" else: # TODO : que se passe-t-il si l'envoi de mail fail ? date_max = dt.datetime.utcnow() + dt.timedelta(hours=12) signature = generate_signed_string_from_mail_and_date(mail_ancien, date_max.strftime(DATETIME_FORMAT)) annuaire.helper.send_reset_password_mail(mail_ancien, signature) flash( "Tu vas bientôt recevoir un mail avec les instructions pour mettre" " à jour ton mont de passe.", "success" ) app.logger.info("REQUEST PASS RESET - SUCCESS - updating pass for user with mail : %s", form.mail_ancien.data) return redirect(url_for("login")) return render_template( "user/password/request_new_password.html", form = form )