{ "info": { "author": "Level 12", "author_email": "devteam@level12.io", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5" ], "description": ".. default-role:: code\n\n.. role:: python(code)\n :language: python\n\n==========\nKegBouncer\n==========\n\n.. image:: https://circleci.com/gh/level12/keg-bouncer.svg?style=svg\n :target: https://circleci.com/gh/level12/keg-bouncer\n\n.. image:: https://codecov.io/github/level12/keg-bouncer/coverage.svg?branch=master\n :target: https://codecov.io/github/level12/keg-bouncer?branch=master\n\n.. _Keg: https://pypi.python.org/pypi/Keg\n.. _KegElements: https://pypi.python.org/pypi/KegElements\n.. _Flask-Login: http://flask-login.readthedocs.io/en/latest/\n\nA one-stop shop for all things related to authentication and authorization in a Keg_ app.\n\n\nIntro\n-----\n\nBuilt on top of Keg_ and KegElements_, KegBouncer offers several features for managing authorization and authentication. KegBouncer allows you to pick and choose which features you want it to handle in you application. It achieves this by providing each feature as a Mixin class which you can optionally mixin to your entities (probably a `User` entity).\n\nThe available mixins cover:\n\n* Three-tierd permission system\n* Password-based authentication and password history\n* Login history\n\nRefer to the sections below on how to use each of these.\n\nOne-Primary-Key Requirement\n***************************\n\nNote that each mixin will automatically determine the primary key of your entitiy. However, your entity must have exactly one primary key, and it must be specified as SQLAlchemy declarative class attribute.\n\n\nPermissions\n-----------\n\nIn order to use KegBouncer's authorization features to protect Keg views, you will also need Flask-Login_.\nHowever, KegBouncer's models do not require that dependency.\n\n\n`keg_bouncer.mixins.PermissionMixin` provides a three-tiered permissions model. It manages four kinds of entities:\n\n* Users\n* Permissions (for describing actions that can be guarded within the system)\n* User groups (for grouping users in a way that best models business needs)\n* Permission bundles (for grouping permissions in a way that best models the system)\n\nWe call this a \"three-tiered\" permissions model because a user can be granted permissions in three ways:\n\n1. Directly\n2. Through permission bundles\n3. Through user groups\n\nThis terminology is designed to distinguish this permissions model from other ones, like RBAC, which permit higherarchies of any depth. Technically, this three-tier model is a special case of RBAC.\n\n**Note about the term \"role\":** While this model is technically a special case of the widely-used *Role-based access control (RBAC)*, we took great pains to avoid the highly ambiguous term \"role.\"\n\n\nUsage\n*****\n\nTo add permission facilities to your user entity, inherit the `PermissionMixin` like this:\n\n.. code:: python\n\n import flask_login # Only necessary if using KegBouncer to protect you views.\n from sqlalchemy import import Column, Integer, String\n\n Base = sqlalchemy.ext.declarative.declarative_base()\n\n class User(Base, flask_login.UserMixin, keg_bouncer.model.mixins.PermissionMixin):\n __tablename__ = 'users'\n id = Column(Integer, primary_key=True)\n\n\nProtecting Views and Components\n*******************************\n\nTo protect various parts of your application, you can use the tools provided in `keg_bouncer.auth`:\n\nIn order to take advantage of these tools, your `User` entity needs to also mixin `flask_login.UserMixin`.\n\n#. Use an `if` block and check for permissions:\n\n .. code:: python\n\n # ...\n if keg_bouncer.auth.current_user_has_permissions('launch-missiles'):\n launch_missiles()\n\n#. Decorate a function:\n\n .. code:: python\n\n # ...\n @keg_bouncer.auth.requires_permissions('launch-missiles')\n def launch_missiles(target=Enemy())\n # ...\n\n#. Inherit from `ProtectedBaseView`:\n\n .. code:: python\n\n # ...\n class LaunchMissilesView(keg_bouncer.auth.ProtectedBaseView):\n requires_permission = 'launch-missiles'\n\nMigration\n*********\n\nKegBouncer uses Alembic_ to manage migrations and it assumes your app does as well.\n\n.. _Alembic: https://alembic.readthedocs.org/\n\nTo use the migrations that KegBouncer provides, you need to tell Alembic where\nto find the revisions. In your `alembic.ini` file for your application, adjust\nyour ``version_locations`` setting to include your KegBouncer's versions\nfolder.\n\n\n.. code:: ini\n\n [alembic]\n version_locations = alembic/versions keg_bouncer:alembic/versions\n\n\nIf you run ``alembic heads`` you should now see two heads, one for your application and one for\nKegBouncer.\n\n.. code:: sh\n\n $ alembic heads\n 51ba1b47505e (application) (head)\n 13d265b97e4d (keg_bouncer) (head)\n\n\nIt is totally fine for the application to have multiple heads, but you will need to upgrade them\nindependently. A better option is to merge the two heads into one. Do that with the\n``alembic merge`` comand.\n\n\n.. code:: sh\n\n $ alembic merge -m \"pull KegBouncer into application\" 51ba1b 13d265\n Generating /path/to/app/alembic/versions/31b094b2844f_pull_keg_bouncer_into_application.py ... done\n\n\nIf you run ``alembic heads`` again you will find that there is one head.\n\n.. code:: sh\n\n $ alembic heads\n 31b094b2844f (application, keg_bouncer) (head)\n\n\nAlso within this merge revision, you will need to create some linking tables for your `User`\nentity (which mixes in ``keg_bouncer.model.mixins.PermissionMixin``).\n\n\nPassword-based Authentication\n-----------------------------\n\nTo add password-based authentication to your entity, you need to dynamically construct a password mixin object and mix it in to your entity.\n\n.. code:: python\n\n from keg_bouncer.model import mixins\n from passlib.context import CryptContext\n import sqlalchemy as sa\n\n crypt_context = CryptContext(schemes=['bcrypt'])\n\n # This mixin is optional but allows you to add additional fields to the password history table.\n class OptionalAdditionalFields(object):\n another_field = sa.Column(sa.Integer)\n\n\n password_history_mixin = mixins.make_password_mixin(\n OptionalAdditionalFields, # [optional] Allows you to add more fields to the password\n # history table via a mixin\n crypt_context=crypt_context # [optional, but must be provided here or via another means]\n # Configures the CryptContext for hashing and verifying\n )\n\n\n class User(password_history_mixin):\n default_crypt_context = crypt_context # An alternative way of specifying your CryptContext\n\n # Yet another way to specify your CryptContext\n def get_crypt_context(self):\n return crypt_context\n\n\n help(User.set_password) # Adds password to password history\n\n help(User.verify_password) # Verifies a password against most recent password\n\n help(User.is_password_used_previously) # Looks for password in history\n\n help(User.password_history_entity) # SQLAlchemy entity defining password history entries\n\n User.password_history # SQLAlchemy relationship for past passwords;\n # sorted in reverse chronological order\n\n\n**Note:** If you use `is_password_used_previously` or a similar concept, your choice of a hashing algorithm can drastically impact performance since password verification is intentionally slow.\nFor example, using `bcrypt` instead of `sha256_crypt` will allow you to verify passwords about twice as quickly. This makes a big difference when you're sifting through past passwords.\n\n\nLogin History\n-------------\n\nTo add login history to your entity, you need to dynamically construct a history mixin object and mix it in to your entity.\n\n.. code:: python\n\n from keg_bouncer.model import mixins\n import sqlalchemy as sa\n\n # This mixin is optional but allows you to add additional fields to the login history table.\n class OptionalAdditionalFields(object):\n another_field = sa.Column(sa.Integer)\n\n\n login_history_mixin = mixins.make_login_history_mixin(\n OptionalAdditionalFields, # [optional] Allows you to add more fields to the login history\n # table via a mixin\n )\n\n\n class User(login_history_mixin):\n pass\n\n\n help(User.login_history_entity) # SQLAlchemy entity defining login history entries\n\n User.login_history # SQLAlchemy relationship for past logins;\n # sorted in reverse chronological order\n\n # Example use:\n def register_login(user):\n user.login_history.insert(0, user.login_history_entity(is_login_successful=True))\n\n\nDevelopment\n-----------\n\nBranches & State\n****************\n\n* `master`: our \"production\" branch\n\nAll other branches are feature branches.\n\nProject Requirements\n********************\n\nSee `requirements` directory for the files needed and note:\n\n* You should clone Keg and KegElements and `pip install -e .` to get working copies. Since these\n libraries are new, they will likely change frequently.\n* Read the notes in the requirements files if you have problems.\n* There is a `build-wheelhouse.py` script that can be run if new requirements have been added. It\n always rebuilds libraries in `wheel-only.txt` so Git will always show them modified. But, if they\n haven't really been changed, you should revert those files so as to not add \"static\" to the\n commits.\n\nDevelopment Environment\n***********************\n\nTo quickly setup a virtual environment for development, you can use one of the supplied scripts.\n\nIf `pyenv` + `virtualenv` is your thing, use `source scripts/make-env-venv.sh`.\n\nIf `vex` is your thing, use `source scripts/make-env-vex.sh`.\n\nLint\n****\n\nProtect yourself from committing lint by installing the pre-commit hook:\n\n.. code:: sh\n\n ln -s scripts/pre-commit .git/hooks\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/level12/keg-bouncer", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "KegBouncer", "package_url": "https://pypi.org/project/KegBouncer/", "platform": "", "project_url": "https://pypi.org/project/KegBouncer/", "project_urls": { "Homepage": "https://github.com/level12/keg-bouncer" }, "release_url": "https://pypi.org/project/KegBouncer/2.2.4/", "requires_dist": [ "Flask-Login", "Keg", "KegElements", "cryptography", "six", "SQLAlchemy", "wrapt" ], "requires_python": "", "summary": "A three-tiered permissions model for KegElements built atop Flask-User", "version": "2.2.4" }, "last_serial": 4984680, "releases": { "0.1.0": [], "1.0.0": [ { "comment_text": "", "digests": { "md5": "f8c8776bc948f173cd7dc8f07b8852ee", "sha256": "a635408cb4b2d30a2bc3351877e536db4aa29828bc71e9fb41bf5a66f9a72fc0" }, "downloads": -1, "filename": "KegBouncer-1.0.0.tar.gz", "has_sig": true, "md5_digest": "f8c8776bc948f173cd7dc8f07b8852ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9558, "upload_time": "2016-03-17T19:31:06", "url": "https://files.pythonhosted.org/packages/86/eb/9de3a6cb7c6dd6aab523cea5d14f8fe3a69bad57e3557634338d07842731/KegBouncer-1.0.0.tar.gz" } ], "2.2.0": [ { "comment_text": "", "digests": { "md5": "5cd2a6eb980acc2a348c0501006825b3", "sha256": "95845b334cb08e17d5d2e497a3f10328bc4eabb65f070727302dd7e4948f4f9d" }, "downloads": -1, "filename": "KegBouncer-2.2.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "5cd2a6eb980acc2a348c0501006825b3", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 21890, "upload_time": "2016-12-15T04:57:19", "url": "https://files.pythonhosted.org/packages/22/f5/150db76e44d734aff062f233edb9bc7b12acf4d44c83a6969b6f0451b701/KegBouncer-2.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b7600249a65251db7cbcfe9c3895404a", "sha256": "71b2d4623de08d0af9437e2f8c4308b7bafea96f9bb35922e4d2ebb56b685de4" }, "downloads": -1, "filename": "KegBouncer-2.2.0.tar.gz", "has_sig": true, "md5_digest": "b7600249a65251db7cbcfe9c3895404a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22275119, "upload_time": "2016-12-15T04:57:45", "url": "https://files.pythonhosted.org/packages/e5/02/b3d34491ebb316540ae7d9579206e6bd2c2f33911924425900fc791dad98/KegBouncer-2.2.0.tar.gz" } ], "2.2.1": [ { "comment_text": "", "digests": { "md5": "cf04414275f7664ab5838b50150ceaab", "sha256": "e4d1a074f501347df0e7f76bcd6c498fbb11564320012b67827f0a88648b4bd8" }, "downloads": -1, "filename": "KegBouncer-2.2.1-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "cf04414275f7664ab5838b50150ceaab", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 21894, "upload_time": "2016-12-15T05:36:20", "url": "https://files.pythonhosted.org/packages/5b/a7/bf89bcfac36d2c7ff62f5894994b85d8fb66f75ea68b7135bb79540d52b3/KegBouncer-2.2.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c40b4088a70019ad3f444d6d90c75bc7", "sha256": "319392a3cd9f8181a34d8c5ff84e7d80f0c1b2bb0fda67bee94ec32c6e40768f" }, "downloads": -1, "filename": "KegBouncer-2.2.1.tar.gz", "has_sig": true, "md5_digest": "c40b4088a70019ad3f444d6d90c75bc7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23082, "upload_time": "2016-12-15T05:36:23", "url": "https://files.pythonhosted.org/packages/a6/2a/308c8bf3658887624eff41213f7eb4e570b78843da1142773f06cf1a1109/KegBouncer-2.2.1.tar.gz" } ], "2.2.2": [ { "comment_text": "", "digests": { "md5": "dc7a3e38126163da2ced2138f7b8f06f", "sha256": "b3881bf42d0ac5728cbd50da660b26a98476eeb30c5883bdcb8747f849f6f7d1" }, "downloads": -1, "filename": "KegBouncer-2.2.2-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "dc7a3e38126163da2ced2138f7b8f06f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 21883, "upload_time": "2016-12-15T17:31:19", "url": "https://files.pythonhosted.org/packages/9d/df/3bad796f62d24e181e6e732526a0fb516afc58eada3dbaa16b0c8f81c04e/KegBouncer-2.2.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7d41b0d4b17a446770dcee3e2af18c06", "sha256": "f09f0b61bbb7859578a2f8f7e56b8ac6a970f78808c9ca1f3de371cdf2ec5855" }, "downloads": -1, "filename": "KegBouncer-2.2.2.tar.gz", "has_sig": true, "md5_digest": "7d41b0d4b17a446770dcee3e2af18c06", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23961, "upload_time": "2016-12-15T17:31:22", "url": "https://files.pythonhosted.org/packages/c7/c3/816957841449dbaa75d4e776949ff259df10cb736759f9970992e140c90a/KegBouncer-2.2.2.tar.gz" } ], "2.2.3": [ { "comment_text": "", "digests": { "md5": "451c2f0251da41e4075da3bb9bd1858b", "sha256": "8693e9317274c7001ddc3d6ce5e20fdcaff3c4b30e60b6983f8aee3d86731546" }, "downloads": -1, "filename": "KegBouncer-2.2.3-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "451c2f0251da41e4075da3bb9bd1858b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 20797, "upload_time": "2017-04-04T19:41:18", "url": "https://files.pythonhosted.org/packages/af/7b/9d343900204a6f765bb3bdae7ce67b62efa10aed2f888b91609753d61d2d/KegBouncer-2.2.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "570dd42b93369a884189f64c2b7e542c", "sha256": "5338ee1101a91ca5353578df11e74429f914cf547dbf2006846f47fb3dd8554e" }, "downloads": -1, "filename": "KegBouncer-2.2.3.tar.gz", "has_sig": true, "md5_digest": "570dd42b93369a884189f64c2b7e542c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23376, "upload_time": "2017-04-04T19:41:20", "url": "https://files.pythonhosted.org/packages/9e/c9/4566ddcf71fae395a9a8cc54cac12f48291b575470521a4e89d673634e64/KegBouncer-2.2.3.tar.gz" } ], "2.2.4": [ { "comment_text": "", "digests": { "md5": "46de76cb9c7a03c28abffb20dec3d7c1", "sha256": "2b2611c85f7817094136ac7d6c57cd5cb1cf80366fcd93801618be42392231cc" }, "downloads": -1, "filename": "KegBouncer-2.2.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "46de76cb9c7a03c28abffb20dec3d7c1", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 17299, "upload_time": "2019-03-25T21:18:38", "url": "https://files.pythonhosted.org/packages/3b/99/e2aca61c530bb946994401fe0dd63ccee7a0dd1e85d57f5ee6075e393e85/KegBouncer-2.2.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c02364f9952f7440180e739e0a731c59", "sha256": "d29a95e01fa57d3945a352f0a97957090b0e2f646afcff3a6a1809a9a48e9c1d" }, "downloads": -1, "filename": "KegBouncer-2.2.4.tar.gz", "has_sig": false, "md5_digest": "c02364f9952f7440180e739e0a731c59", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24316, "upload_time": "2019-03-25T21:18:40", "url": "https://files.pythonhosted.org/packages/f1/02/aa48f7d8ccc70aef049623ed5ccbd9093c94a292f7715de0dcd7ce698be5/KegBouncer-2.2.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "46de76cb9c7a03c28abffb20dec3d7c1", "sha256": "2b2611c85f7817094136ac7d6c57cd5cb1cf80366fcd93801618be42392231cc" }, "downloads": -1, "filename": "KegBouncer-2.2.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "46de76cb9c7a03c28abffb20dec3d7c1", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 17299, "upload_time": "2019-03-25T21:18:38", "url": "https://files.pythonhosted.org/packages/3b/99/e2aca61c530bb946994401fe0dd63ccee7a0dd1e85d57f5ee6075e393e85/KegBouncer-2.2.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c02364f9952f7440180e739e0a731c59", "sha256": "d29a95e01fa57d3945a352f0a97957090b0e2f646afcff3a6a1809a9a48e9c1d" }, "downloads": -1, "filename": "KegBouncer-2.2.4.tar.gz", "has_sig": false, "md5_digest": "c02364f9952f7440180e739e0a731c59", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24316, "upload_time": "2019-03-25T21:18:40", "url": "https://files.pythonhosted.org/packages/f1/02/aa48f7d8ccc70aef049623ed5ccbd9093c94a292f7715de0dcd7ce698be5/KegBouncer-2.2.4.tar.gz" } ] }