{ "info": { "author": "Victor Andrade de Almeida", "author_email": "vct.a.almeida@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: Flask", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: Implementation" ], "description": "#############################\nFlask Digest |license| |pypi|\n#############################\n\n.. |license| image:: https://img.shields.io/pypi/l/Flask-Digest.svg?style=flat-square\n :target: https://github.com/vctandrade/flask-digest/blob/master/LICENSE.txt\n\n.. |pypi| image:: https://img.shields.io/pypi/v/Flask-Digest.svg?style=flat-square\n :target: https://pypi.python.org/pypi/Flask-Digest\n\nFlask Digest provides a RESTful way of authenticating users using a Flask\napplication. To achieve that, it uses the Digest Access Authentication protocol\nand most optional features described in `RFC 2617`_.\n\nIn a simplified manner, Flask Digest allows you to make your resources available\nonly to those registered in your system, while taking care of security issues by\nfollowing well known protocols.\n\n.. _RFC 2617: https://www.ietf.org/rfc/rfc2617.txt\n\nQuick start\n===========\n\nFirst of all, installation is as simple as:\n\n.. code-block:: console\n\n $ pip install flask-digest\n\nAfter doing that, it's important to note this module is\nimplementation-independent of how the user database is handled and accessed. So\nthe first thing you need to do is set that up, including methods for registering\nusers and accessing their passwords.\n\nThen, you need to create a ``Stomach`` object and inform it of how to use the\ndatabase you created. The only thing left now is to decide which resources\nshould be protected and mark them accordingly.\n\nAll the steps regarding the ``Stomach`` object are done with the use of three\ndecorator methods, similar to the ones used by Flask. Those are exemplified\nbellow, where ``myRealm`` is a string of your choosing, used to describe and\nidentify your server in a unique fashion:\n\n.. code-block:: python\n\n from flask import Flask\n from flask_digest import Stomach\n\n app = Flask(__name__)\n stomach = Stomach('myRealm')\n\n db = dict()\n\n @stomach.register\n def add_user(username, password):\n db[username] = password\n\n @stomach.access\n def get_user(username):\n return db.get(username, None)\n\n @app.route('/')\n @stomach.protect\n def main():\n return '

resource

'\n\n add_user('admin', '12345')\n app.run()\n\nKeep in mind that the ``protect`` decorator MUST be located between the chosen\nmethod and Flask's ``route`` decorator.\n\nAlso, the method for registering new users is expected to receive a username as\nfirst parameter and a password as second. If you need to, other parameters are\nallowed as well.\n\nAs for the database access method, it should only have the username as required\nparameter, while returning the stored password or ``None`` if the username was\nnot registered. For more advanced uses, notice that the ``request`` object is\nvisible from this method, when called internally.\n\nAccessing\n=========\n\nOkay, now you know how to protect your resources. But how do you access them,\nwith all this security casing? Depending on the context of your application,\nit can be quite simple. For example, most browsers already support this kind of\nauthentication protocol out of the box!\n\nIf you're thinking of accessing your stuff through another python script, you're\nalso in luck! There's a module called **Requests**, which seamlessly supports\nDigest and will do all the work for you. I *strongly* recommend\n`checking it out`_.\n\n.. _checking it out: http://docs.python-requests.org/en/latest/\n\nOn the other hand, if it's written in another language there's no easy solution\nI can offer. Either you look for another module with that functionality or\ncreate one yourself. In any case, make sure to tell me how it went, so I can\nshare your experience here.\n\nBellow, there's a small list of possible response codes you can get when making\na request to a protected resource and their causes. If the code you got is not\nin this list, it probably wasn't generated by Flask Digest.\n\nResponses\n=========\n\n**401 Unauthorized**\n When the user provides an invalid combination of username/password, uses a\n ``nonce`` created for another IP or provides a wrong ``nc``, the server will\n deny access to the resource.\n\n However, if the user does not provide an ``Authorization`` header or uses a\n stale ``nonce``, the server will include a ``WWW-Authenticate`` header, with\n everything he needs to provide his credentials.\n\n**400 BadRequest**\n If the user's ``Authorization`` header is missing a field, does not use the\n requested ``qop`` value or provides the wrong ``uri``, the server will deny\n access to the resource.\n\nFeatures\n========\n\nThis implementation of the Digest Authentication scheme uses the **Quality of\nProtection (qop)** optional feature. More specifically, it forces you to use the\n``auth`` variation of it, since it makes the protocol much more secure. Also, it\ndiscards the ``nonce`` tokens after half an hour and makes sure they are only\nused from the IP for whom they were created.\n\nBesides authenticating users, Flask Digest also makes it possible for the client\nto authenticate the server. This is done by using the ``Authentication-Info``\nheader, as it contains a hash that could only be produced if one knew the\nclient's credentials. This header is included on every successful response.\n\nRegarding user database security, the ``register`` decorator does not allow you\nto store passwords in plain text, offering instead a digest of the user's\ncredentials to the underlying method when it is called.\n\nAll of this together results in your application being protected against the\nfollowing attacks:\n\n* **Replay**: the request is intercepted and reproduced in the future\n* **Reflection**: attacker repasses the server's challenge to the user\n* **Cryptanalysis**\n\n * **Chosen plaintext**: malicious server chooses the ``nonce``\n * **Precomputed dictionary**: precomputed version of the above\n * **Batch brute force**: chosen plain text on multiple users at once\n\n**Man-in-the-middle attacks**, i.e. intercept and modify requests, are also\nprevented regarding the request URIs, but until ``auth-int`` is implemented\nentity bodies CAN be modified. So ``POST`` and ``PUT`` methods are still\nvulnerable.\n\nRecommendations\n===============\n\nEven thought Flask Digest doesn't allow you to store plain text passwords, it's\nstill a good idea to encrypt the file in some way. Also, if maintaining multiple\nrealms, make sure their names differ, so that a security breach in one doesn't\naffect the other.\n\nTo avoid **online dictionary attacks**, i.e. a brute force attack using a list\nof common passwords, do not permit your users to choose easy passwords. And to\navoid **spoofing** do not trust any server that doesn't use Quality of\nProtection and have the clients also authenticates the server.\n\nChangelog\n=========\n\nTo check out the complete changelog, click `here`_.\n\n.. _here: https://github.com/vctandrade/flask-digest/releases\n\nWhat the future holds\n=====================\n\n* Logging of possible attacks\n* Implementation of ``auth-int``\n* Per user/resource authentication\n* Support Werkzeug's ``views`` and ``blueprints``\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/vctandrade/flask-digest", "keywords": "digest", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "Flask-Digest", "package_url": "https://pypi.org/project/Flask-Digest/", "platform": "Platform Independent", "project_url": "https://pypi.org/project/Flask-Digest/", "project_urls": { "Homepage": "https://github.com/vctandrade/flask-digest" }, "release_url": "https://pypi.org/project/Flask-Digest/0.2.1/", "requires_dist": null, "requires_python": "", "summary": "A RESTful authentication service for Flask applications", "version": "0.2.1" }, "last_serial": 2988862, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "6638764d4dde1dde8cced4e474967958", "sha256": "e7507a2ec2066ebd1cc44db3032c31e0a767f02c67f106359d7f4a21c31ef98b" }, "downloads": -1, "filename": "Flask_Digest-0.1.0-py2-none-any.whl", "has_sig": false, "md5_digest": "6638764d4dde1dde8cced4e474967958", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 6608, "upload_time": "2015-07-12T05:00:50", "url": "https://files.pythonhosted.org/packages/aa/7b/dd4cd039edc43b6b82c4dd45cc6032c331ec8a3400923d7fb763d0bdbebb/Flask_Digest-0.1.0-py2-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "1b95a7d780d1dc94e987703a9d19ef1d", "sha256": "4884a892d054a45e650c750a730c6a7211bddaa17542edb06d5a118686009f15" }, "downloads": -1, "filename": "Flask_Digest-0.1.1-py2-none-any.whl", "has_sig": false, "md5_digest": "1b95a7d780d1dc94e987703a9d19ef1d", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10660, "upload_time": "2015-07-17T18:51:23", "url": "https://files.pythonhosted.org/packages/81/74/e0c03c770a0e0e009d6e60119abd85ca0c650a468fbd4ae9cc8ed683ec23/Flask_Digest-0.1.1-py2-none-any.whl" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "69686c1c240b150c704c4c427f9c91ca", "sha256": "98b4026ca7668bc7c44bd149ee220cf1f821661057e25e74e34d5b6df99aebe3" }, "downloads": -1, "filename": "Flask_Digest-0.2.0-py2-none-any.whl", "has_sig": false, "md5_digest": "69686c1c240b150c704c4c427f9c91ca", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10899, "upload_time": "2016-03-14T22:35:41", "url": "https://files.pythonhosted.org/packages/68/fe/f8ea70c80fe6eb0b5033364692404e8fad3cabac492621f142526b485e4a/Flask_Digest-0.2.0-py2-none-any.whl" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "786c1592c88ddf043cb43ff50ecbf905", "sha256": "e9d6c7c1514ea7bd3a2aad414348df98d816a89aa362152286b855e12fe3e1a4" }, "downloads": -1, "filename": "Flask_Digest-0.2.1-py2-none-any.whl", "has_sig": false, "md5_digest": "786c1592c88ddf043cb43ff50ecbf905", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10925, "upload_time": "2017-06-30T01:02:54", "url": "https://files.pythonhosted.org/packages/95/1f/93bd8084020742553fb187c8471ef165f55c3a9e214e833201bd81474c49/Flask_Digest-0.2.1-py2-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "786c1592c88ddf043cb43ff50ecbf905", "sha256": "e9d6c7c1514ea7bd3a2aad414348df98d816a89aa362152286b855e12fe3e1a4" }, "downloads": -1, "filename": "Flask_Digest-0.2.1-py2-none-any.whl", "has_sig": false, "md5_digest": "786c1592c88ddf043cb43ff50ecbf905", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10925, "upload_time": "2017-06-30T01:02:54", "url": "https://files.pythonhosted.org/packages/95/1f/93bd8084020742553fb187c8471ef165f55c3a9e214e833201bd81474c49/Flask_Digest-0.2.1-py2-none-any.whl" } ] }