diff --git a/example/__init__.py b/example/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/example/app.py b/example/app.py deleted file mode 100644 index 99ffee6..0000000 --- a/example/app.py +++ /dev/null @@ -1,276 +0,0 @@ -# -*- coding: utf-8 -*- - -# a little trick so you can run: -# $ python example/app.py -# from the root of the security project -import os -import sys -sys.path.pop(0) -sys.path.insert(0, os.getcwd()) - -from flask import Flask, render_template, current_app -from flask.ext.mail import Mail -from flask.ext.mongoengine import MongoEngine -from flask.ext.sqlalchemy import SQLAlchemy -from flask.ext.security import Security, LoginForm, PasswordlessLoginForm, \ - login_required, roles_required, roles_accepted, UserMixin, RoleMixin -from flask.ext.security.datastore import SQLAlchemyUserDatastore, \ - MongoEngineUserDatastore -from flask.ext.security.decorators import http_auth_required, \ - auth_token_required -from flask.ext.security.exceptions import RoleNotFoundError -from flask.ext.security.utils import encrypt_password - - -def create_roles(): - for role in ('admin', 'editor', 'author'): - current_app.security.datastore.create_role(name=role) - current_app.security.datastore._commit() - - -def create_users(): - for u in (('matt@lp.com', 'password', ['admin'], True), - ('joe@lp.com', 'password', ['editor'], True), - ('dave@lp.com', 'password', ['admin', 'editor'], True), - ('jill@lp.com', 'password', ['author'], True), - ('tiya@lp.com', 'password', [], False)): - current_app.security.datastore.create_user( - email=u[0], password=encrypt_password(u[1]), roles=u[2], active=u[3]) - current_app.security.datastore._commit() - - -def populate_data(): - create_roles() - create_users() - - -def add_ctx_processors(app): - s = app.security - - @s.context_processor - def for_all(): - return dict() - - @s.forgot_password_context_processor - def forgot_password(): - return dict() - - @s.login_context_processor - def login(): - return dict() - - @s.register_context_processor - def register(): - return dict() - - @s.reset_password_context_processor - def reset_password(): - return dict() - - @s.send_confirmation_context_processor - def send_confirmation(): - return dict() - - @s.send_login_context_processor - def send_login(): - return dict() - - -def create_app(auth_config): - app = Flask(__name__) - app.debug = True - app.config['SECRET_KEY'] = 'secret' - - mail = Mail(app) - app.extensions['mail'] = mail - - if auth_config: - for key, value in auth_config.items(): - app.config[key] = value - - @app.route('/') - def index(): - return render_template('index.html', content='Home Page') - - @app.route('/profile') - @login_required - def profile(): - return render_template('index.html', content='Profile Page') - - @app.route('/post_login') - @login_required - def post_login(): - return render_template('index.html', content='Post Login') - - @app.route('/http') - @http_auth_required - def http(): - return render_template('index.html', content='HTTP Authentication') - - @app.route('/http_custom_realm') - @http_auth_required('My Realm') - def http_custom_realm(): - return render_template('index.html', content='HTTP Authentication') - - @app.route('/token') - @auth_token_required - def token(): - return render_template('index.html', content='Token Authentication') - - @app.route('/post_logout') - def post_logout(): - return render_template('index.html', content='Post Logout') - - @app.route('/post_register') - def post_register(): - return render_template('index.html', content='Post Register') - - @app.route('/admin') - @roles_required('admin') - def admin(): - return render_template('index.html', content='Admin Page') - - @app.route('/admin_and_editor') - @roles_required('admin', 'editor') - def admin_and_editor(): - return render_template('index.html', content='Admin and Editor Page') - - @app.route('/admin_or_editor') - @roles_accepted('admin', 'editor') - def admin_or_editor(): - return render_template('index.html', content='Admin or Editor Page') - - @app.route('/unauthorized') - def unauthorized(): - return render_template('unauthorized.html') - - @app.route('/coverage/add_role_to_user') - def add_role_to_user(): - ds = app.security.datastore - u = ds.find_user(email='joe@lp.com') - r = ds.find_role('admin') - ds.add_role_to_user(u, r) - return 'success' - - @app.route('/coverage/remove_role_from_user') - def remove_role_from_user(): - ds = app.security.datastore - u = ds.find_user(email='matt@lp.com') - ds.remove_role_from_user(u, 'admin') - return 'success' - - @app.route('/coverage/deactivate_user') - def deactivate_user(): - ds = app.security.datastore - u = ds.find_user(email='matt@lp.com') - ds.deactivate_user(u) - return 'success' - - @app.route('/coverage/activate_user') - def activate_user(): - ds = app.security.datastore - u = ds.find_user(email='tiya@lp.com') - ds.activate_user(u) - return 'success' - - @app.route('/coverage/invalid_role') - def invalid_role(): - ds = app.security.datastore - try: - ds.find_role('bogus') - except RoleNotFoundError: - return 'success' - - return app - - -def create_sqlalchemy_app(auth_config=None, register_blueprint=True): - app = create_app(auth_config) - app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root@localhost/flask_security_test' - - db = SQLAlchemy(app) - app.db = db - - roles_users = db.Table('roles_users', - db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), - db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) - - class Role(db.Model, RoleMixin): - id = db.Column(db.Integer(), primary_key=True) - name = db.Column(db.String(80), unique=True) - description = db.Column(db.String(255)) - - 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)) - last_login_at = db.Column(db.DateTime()) - current_login_at = db.Column(db.DateTime()) - last_login_ip = db.Column(db.String(100)) - current_login_ip = db.Column(db.String(100)) - login_count = db.Column(db.Integer) - active = db.Column(db.Boolean()) - confirmed_at = db.Column(db.DateTime()) - roles = db.relationship('Role', secondary=roles_users, - backref=db.backref('users', lazy='dynamic')) - - app.security = Security(app, SQLAlchemyUserDatastore(db, User, Role), - register_blueprint=register_blueprint) - - if not register_blueprint: - from example import security - blueprint = security.create_blueprint(app, 'flask_security', __name__) - app.register_blueprint(blueprint) - - @app.before_first_request - def before_first_request(): - db.drop_all() - db.create_all() - populate_data() - - add_ctx_processors(app) - - return app - - -def create_mongoengine_app(auth_config=None): - app = create_app(auth_config) - app.config['MONGODB_DB'] = 'flask_security_test' - app.config['MONGODB_HOST'] = 'localhost' - app.config['MONGODB_PORT'] = 27017 - - db = MongoEngine(app) - app.db = db - - class Role(db.Document, RoleMixin): - name = db.StringField(required=True, unique=True, max_length=80) - description = db.StringField(max_length=255) - - class User(db.Document, UserMixin): - email = db.StringField(unique=True, max_length=255) - password = db.StringField(required=True, max_length=255) - last_login_at = db.DateTimeField() - current_login_at = db.DateTimeField() - last_login_ip = db.StringField(max_length=100) - current_login_ip = db.StringField(max_length=100) - login_count = db.IntField() - active = db.BooleanField(default=True) - confirmed_at = db.DateTimeField() - roles = db.ListField(db.ReferenceField(Role), default=[]) - - app.security = Security(app, MongoEngineUserDatastore(db, User, Role)) - - @app.before_first_request - def before_first_request(): - User.drop_collection() - Role.drop_collection() - populate_data() - - add_ctx_processors(app) - - return app - -if __name__ == '__main__': - app = create_sqlalchemy_app() - #app = create_mongoengine_app() - app.run() diff --git a/example/manage.py b/example/manage.py deleted file mode 100644 index ea5ff32..0000000 --- a/example/manage.py +++ /dev/null @@ -1,19 +0,0 @@ -# a little trick so you can run: -# $ python example/app.py -# from the root of the security project -import sys -import os - -sys.path.pop(0) -sys.path.insert(0, os.getcwd()) - -from example import app -from flask.ext.script import Manager -from flask.ext.security.script import CreateUserCommand, GenerateBlueprintCommand - -manager = Manager(app.create_sqlalchemy_app()) -manager.add_command('create_user', CreateUserCommand()) -manager.add_command('generate_blueprint', GenerateBlueprintCommand()) - -if __name__ == "__main__": - manager.run() diff --git a/tests/__init__.py b/tests/__init__.py index 88dbf6e..bba64ef 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,5 @@ from unittest import TestCase -from example import app - +from tests.test_app.sqlalchemy import create_app class SecurityTest(TestCase): @@ -9,14 +8,15 @@ class SecurityTest(TestCase): def setUp(self): super(SecurityTest, self).setUp() - self.app = self._create_app(self.AUTH_CONFIG or None) - self.app.debug = False - self.app.config['TESTING'] = True + app = self._create_app(self.AUTH_CONFIG or {}) + app.debug = False + app.config['TESTING'] = True - self.client = self.app.test_client() + self.app = app + self.client = app.test_client() def _create_app(self, auth_config): - return app.create_sqlalchemy_app(auth_config) + return create_app(auth_config) def _get(self, route, content_type=None, follow_redirects=None, headers=None): return self.client.get(route, follow_redirects=follow_redirects, diff --git a/tests/functional_tests.py b/tests/functional_tests.py index 5a5d187..c5af61e 100644 --- a/tests/functional_tests.py +++ b/tests/functional_tests.py @@ -560,7 +560,8 @@ class ExpiredLoginTokenTests(SecurityTest): class MongoEngineSecurityTests(DefaultSecurityTests): def _create_app(self, auth_config): - return app.create_mongoengine_app(auth_config) + from tests.test_app.mongoengine import create_app + return create_app(auth_config) class DefaultDatastoreTests(SecurityTest): diff --git a/tests/test_app/__init__.py b/tests/test_app/__init__.py new file mode 100644 index 0000000..52de7a0 --- /dev/null +++ b/tests/test_app/__init__.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- + +from flask import Flask, render_template, current_app +from flask.ext.mail import Mail +from flask.ext.security import login_required, roles_required, roles_accepted +from flask.ext.security.decorators import http_auth_required, \ + auth_token_required +from flask.ext.security.exceptions import RoleNotFoundError +from flask.ext.security.utils import encrypt_password +from werkzeug.local import LocalProxy + +ds = LocalProxy(lambda: current_app.extensions['security'].datastore) + +def create_app(config): + app = Flask(__name__) + app.debug = True + app.config['SECRET_KEY'] = 'secret' + + for key, value in config.items(): + app.config[key] = value + + mail = Mail(app) + app.extensions['mail'] = mail + + @app.route('/') + def index(): + return render_template('index.html', content='Home Page') + + @app.route('/profile') + @login_required + def profile(): + return render_template('index.html', content='Profile Page') + + @app.route('/post_login') + @login_required + def post_login(): + return render_template('index.html', content='Post Login') + + @app.route('/http') + @http_auth_required + def http(): + return render_template('index.html', content='HTTP Authentication') + + @app.route('/http_custom_realm') + @http_auth_required('My Realm') + def http_custom_realm(): + return render_template('index.html', content='HTTP Authentication') + + @app.route('/token') + @auth_token_required + def token(): + return render_template('index.html', content='Token Authentication') + + @app.route('/post_logout') + def post_logout(): + return render_template('index.html', content='Post Logout') + + @app.route('/post_register') + def post_register(): + return render_template('index.html', content='Post Register') + + @app.route('/admin') + @roles_required('admin') + def admin(): + return render_template('index.html', content='Admin Page') + + @app.route('/admin_and_editor') + @roles_required('admin', 'editor') + def admin_and_editor(): + return render_template('index.html', content='Admin and Editor Page') + + @app.route('/admin_or_editor') + @roles_accepted('admin', 'editor') + def admin_or_editor(): + return render_template('index.html', content='Admin or Editor Page') + + @app.route('/unauthorized') + def unauthorized(): + return render_template('unauthorized.html') + + @app.route('/coverage/add_role_to_user') + def add_role_to_user(): + u = ds.find_user(email='joe@lp.com') + r = ds.find_role('admin') + ds.add_role_to_user(u, r) + return 'success' + + @app.route('/coverage/remove_role_from_user') + def remove_role_from_user(): + u = ds.find_user(email='matt@lp.com') + ds.remove_role_from_user(u, 'admin') + return 'success' + + @app.route('/coverage/deactivate_user') + def deactivate_user(): + u = ds.find_user(email='matt@lp.com') + ds.deactivate_user(u) + return 'success' + + @app.route('/coverage/activate_user') + def activate_user(): + u = ds.find_user(email='tiya@lp.com') + ds.activate_user(u) + return 'success' + + @app.route('/coverage/invalid_role') + def invalid_role(): + try: + ds.find_role('bogus') + except RoleNotFoundError: + return 'success' + + return app + +def create_roles(): + for role in ('admin', 'editor', 'author'): + ds.create_role(name=role) + ds._commit() + + +def create_users(): + for u in (('matt@lp.com', 'password', ['admin'], True), + ('joe@lp.com', 'password', ['editor'], True), + ('dave@lp.com', 'password', ['admin', 'editor'], True), + ('jill@lp.com', 'password', ['author'], True), + ('tiya@lp.com', 'password', [], False)): + ds.create_user(email=u[0], password=encrypt_password(u[1]), + roles=u[2], active=u[3]) + ds._commit() + +def populate_data(): + create_roles() + create_users() + +def add_context_processors(s): + @s.context_processor + def for_all(): + return dict() + + @s.forgot_password_context_processor + def forgot_password(): + return dict() + + @s.login_context_processor + def login(): + return dict() + + @s.register_context_processor + def register(): + return dict() + + @s.reset_password_context_processor + def reset_password(): + return dict() + + @s.send_confirmation_context_processor + def send_confirmation(): + return dict() + + @s.send_login_context_processor + def send_login(): + return dict() diff --git a/tests/test_app/mongoengine.py b/tests/test_app/mongoengine.py new file mode 100644 index 0000000..e1efdec --- /dev/null +++ b/tests/test_app/mongoengine.py @@ -0,0 +1,47 @@ + +from flask.ext.mongoengine import MongoEngine +from flask.ext.security import Security, UserMixin, RoleMixin, \ + MongoEngineUserDatastore + +from tests.test_app import create_app as create_base_app, populate_data, \ + add_context_processors + +def create_app(config): + app = create_base_app(config) + + app.config['MONGODB_DB'] = 'flask_security_test' + app.config['MONGODB_HOST'] = 'localhost' + app.config['MONGODB_PORT'] = 27017 + + db = MongoEngine(app) + + class Role(db.Document, RoleMixin): + name = db.StringField(required=True, unique=True, max_length=80) + description = db.StringField(max_length=255) + + class User(db.Document, UserMixin): + email = db.StringField(unique=True, max_length=255) + password = db.StringField(required=True, max_length=255) + last_login_at = db.DateTimeField() + current_login_at = db.DateTimeField() + last_login_ip = db.StringField(max_length=100) + current_login_ip = db.StringField(max_length=100) + login_count = db.IntField() + active = db.BooleanField(default=True) + confirmed_at = db.DateTimeField() + roles = db.ListField(db.ReferenceField(Role), default=[]) + + @app.before_first_request + def before_first_request(): + User.drop_collection() + Role.drop_collection() + populate_data() + + app.security = Security(app, MongoEngineUserDatastore(db, User, Role)) + + add_context_processors(app.security) + + return app + +if __name__ == '__main__': + create_app({}).run() diff --git a/tests/test_app/sqlalchemy.py b/tests/test_app/sqlalchemy.py new file mode 100644 index 0000000..555af75 --- /dev/null +++ b/tests/test_app/sqlalchemy.py @@ -0,0 +1,52 @@ + +from flask.ext.sqlalchemy import SQLAlchemy +from flask.ext.security import Security, UserMixin, RoleMixin, \ + SQLAlchemyUserDatastore + +from tests.test_app import create_app as create_base_app, populate_data, \ + add_context_processors + +def create_app(config): + app = create_base_app(config) + + app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root@localhost/flask_security_test' + + db = SQLAlchemy(app) + + roles_users = db.Table('roles_users', + db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), + db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) + + class Role(db.Model, RoleMixin): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(80), unique=True) + description = db.Column(db.String(255)) + + 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)) + last_login_at = db.Column(db.DateTime()) + current_login_at = db.Column(db.DateTime()) + last_login_ip = db.Column(db.String(100)) + current_login_ip = db.Column(db.String(100)) + login_count = db.Column(db.Integer) + active = db.Column(db.Boolean()) + confirmed_at = db.Column(db.DateTime()) + roles = db.relationship('Role', secondary=roles_users, + backref=db.backref('users', lazy='dynamic')) + + @app.before_first_request + def before_first_request(): + db.drop_all() + db.create_all() + populate_data() + + app.security = Security(app, SQLAlchemyUserDatastore(db, User, Role)) + + add_context_processors(app.security) + + return app + +if __name__ == '__main__': + create_app({}).run() diff --git a/example/templates/_messages.html b/tests/test_app/templates/_messages.html similarity index 100% rename from example/templates/_messages.html rename to tests/test_app/templates/_messages.html diff --git a/example/templates/_nav.html b/tests/test_app/templates/_nav.html similarity index 100% rename from example/templates/_nav.html rename to tests/test_app/templates/_nav.html diff --git a/example/templates/index.html b/tests/test_app/templates/index.html similarity index 100% rename from example/templates/index.html rename to tests/test_app/templates/index.html diff --git a/example/templates/register.html b/tests/test_app/templates/register.html similarity index 100% rename from example/templates/register.html rename to tests/test_app/templates/register.html diff --git a/example/templates/unauthorized.html b/tests/test_app/templates/unauthorized.html similarity index 100% rename from example/templates/unauthorized.html rename to tests/test_app/templates/unauthorized.html diff --git a/tests/unit_tests.py b/tests/unit_tests.py index ad0b37d..44860a4 100644 --- a/tests/unit_tests.py +++ b/tests/unit_tests.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import unittest