From f2e41174a7e2091e7e835b137c6c7e2874feda04 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 23 Aug 2013 17:38:55 -0500 Subject: Finally figured out where to put flask_security into the code Various registration template changes --- wqflask/secure_server.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'wqflask/secure_server.py') diff --git a/wqflask/secure_server.py b/wqflask/secure_server.py index 2abfdb05..04b85663 100644 --- a/wqflask/secure_server.py +++ b/wqflask/secure_server.py @@ -25,6 +25,9 @@ app.logger.addHandler(file_handler) import logging_tree logging_tree.printout() +import sys +print("At startup, path is:", sys.path) + #print("app.config is:", app.config) if __name__ == '__main__': -- cgit v1.2.3 From cd4d985e7142f92e18f8cf316c72073cb3609a85 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 Aug 2013 16:21:12 -0500 Subject: Various changes to track down what happens with security modules --- wqflask/flask_security/core.py | 1 + wqflask/flask_security/datastore.py | 1 + wqflask/flask_security/forms.py | 3 +++ wqflask/flask_security/registerable.py | 1 + wqflask/secure_server.py | 15 +++++++++++++++ 5 files changed, 21 insertions(+) (limited to 'wqflask/secure_server.py') diff --git a/wqflask/flask_security/core.py b/wqflask/flask_security/core.py index d794fad5..0f3a231f 100644 --- a/wqflask/flask_security/core.py +++ b/wqflask/flask_security/core.py @@ -207,6 +207,7 @@ def _get_serializer(app, name): def _get_state(app, datastore, **kwargs): for key, value in get_config(app).items(): + print "in _get_state [{}]: {}".format(key, value) kwargs[key.lower()] = value kwargs.update(dict( diff --git a/wqflask/flask_security/datastore.py b/wqflask/flask_security/datastore.py index f8c7218d..634399d9 100644 --- a/wqflask/flask_security/datastore.py +++ b/wqflask/flask_security/datastore.py @@ -157,6 +157,7 @@ class UserDatastore(object): """Creates and returns a new user from the given parameters.""" user = self.user_model(**self._prepare_create_user_args(**kwargs)) + print "in abstraced create_user, user is:", user return self.put(user) def delete_user(self, user): diff --git a/wqflask/flask_security/forms.py b/wqflask/flask_security/forms.py index e64e1502..4c1dc894 100644 --- a/wqflask/flask_security/forms.py +++ b/wqflask/flask_security/forms.py @@ -89,6 +89,8 @@ def valid_user_email(form, field): class Form(BaseForm): def __init__(self, *args, **kwargs): + print "in Form, args:", args + print "in Form, kwargs:", kwargs if current_app.testing: self.TIME_LIMIT = None super(Form, self).__init__(*args, **kwargs) @@ -148,6 +150,7 @@ class RegisterFormMixin(): def to_dict(form): def is_field_and_user_attr(member): + print "in ifaua:", member return isinstance(member, Field) and \ hasattr(_datastore.user_model, member.name) diff --git a/wqflask/flask_security/registerable.py b/wqflask/flask_security/registerable.py index 4e9f357d..4606c7c6 100644 --- a/wqflask/flask_security/registerable.py +++ b/wqflask/flask_security/registerable.py @@ -24,6 +24,7 @@ _datastore = LocalProxy(lambda: _security.datastore) def register_user(**kwargs): + print "in register_user kwargs:", kwargs confirmation_link, token = None, None kwargs['password'] = encrypt_password(kwargs['password']) user = _datastore.create_user(**kwargs) diff --git a/wqflask/secure_server.py b/wqflask/secure_server.py index 04b85663..b877c544 100644 --- a/wqflask/secure_server.py +++ b/wqflask/secure_server.py @@ -28,6 +28,21 @@ logging_tree.printout() import sys print("At startup, path is:", sys.path) + +######## +def tracefunc(frame, event, arg, indent=[0]): + if event == "call": + indent[0] += 2 + print("-" * indent[0] + "> call function", frame.f_code.co_name) + elif event == "return": + print("<" + "-" * indent[0], "exit function", frame.f_code.co_name) + indent[0] -= 2 + return tracefunc + +import sys +sys.settrace(tracefunc) +############## + #print("app.config is:", app.config) if __name__ == '__main__': -- cgit v1.2.3 From 8d61798c41f9ec77dea3231cbcf0957c7cadc533 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 4 Sep 2013 15:31:22 -0500 Subject: Trying to trace through files --- wqflask/flask_security/forms.py | 6 ++++++ wqflask/secure_server.py | 19 ++----------------- wqflask/wqflask/model.py | 1 + wqflask/wqflask/tracer.py | 41 +++++++++++++++++++++++++++++++++++++++++ wqflask/wqflask/views.py | 5 +++++ 5 files changed, 55 insertions(+), 17 deletions(-) create mode 100644 wqflask/wqflask/tracer.py (limited to 'wqflask/secure_server.py') diff --git a/wqflask/flask_security/forms.py b/wqflask/flask_security/forms.py index 4c1dc894..54677e77 100644 --- a/wqflask/flask_security/forms.py +++ b/wqflask/flask_security/forms.py @@ -89,6 +89,10 @@ def valid_user_email(form, field): class Form(BaseForm): def __init__(self, *args, **kwargs): + #print "importing tracer" + #from wqflask import tracer + #tracer.turn_on() + #print "imported tracer" print "in Form, args:", args print "in Form, kwargs:", kwargs if current_app.testing: @@ -154,7 +158,9 @@ class RegisterFormMixin(): return isinstance(member, Field) and \ hasattr(_datastore.user_model, member.name) + print("green:", vars(form)) fields = inspect.getmembers(form, is_field_and_user_attr) + print("fields:" ,vars(form)) return dict((key, value.data) for key, value in fields) diff --git a/wqflask/secure_server.py b/wqflask/secure_server.py index b877c544..697ebfe0 100644 --- a/wqflask/secure_server.py +++ b/wqflask/secure_server.py @@ -1,4 +1,4 @@ -from __future__ import print_function, division, absolute_import +from __future__ import absolute_import, division, print_function from wqflask import app @@ -28,21 +28,6 @@ logging_tree.printout() import sys print("At startup, path is:", sys.path) - -######## -def tracefunc(frame, event, arg, indent=[0]): - if event == "call": - indent[0] += 2 - print("-" * indent[0] + "> call function", frame.f_code.co_name) - elif event == "return": - print("<" + "-" * indent[0], "exit function", frame.f_code.co_name) - indent[0] -= 2 - return tracefunc - -import sys -sys.settrace(tracefunc) -############## - #print("app.config is:", app.config) if __name__ == '__main__': @@ -51,4 +36,4 @@ if __name__ == '__main__': port=app.config['SERVER_PORT'], use_debugger=False, threaded=True, - use_reloader=True) + use_reloader=False) diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py index 1f873545..c1b8d060 100644 --- a/wqflask/wqflask/model.py +++ b/wqflask/wqflask/model.py @@ -70,6 +70,7 @@ user_datastore = SQLAlchemyUserDatastore(db, User, Role) class ExtendedRegisterForm(RegisterForm): name = TextField('name') + #print("name is:", name['_name'], vars(name)) organization = TextField('organization') security = Security(app, user_datastore, register_form=ExtendedRegisterForm) diff --git a/wqflask/wqflask/tracer.py b/wqflask/wqflask/tracer.py new file mode 100644 index 00000000..43a0f15e --- /dev/null +++ b/wqflask/wqflask/tracer.py @@ -0,0 +1,41 @@ +from __future__ import absolute_import, division, print_function + +print("At top of tracer") + +import sys + +#################################################################################### + +# Originally based on http://stackoverflow.com/a/8315566 +def tracefunc(frame, event, arg, indent=[0]): + + func = dict(funcname = frame.f_code.co_name, + filename = frame.f_code.co_filename, + lineno = frame.f_lineno) + + #These are too common to bother printing... + too_common = ( + '/home/sam/ve27/local/lib/python2.7/site-packages/werkzeug/', + '/home/sam/ve27/local/lib/python2.7/site-packages/jinja2/', + ) + + + if func['filename'].startswith(too_common): + return tracefunc + + info = "{funcname} [{filename}: {lineno}]".format(**func) + + if event == "call": + indent[0] += 2 + #print("-" * indent[0] + "> call function", frame.f_code.co_name) + print("-" * indent[0] + "> call function:", info) + elif event == "return": + print("<" + "-" * indent[0], "exit function:", info) + indent[0] -= 2 + return tracefunc + +def turn_on(): + sys.settrace(tracefunc) + print("Tracing turned on!!!!") +#################################################################################### + diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index d57bbaa7..2b16dd77 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -50,6 +50,11 @@ 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 + tracer.turn_on() @app.route("/") def index_page(): -- cgit v1.2.3 From e91c058cd718fea25e38181098b1d0eb2ccf64cd Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 6 Sep 2013 17:33:19 -0500 Subject: Registration form validaiton without js works --- wqflask/secure_server.py | 2 +- wqflask/wqflask/model.py | 8 +++--- .../static/new/js_external/zxcvbn/zxcvbn-async.js | 1 + .../templates/new_security/register_user.html | 25 ++++++++++------ wqflask/wqflask/user_manager.py | 33 ++++++++++++++++++++++ wqflask/wqflask/views.py | 30 ++++++++++++++++++-- 6 files changed, 83 insertions(+), 16 deletions(-) create mode 100644 wqflask/wqflask/static/new/js_external/zxcvbn/zxcvbn-async.js (limited to 'wqflask/secure_server.py') diff --git a/wqflask/secure_server.py b/wqflask/secure_server.py index 697ebfe0..df195bd2 100644 --- a/wqflask/secure_server.py +++ b/wqflask/secure_server.py @@ -36,4 +36,4 @@ if __name__ == '__main__': port=app.config['SERVER_PORT'], use_debugger=False, threaded=True, - use_reloader=False) + use_reloader=True) diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py index c1b8d060..b3dfe746 100644 --- a/wqflask/wqflask/model.py +++ b/wqflask/wqflask/model.py @@ -47,11 +47,11 @@ class Role(db.Model, RoleMixin): class User(db.Model, UserMixin): id = db.Column(db.Integer(), primary_key=True) - email = db.Column(db.String(255), unique=True) - password = db.Column(db.String(255)) + email = db.Column(db.String(50), unique=True) + password = db.Column(db.String(50)) - name = db.Column(db.Unicode(255)) - organization = db.Column(db.Unicode(255)) + full_name = db.Column(db.Unicode(50)) + organization = db.Column(db.Unicode(50)) active = db.Column(db.Boolean()) confirmed_at = db.Column(db.DateTime()) diff --git a/wqflask/wqflask/static/new/js_external/zxcvbn/zxcvbn-async.js b/wqflask/wqflask/static/new/js_external/zxcvbn/zxcvbn-async.js new file mode 100644 index 00000000..404944d3 --- /dev/null +++ b/wqflask/wqflask/static/new/js_external/zxcvbn/zxcvbn-async.js @@ -0,0 +1 @@ +(function(){var a;a=function(){var a,b;b=document.createElement("script");b.src="//dl.dropbox.com/u/209/zxcvbn/zxcvbn.js";b.type="text/javascript";b.async=!0;a=document.getElementsByTagName("script")[0];return a.parentNode.insertBefore(b,a)};null!=window.attachEvent?window.attachEvent("onload",a):window.addEventListener("load",a,!1)}).call(this); diff --git a/wqflask/wqflask/templates/new_security/register_user.html b/wqflask/wqflask/templates/new_security/register_user.html index d203d65f..6a7f4c9c 100644 --- a/wqflask/wqflask/templates/new_security/register_user.html +++ b/wqflask/wqflask/templates/new_security/register_user.html @@ -28,15 +28,26 @@

Don't have an account?

Register here
- -
+ Please note: + + + {% endif %} + +
-
@@ -44,7 +55,7 @@
-
@@ -52,7 +63,7 @@
- +
@@ -62,8 +73,7 @@ - - + -
diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py index 9e666bbd..d03910ca 100644 --- a/wqflask/wqflask/user_manager.py +++ b/wqflask/wqflask/user_manager.py @@ -9,6 +9,8 @@ from __future__ import print_function, division, absolute_import from wqflask import model +from utility import Bunch + from flask import Flask, g from pprint import pformat as pf @@ -43,6 +45,37 @@ class UserManager(object): print(" ID:", dataset.id) print(" Confidential:", dataset.check_confidentiality()) #print(" ---> self.datasets:", self.datasets) + + +class RegisterUser(object): + def __init__(self, kw): + self.errors = [] + user = Bunch() + + user.email_address = kw.get('email_address', '').strip() + if not (5 <= len(user.email_address) <= 50): + self.errors.append('Email Address needs to be between 5 and 50 characters.') + + user.full_name = kw.get('full_name', '').strip() + if not (5 <= len(user.full_name) <= 50): + self.errors.append('Full Name needs to be between 5 and 50 characters.') + + user.organization = kw.get('organization', '').strip() + if user.organization and not (5 <= len(user.organization) <= 50): + self.errors.append('Organization needs to be empty or between 5 and 50 characters.') + + user.password = kw.get('password', '') + if not (6 <= len(user.password) <= 30): + self.errors.append('Password needs to be between 6 and 30 characters.') + + if kw.get('password_confirm') != user.password: + self.errors.append("Passwords don't match.") + + if self.errors: + return + + + class GroupsManager(object): diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 6f14ac8d..9a0401d6 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -23,7 +23,8 @@ import sqlalchemy from wqflask import app -from flask import render_template, request, make_response, Response, Flask, g, config, jsonify +from flask import (render_template, request, make_response, Response, + Flask, g, config, jsonify, redirect, url_for) from wqflask import search_results from base.data_set import DataSet # Used by YAML in marker_regression @@ -292,9 +293,32 @@ def manage_groups(): return render_template("admin/group_manager.html", **template_vars.__dict__) -@app.route("/n/register") +@app.route("/n/register", methods=('GET', 'POST')) def new_register(): - return render_template("new_security/register_user.html") + params = None + errors = None + if request.form: + params = request.form + else: + params = request.args + if params: + result = user_manager.RegisterUser(params) + errors = result.errors + 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") def new_login(): -- cgit v1.2.3 From a55a1b941864a9574b8177349b8c9c750f379c72 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 7 Oct 2013 02:14:41 -0500 Subject: Worked on logins, session_ids, flash messages, etc. --- wqflask/secure_server.py | 7 +- wqflask/utility/__init__.py | 23 ++++ wqflask/wqflask/model.py | 12 +- wqflask/wqflask/templates/base.html | 29 +++++ wqflask/wqflask/templates/index_page.html | 7 +- .../wqflask/templates/new_security/login_user.html | 144 ++++++++++++--------- .../wqflask/templates/new_security/thank_you.html | 4 +- wqflask/wqflask/user_manager.py | 94 +++++++++++--- wqflask/wqflask/views.py | 43 +++--- 9 files changed, 260 insertions(+), 103 deletions(-) (limited to 'wqflask/secure_server.py') diff --git a/wqflask/secure_server.py b/wqflask/secure_server.py index df195bd2..a77abf7e 100644 --- a/wqflask/secure_server.py +++ b/wqflask/secure_server.py @@ -25,8 +25,11 @@ app.logger.addHandler(file_handler) import logging_tree logging_tree.printout() -import sys -print("At startup, path is:", sys.path) +#import sys +#print("At startup, path is:", sys.path) + +from werkzeug.contrib.fixers import ProxyFix +app.wsgi_app = ProxyFix(app.wsgi_app) #print("app.config is:", app.config) diff --git a/wqflask/utility/__init__.py b/wqflask/utility/__init__.py index d0e4a3fa..d9856eed 100755 --- a/wqflask/utility/__init__.py +++ b/wqflask/utility/__init__.py @@ -1,5 +1,6 @@ from pprint import pformat as pf +# Todo: Move these out of __init__ class Bunch(object): """Like a dictionary but using object notation""" @@ -10,3 +11,25 @@ class Bunch(object): return pf(self.__dict__) +class Struct(object): + '''The recursive class for building and representing objects with. + + From http://stackoverflow.com/a/6573827/1175849 + + ''' + + def __init__(self, obj): + for k, v in obj.iteritems(): + if isinstance(v, dict): + setattr(self, k, Struct(v)) + else: + setattr(self, k, v) + + def __getitem__(self, val): + return self.__dict__[val] + + def __repr__(self): + return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for + (k, v) in self.__dict__.iteritems())) + + diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py index 8e7a823e..5c514bde 100644 --- a/wqflask/wqflask/model.py +++ b/wqflask/wqflask/model.py @@ -1,7 +1,9 @@ from __future__ import print_function, division, absolute_import import uuid +import datetime +from flask import request from flask.ext.sqlalchemy import SQLAlchemy #from flask.ext.security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin @@ -84,9 +86,15 @@ class Login(Base): __tablename__ = "login" id = Column(Unicode(36), primary_key=True, default=lambda: unicode(uuid.uuid4())) user = Column(Unicode(36), ForeignKey('user.id')) - timestamp = Column(DateTime()) + timestamp = Column(DateTime(), default=lambda: datetime.datetime.utcnow()) ip_address = Column(Unicode(39)) - + successful = Column(Boolean(), nullable=False) # False if wrong password was entered + session_id = Column(Text) # Set only if successfully logged in, otherwise should be blank + + def __init__(self, user): + self.user = user.id + self.ip_address = request.remote_addr + # Setup Flask-Security #user_datastore = SQLAlchemyUserDatastore(db, User, Role) diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html index 6e7119fe..077e4705 100644 --- a/wqflask/wqflask/templates/base.html +++ b/wqflask/wqflask/templates/base.html @@ -26,10 +26,39 @@ +{% macro header(main, second) %} +
+
+

Login

+

+ Gain access to GeneNetwork. +

+
+
+ + {{ flash_me() }} +{% endmacro %} + + +{% macro flash_me() -%} + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+
+ {% for category, message in messages %} +
{{ message }}
+ {% endfor %} +
+ {% endif %} + {% endwith %} +{% endmacro %} + +