about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSam2013-10-15 18:17:02 -0500
committerSam2013-10-15 18:17:02 -0500
commit5b7d03c4af45a6e9b556368746d3ff04b6942a57 (patch)
treec8e1440ec7688af54560febcf22783b26c146fcd
parent612bc953cc82bee292a6a230b6604cc3070ea6d8 (diff)
downloadgenenetwork2-5b7d03c4af45a6e9b556368746d3ff04b6942a57.tar.gz
Password reset now works...but needs some error checking still
-rw-r--r--wqflask/wqflask/templates/new_security/password_reset.html2
-rw-r--r--wqflask/wqflask/user_manager.py191
-rw-r--r--wqflask/wqflask/views.py64
3 files changed, 154 insertions, 103 deletions
diff --git a/wqflask/wqflask/templates/new_security/password_reset.html b/wqflask/wqflask/templates/new_security/password_reset.html
index c66ddd07..cda1e477 100644
--- a/wqflask/wqflask/templates/new_security/password_reset.html
+++ b/wqflask/wqflask/templates/new_security/password_reset.html
@@ -29,8 +29,10 @@
 
             <form class="form-horizontal" action="/n/password_reset_step2" data-validate="parsley"
                   method="POST" name="login_user_form">
+
                 <fieldset>
 
+                    <input class="hidden" name="user_encode" value="{{ user_encode }}">
 
 
                     <div class="control-group">
diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py
index 1df2c153..766f49df 100644
--- a/wqflask/wqflask/user_manager.py
+++ b/wqflask/wqflask/user_manager.py
@@ -17,6 +17,8 @@ import hashlib
 import hmac
 import base64
 
+import urlparse
+
 import simplejson as json
 
 from sqlalchemy import orm
@@ -140,7 +142,7 @@ class RegisterUser(object):
 
         print("No errors!")
 
-        self.set_password(password)
+        set_password(password, user)
 
         self.user.registration_info = json.dumps(basic_info(), sort_keys=True)
 
@@ -156,48 +158,49 @@ class RegisterUser(object):
         self.thank_you_mode = True
 
 
-    def set_password(self, password):
-        pwfields = Bunch()
+def set_password(password, user):
+    pwfields = Bunch()
+
+    pwfields.algorithm = "pbkdf2"
+    pwfields.hashfunc = "sha256"
+    #hashfunc = getattr(hashlib, pwfields.hashfunc)
 
-        pwfields.algorithm = "pbkdf2"
-        pwfields.hashfunc = "sha256"
-        #hashfunc = getattr(hashlib, pwfields.hashfunc)
+    # Encoding it to base64 makes storing it in json much easier
+    pwfields.salt = base64.b64encode(os.urandom(32))
 
-        # Encoding it to base64 makes storing it in json much easier
-        pwfields.salt = base64.b64encode(os.urandom(32))
+    # https://forums.lastpass.com/viewtopic.php?t=84104
+    pwfields.iterations = 100000
+    pwfields.keylength = 32
 
-        # https://forums.lastpass.com/viewtopic.php?t=84104
-        pwfields.iterations = 100000
-        pwfields.keylength = 32
+    pwfields.created_ts = timestamp()
+    # One more check on password length
+    assert len(password) >= 6, "Password shouldn't be so short here"
 
-        pwfields.created_ts = timestamp()
-        # One more check on password length
-        assert len(password) >= 6, "Password shouldn't be so short here"
+    print("pwfields:", vars(pwfields))
+    print("locals:", locals())
 
-        print("pwfields:", vars(pwfields))
-        print("locals:", locals())
+    enc_password = Password(password,
+                            pwfields.salt,
+                            pwfields.iterations,
+                            pwfields.keylength,
+                            pwfields.hashfunc)
 
-        enc_password = Password(password,
-                                pwfields.salt,
-                                pwfields.iterations,
-                                pwfields.keylength,
-                                pwfields.hashfunc)
+    pwfields.password = enc_password.password
+    pwfields.encrypt_time = enc_password.encrypt_time
 
-        pwfields.password = enc_password.password
-        pwfields.encrypt_time = enc_password.encrypt_time
+    user.password = json.dumps(pwfields.__dict__,
+                                    sort_keys=True,
+                                   )
 
-        self.user.password = json.dumps(pwfields.__dict__,
-                                        sort_keys=True,
-                                       )
 
 class VerificationEmail(object):
     template_name =  "email/verification.txt"
-    key_preface = "verification_code"
+    key_prefix = "verification_code"
     subject = "GeneNetwork email verification"
 
     def __init__(self, user):
         verification_code = str(uuid.uuid4())
-        key = self.key_preface + "verification_code:" + verification_code
+        key = self.key_prefix + ":" + verification_code
 
         data = json.dumps(dict(id=user.id,
                                timestamp=timestamp())
@@ -214,7 +217,7 @@ class VerificationEmail(object):
 
 class ForgotPasswordEmail(VerificationEmail):
     template_name = "email/forgot_password.txt"
-    key_preface = "forgot_password_code"
+    key_prefix = "forgot_password_code"
     subject = "GeneNetwork password reset"
 
 
@@ -239,16 +242,71 @@ def basic_info():
 
 @app.route("/manage/verify_email")
 def verify_email():
-    print("in verify_email request.url is:", request.url)
-    verify_url_hmac(request.url)
-    verification_code = request.args['code']
-    data = Redis.get("verification_code:" + verification_code)
-    data = json.loads(data)
-    print("data is:", data)
-    user = model.User.query.get(data['id'])
+    user = DecodeUser(VerificationEmail.key_prefix).user
     user.confirmed = json.dumps(basic_info(), sort_keys=True)
     db_session.commit()
 
+@app.route("/n/password_reset")
+def password_reset():
+    print("in password_reset request.url is:", request.url)
+
+    # We do this mainly just to assert that it's in proper form for displaying next page
+    # Really not necessary but doesn't hurt
+    user_encode = DecodeUser(ForgotPasswordEmail.key_prefix).reencode_standalone()
+
+    return render_template("new_security/password_reset.html", user_encode=user_encode)
+
+@app.route("/n/password_reset_step2", methods=('POST',))
+def password_reset_step2():
+    print("in password_reset request.url is:", request.url)
+
+    errors = []
+
+    user_encode = request.form['user_encode']
+    verification_code, separator, hmac = user_encode.partition(':')
+
+    hmac_verified = actual_hmac_creation(verification_code)
+    print("locals are:", locals())
+
+
+    assert hmac == hmac_verified, "Someone has been naughty"
+
+    user = DecodeUser.actual_get_user(ForgotPasswordEmail.key_prefix, verification_code)
+    print("user is:", user)
+
+    password = request.form['password']
+
+    set_password(password, user)
+    db_session.commit()
+
+    flash("Password changed successfully. You can now sign in.", "alert-info")
+    response = make_response(redirect(url_for('login')))
+
+    return response
+
+class DecodeUser(object):
+
+    def __init__(self, code_prefix):
+        verify_url_hmac(request.url)
+
+        #params = urlparse.parse_qs(url)
+
+        self.verification_code = request.args['code']
+        self.user = self.actual_get_user(code_prefix, self.verification_code)
+
+    def reencode_standalone(self):
+        hmac = actual_hmac_creation(self.verification_code)
+        return self.verification_code + ":" + hmac
+
+    @staticmethod
+    def actual_get_user(code_prefix, verification_code):
+        data = Redis.get(code_prefix + ":" + verification_code)
+        print("in get_coded_user, data is:", data)
+        data = json.loads(data)
+        print("data is:", data)
+        return model.User.query.get(data['id'])
+
+@app.route("/n/login", methods=('GET', 'POST'))
 def login():
     params = request.form if request.form else request.args
     print("in login params are:", params)
@@ -282,7 +340,7 @@ def login():
                            user_id = user.id,
                            user_email_address = user.email_address)
 
-            flash("Thank you for logging in.", "alert-success")
+            flash("Thank you for logging in {}.".format(user.full_name), "alert-success")
 
             key = "session_id:" + login_rec.session_id
             print("Key when signing:", key)
@@ -324,10 +382,63 @@ def forgot_password_submit():
             email_address))
         return redirect(url_for("login"))
     ForgotPasswordEmail(user)
+    return render_template("new_security/forgot_password_step2.html",
+                            subject=ForgotPasswordEmail.subject)
+
+
+
+@app.route("/manage/users")
+def manage_users():
+    template_vars = UsersManager()
+    return render_template("admin/user_manager.html", **template_vars.__dict__)
+
+@app.route("/manage/user")
+def manage_user():
+    template_vars = UserManager(request.args)
+    return render_template("admin/ind_user_manager.html", **template_vars.__dict__)
+
+@app.route("/manage/groups")
+def manage_groups():
+    template_vars = GroupsManager(request.args)
+    return render_template("admin/group_manager.html", **template_vars.__dict__)
+
+
+@app.route("/n/register", methods=('GET', 'POST'))
+def register():
+    params = None
+    errors = None
+
+    #if request.form:
+    #    params = request.form
+    #else:
+    #    params = request.args
+
+    params = request.form if request.form else request.args
+
+    if params:
+        print("Attempting to register the user...")
+        result = RegisterUser(params)
+        errors = result.errors
+
+        if result.thank_you_mode:
+            assert not errors, "Errors while in thank you mode? That seems wrong..."
+            return render_template("new_security/registered.html",
+                                   subject=VerificationEmail.subject)
+
+    return render_template("new_security/register_user.html", values=params, errors=errors)
+
+
+
+
+#@app.route("/n/login", methods=('GET', 'POST'))
+#def login():
+#    return user_manager.login()
+#
+#@app.route("/manage/verify")
+#def verify():
+#    user_manager.verify_email()
+#    return render_template("new_security/verified.html")
 
-@app.route("/n/password_reset")
-def password_reset():
-    pass
 
 
 ################################# Sign and unsign #####################################
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index deccf459..a060ba3c 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -51,7 +51,7 @@ from wqflask import user_manager
 @app.before_request
 def connect_db():
     g.db = sqlalchemy.create_engine(app.config['DB_URI'])
-    
+
 #@app.before_request
 #def trace_it():
 #    from wqflask import tracer
@@ -277,68 +277,6 @@ def get_temp_data():
 ###################################################################################################
 
 
-@app.route("/manage/users")
-def manage_users():
-    template_vars = user_manager.UsersManager()
-    return render_template("admin/user_manager.html", **template_vars.__dict__)
-
-@app.route("/manage/user")
-def manage_user():
-    template_vars = user_manager.UserManager(request.args)
-    return render_template("admin/ind_user_manager.html", **template_vars.__dict__)
-
-@app.route("/manage/groups")
-def manage_groups():
-    template_vars = user_manager.GroupsManager(request.args)
-    return render_template("admin/group_manager.html", **template_vars.__dict__)
-
-
-@app.route("/n/register", methods=('GET', 'POST'))
-def register():
-    params = None
-    errors = None
-
-    #if request.form:
-    #    params = request.form
-    #else:
-    #    params = request.args
-    
-    params = request.form if request.form else request.args
-    
-    if params:
-        print("Attempting to register the user...")
-        result = user_manager.RegisterUser(params)
-        errors = result.errors
-        
-        if result.thank_you_mode:
-            assert not errors, "Errors while in thank you mode? That seems wrong..."
-            return render_template("new_security/registered.html")
-       
-    return render_template("new_security/register_user.html", values=params, errors=errors)
-
-#@app.route("/n/register_submit", methods=('POST',))
-#def register_submit():
-#    print("request.args are: ", request.args)
-#    result = user_manager.RegisterUser(request.form)
-#    if result.errors:
-#        print("Redirecting")
-#        # 307 preserves the post on the redirect (maybe)
-#        errors = result.errors
-#        #errors = json.dumps(errors)
-#        print("request.args are: ", request.args)
-#        return render_template("new_security/register_user.html", errors=errors, values=request.form)
-#        #return redirect(url_for('new_register', errors=errors), code=307)
-
-
-@app.route("/n/login", methods=('GET', 'POST'))
-def login():
-    return user_manager.login()
-
-@app.route("/manage/verify")
-def verify():
-    user_manager.verify_email()
-    return render_template("new_security/verified.html")
-
 
 ##########################################################################