{ "info": { "author": "Toaster Ltd.", "author_email": "developers@toaster.co", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only" ], "description": "# Secure GAE Scaffold (Python 3)\n\n## Introduction\n\nPlease note: this is not an official Google product.\n\nThis is a secure scaffold package designed primarily to work with\nGoogle App Engine (although it is not limited to this).\n\nIt is built using Python 3 and Flask.\n\nThe scaffold provides the following basic security guarantees by default through\na flask app factory found in `secure_scaffold/factories.py`. This app will:\n\n1. Set assorted security headers (Strict-Transport-Security, X-Frame-Options,\n X-XSS-Protection, X-Content-Type-Options, Content-Security-Policy) with\n strong default values to help avoid attacks like Cross-Site Scripting (XSS)\n and Cross-Site Script Inclusion. See `add_csp_headers` and\n `settings.CSP_CONFIG`.\n1. Verify XSRF tokens by default on authenticated requests using any verb other\n that GET, HEAD, or OPTIONS. See the `secure_scaffold/xsrf.py` for more information.\n\n## Usage\n\n### Installation\n\nAs this is currently in beta we have a beta pypi package.\n\nThis project can be installed via\n\n`pip install toaster-secure-scaffold-rc`\n\nFor your convenience we also have the option to install with various other\ndependencies for the contrib APIs such as cloud-tasks, Datastore and Firestore.\n\nThese can be included with the `[]` syntax. For example all of them can be installed\nvia:\n\n`pip install toaster-secure-scaffold-rc[datastore,firestore,tasks]`\n\n### Setup\n\nOnce installed you can easily begin a new project by running:\n\n secure_scaffold start-project PROJECT_NAME GCLOUD_PROJECT_NAME\n\nMore details about this command can be found by running:\n\n secure_scaffold start-project --help\n\n\n### App Factory\n\nTo use the secure scaffold in your app, use our app generator.\n\n```python\nfrom secure_scaffold import factories\n\napp = factories.AppFactory().generate()\n```\n\nThis will automatically set all the needed CSP headers.\n\n### XSRF\n\nTo enable XSRF protection add the decorator to the endpoints you need it for.\nThis needs to be set *after* the route decorator\ne.g.\n\n```python\nfrom secure_scaffold import factories\nfrom secure_scaffold import xsrf\n\napp = factories.AppFactory().generate()\n\n@app.route('/', methods=['GET', 'POST'])\n@xsrf.xsrf_protected()\ndef index():\n return 'Hello World!'\n```\n\n\nWe use Flask Sessions for XSRF, for this you should set up a unique Secret Key for your application.\n\nA random one is set in the app factory, but you should overwrite this yourself, see [Flask Sessions](http://flask.pocoo.org/docs/1.0/quickstart/#sessions)\n\n\n### Settings Config\n\nSimilar to django settings, to enable multiple settings files you need to set an environment variable.\nYour folder structure should include a settings folder containing your settings files, for example:\n\n my_project/\n settings/\n __init__.py\n base.py\n development.py\n production.py\n\nYou should then set the environment variable (**SETTINGS_MODULE**) to the settings you require in that environment.\n\n export SETTINGS_MODULE=settings.development\n\nYou can then import your settings in your project like this:\n\n from secure_scaffold.config import settings\n\n\n### Authentication\n\nThe Secure Scaffold provides two methods of authentication. One is an in built\nauthentication system relying on Googles OAuth2 system. The alternative is a system relying on IAP\n\n#### OAuth2 Users\n\nSecond generation App Engine systems have had the Users API removed so the majority of\nthe original functionality isn't available. As a result it is now recommended to use\nseparate systems such as Googles OAuth2. The Secure Scaffold provides a wrapper for this\nbased heavily on [this guide](https://developers.google.com/identity/sign-in/web/sign-in).\n\nFor this to work there is some minimal setup.\n\nThe first is to provide an OAuth Client ID. To do this go to the GCloud console and create\nan OAuth Client ID [here](https://console.cloud.google.com/apis/credentials). Ensure you add\nthe domains you are using to the `Authorised JavaScript Origins` and `Authorised redirect URIs`.\nYou can include `localhost:5000` in these to enable using this system in development.\n\nOnce you have a `Client ID` add it to your settings file like so:\n\n```python\nAUTH_OAUTH_CLIENT_ID = 'my-client-id'\n```\n\nOnce done all that is required is to register the auth blueprint to your project like so:\n\n```python\nfrom secure_scaffold import factories\nfrom secure_scaffold.contrib.users.auth import auth_handler\n\n\napp = factories.AppFactory().generate()\napp.register_blueprint(auth_handler.blueprint)\n```\n\nThis creates two enpoints at `/auth/login` and `/auth/authenticate`. Login provides a frontend\nwith a Google sign in button. This sends an API request to `/auth/authenticate` which validates\nthe login procedure and returns an endpoint to redirect to. By default this is `/`.\n\nIf you want to force a user to be logged in to access a URL you can use the provided\n`requires_login` decorator like so:\n\n```python\nfrom secure_scaffold import factories\nfrom secure_scaffold.contrib.users.auth import auth_handler\n\n\napp = factories.AppFactory().generate()\napp.register_blueprint(auth_handler.blueprint)\n\n\n@app.route('/')\n@auth_handler.requires_login\ndef private_view():\n return \"You can't see this unless you are logged in.\"\n```\n\nIf a user is logged in they will be able to see the page. If they are not they will\nautomatically be redirected to `/auth/login`.\n\n##### Extending the OAuth2 system.\n\nThe OAuth2 system is built using a class at `secure_scaffold.contrib.users.auth.AuthHandler`.\n\nThis class is designed to be easy to subclass and override. For instance if you wanted to\nchange the URL which the user is redirected to on logging in you can do it like so:\n\n```python\nfrom secure_scaffold import factories\nfrom secure_scaffold.contrib.users.auth import AuthHandler\n\napp = factories.AppFactory().generate()\n\nclass MyAuthHandler(AuthHandler):\n redirect_url = '/after-login'\n\nauth_handler = MyAuthHandler()\napp.register_blueprint(auth_handler.blueprint)\n```\n\n#### IAP Users\n\nThis is available at `secure_scaffold.contrib.appengine.users`. It provides a `User`\nclass which has a few useful methods providing the details of the current user.\nIt also provides `requires_auth` and `requires_admin` decorators which enforce the need\nfor authentication and admin rights respectively on the views they are applied to.\n\nThese work almost identically to how they do in the first generation App Engine APIs.\n\nTo use these you will need to enable IAP on your App Engine instance. This is \nprovides the app with the correct headers for this functionality.\n\n\n### Datastore/Firestore\n\nThe Secure Scaffold comes with a built in API for both Datastore and Firestore.\n\nThis is a partial ORM - it allows you to simply define data models, to create, \nretrieve, update and delete them (CRUD). However it does not work with relations\nor nested entities/documents.\n\nTo use this API you must create a settings file with a variable called `DATABASE_SETTINGS`.\nThis has to be a dict with two fields, an `engine` field and a `settings` field.\n\n- `engine` must reference a module with the appropriate database engine, this\nallows the code to switch between databases such as firestore and datastore with\na single setting change.\n- `settings` are the settings that will be passed to the database engine client. As a\nminimum these should contain `project` pointing to the gcloud project.\n\nThe settings should something like this:\n\n```python\nDATABASE_SETTINGS = {\n 'engine': 'secure_scaffold.contrib.db.engine.firestore',\n 'settings': {\n 'project': 'my-gcloud-project-id'\n }\n}\n```\n\nThe above uses the firestore engine. To use Datastore instead you should replace\n`secure_scaffold.contrib.db.engine.firestore` with \n`secure_scaffold.contrib.db.engine.datastore`. There are no other code changes required.\n\n\nThe API can be used like so:\n\n```python\nfrom secure_scaffold.contrib.db import models\n\n\nclass Person(models.Model):\n name = models.Field(str, primary=True)\n age = models.Field(int)\n arms = models.Field(int, default=2)\n social_security = models.Field(str, unique=True)\n data = models.Field(dict, required=False)\n\n\n# Create some people.\nPerson(name='John', age=30, social_security='111-11-1111').save()\nPerson(name='Jane', age=30, social_security='222-22-2222').save()\n\n\njanes = Person.get(name='Jane') # Returns a generator which yields all objects with a name of 'Jane'\nfor jane in janes:\n jane.age = 28\n jane.save() # Updates Jane to have an age of 28 in the database.\n\npeople = Person.get_all() # Gives a generator which will yield all the people\nfor person in people:\n print(person.name) # Prints 'John' and then 'Jane'\n print(person.age) # Prints 30 and then 28\n print(person.arms) # Prints 2 and then 2\n person.delete() # Deletes the entry in the database.\n```\n\nThe API operates a basic validation system - you define fields within a model class,\neach field has a type and some optional args. If the field receives an object of the\nwrong type it will raise an error.\n\n\n### Tasks\n\nThe Secure Scaffold comes with a system for setting up tasks with\n[Google Cloud Tasks](https://cloud.google.com/tasks/).\n\nThis system works by creating a `TaskRunner` class instance and registering functions\nas `Task` objects using a decorator provided by the `TaskRunner` instance.\n\nThis creates a view in a [Flask blueprint](http://flask.pocoo.org/docs/dev/blueprints/)\nstored in the `TaskRunner` instance and adds a `delay` method to the registered\nfunction - allowing the function to be run later by the task queue.\n\n#### Setup\n\nFor this module to work you must first install `google-cloud-tasks`:\n\n pip install google-cloud-tasks\n\nYou must also add a `CLOUD_TASKS_QUEUE_CONFIG` object to your settings file.\nIt should look like this:\n\n```python\nCLOUD_TASKS_QUEUE_CONFIG = {\n 'project': 'YOUR GCLOUD PROJECT NAME',\n 'location': 'YOUR TASKE QUEUE LOCATION',\n 'queue': 'YOUR TASK QUEUE NAME'\n}\n```\n\n#### Using\n\nA basic example of the task system is as follows:\n\n```python\nfrom flask import request\n\nfrom secure_scaffold import factories\nfrom secure_scaffold.contrib.cloud_tasks import tasks\n\n\napp = factories.AppFactory().generate()\n\ntask_runner = tasks.TaskRunner('tasks', __name__, url_prefix='/tasks')\n\napp.register_blueprint(task_runner.blueprint)\n\n\n@task_runner.task(route='/print_task', methods=['POST'])\ndef print_task():\n arg = request.json().get('arg')\n print(arg)\n return 'OK'\n\n\n@app.route('/')\ndef main():\n print_task.delay(arg='Hello, World!')\n return 'OK'\n```\n\nThis sets up a Secure Scaffold app as well as a task runner. It then registers\nthe blueprint of the task runner in the app.\n\nWe create a task function, which gets an argument called `arg` from\nthe global `request` object and prints it. This is registered as a task\nusing the `task_runner.task` decorator.\n\nFinally we create a flask route called `main` which calls the `delay` method\nof our task.\n\nBehind the scenes what happens is our `task_runner` creates a `Task` object\ncontaining this function and a `delay` method. It then registers the object\nas a flask route at `/tasks/print_task/`. The `Task` objects delay method\nmakes a request to the cloud tasks API to create a task for this method in\nthe queue. It takes any arbitrary arguments and keyword arguments and adds\nthem to the body of this request - making them accessible via the \n`flask.request` global variable within the task. \n\n## Scaffold Development\n\n### Structure:\n\n`secure_scaffold/` \n- Top level directory\n\n`secure_scaffold/contrib` \n- Contains non-essential but useful libraries.\n- Holds several alternatives to App Engine APIs \nwhich are no longer available in second generation instances \n\n`secure_scaffold/tests` \n- Tests for the secure scaffold \n\n`secure_scaffold/config.py` \n- Similar to django settings set up \n- Looks for the \"SETTINGS_MODULE\" environment variable to be set \n- See Settings Config below on how to use this\n\n`secure_scaffold/factories.py`\n- The main Flask app factory that applies the security defaults\n- See App Factory below on how to use this\n\n`secure_scaffold/settings.py`\n- Security settings \n- Defines our CSP headers and other specifics\n\n`secure_scaffold/xsrf.py`\n- Defines XSRF decorators to be used with your flask app \n- See XSRF below on how to use this\n\n### Dependency Setup\n\nWe recommend setting up a virtual env to install dependencies:\n\n`virtualenv env --python=python3`\n\n`source env/bin/activate`\n\n`pip install -r dev_requirements.txt`\n\nThere are some extra dependencies required for the development on specific submodules.\n\nThese include:\n\n- `google-cloud-firestore` for development on `secure_scaffold.contrib.db.engine.firestore\n- `google-cloud-datastore` for development on `secure_scaffold.contrib.db.engine.datastore\n- `google-cloud-tasks` for development on `secure_scaffold.contrib.cloud_tasks.tasks\n\n### Testing\n\nTo run unit tests:\n\n`pytest`\n\n\n## Third Party Credits\n\n- Flask\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/toasterco/gae-secure-scaffold-python", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "Toaster-Secure-Scaffold-RC", "package_url": "https://pypi.org/project/Toaster-Secure-Scaffold-RC/", "platform": "", "project_url": "https://pypi.org/project/Toaster-Secure-Scaffold-RC/", "project_urls": { "Homepage": "https://github.com/toasterco/gae-secure-scaffold-python" }, "release_url": "https://pypi.org/project/Toaster-Secure-Scaffold-RC/0.8.2/", "requires_dist": [ "flask (==1.0.2)", "click (==7.0)", "google-cloud-datastore (==1.8.0) ; extra == 'datastore'", "google-cloud-firestore (==1.2.0) ; extra == 'firestore'", "google-cloud-tasks (==1.1.0) ; extra == 'tasks'" ], "requires_python": "", "summary": "Secure Scaffold for Google App Engine", "version": "0.8.2" }, "last_serial": 5728708, "releases": { "0.8.1": [ { "comment_text": "", "digests": { "md5": "5def6fd827724e538f65003701c25f9f", "sha256": "dd6224d767a839c640b5754d8c53c289684345093f2d96ff43ae0de44c55fe35" }, "downloads": -1, "filename": "Toaster_Secure_Scaffold_RC-0.8.1-py3-none-any.whl", "has_sig": false, "md5_digest": "5def6fd827724e538f65003701c25f9f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 42928, "upload_time": "2019-08-22T02:34:37", "url": "https://files.pythonhosted.org/packages/de/79/22b6802fd65ece90b51311422eca07e42cf0dea228c672a9da6a93382116/Toaster_Secure_Scaffold_RC-0.8.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "822d8636fdea2636e8fa09a08188f2b4", "sha256": "527c86b13ad37489ebcbb180eef7986cdb92e4d23ce033cedfe693b7af8203fa" }, "downloads": -1, "filename": "Toaster Secure Scaffold RC-0.8.1.tar.gz", "has_sig": false, "md5_digest": "822d8636fdea2636e8fa09a08188f2b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32659, "upload_time": "2019-08-22T02:34:40", "url": "https://files.pythonhosted.org/packages/91/d1/a896c355a0b9f3130e114f18529649b9ccfe0f36b3f250158868dc3a5ebc/Toaster%20Secure%20Scaffold%20RC-0.8.1.tar.gz" } ], "0.8.2": [ { "comment_text": "", "digests": { "md5": "0da94fc5cff4fc704bbde708583de283", "sha256": "8503f01a0ddd671c24735e3288f643fc7869566b5d0b1f9a9a6a766ada8f8760" }, "downloads": -1, "filename": "Toaster_Secure_Scaffold_RC-0.8.2-py3-none-any.whl", "has_sig": false, "md5_digest": "0da94fc5cff4fc704bbde708583de283", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 42920, "upload_time": "2019-08-26T03:07:41", "url": "https://files.pythonhosted.org/packages/df/f7/5358dfd3abe036f0a272c48400e18993630b2192d1f821735fab7a760d19/Toaster_Secure_Scaffold_RC-0.8.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f46cc74ebee5168b596c6fc18794b5d8", "sha256": "a2df32bc823afb9affb4b45873172d61aed44c08f86c99435f5caf3a6ed6fe2e" }, "downloads": -1, "filename": "Toaster Secure Scaffold RC-0.8.2.tar.gz", "has_sig": false, "md5_digest": "f46cc74ebee5168b596c6fc18794b5d8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32666, "upload_time": "2019-08-26T03:07:43", "url": "https://files.pythonhosted.org/packages/a0/b7/7008a0f9dacdb0a4fc76ce4d6bccc8de19ce14930c02bc2ba8aff0678bf7/Toaster%20Secure%20Scaffold%20RC-0.8.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0da94fc5cff4fc704bbde708583de283", "sha256": "8503f01a0ddd671c24735e3288f643fc7869566b5d0b1f9a9a6a766ada8f8760" }, "downloads": -1, "filename": "Toaster_Secure_Scaffold_RC-0.8.2-py3-none-any.whl", "has_sig": false, "md5_digest": "0da94fc5cff4fc704bbde708583de283", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 42920, "upload_time": "2019-08-26T03:07:41", "url": "https://files.pythonhosted.org/packages/df/f7/5358dfd3abe036f0a272c48400e18993630b2192d1f821735fab7a760d19/Toaster_Secure_Scaffold_RC-0.8.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f46cc74ebee5168b596c6fc18794b5d8", "sha256": "a2df32bc823afb9affb4b45873172d61aed44c08f86c99435f5caf3a6ed6fe2e" }, "downloads": -1, "filename": "Toaster Secure Scaffold RC-0.8.2.tar.gz", "has_sig": false, "md5_digest": "f46cc74ebee5168b596c6fc18794b5d8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32666, "upload_time": "2019-08-26T03:07:43", "url": "https://files.pythonhosted.org/packages/a0/b7/7008a0f9dacdb0a4fc76ce4d6bccc8de19ce14930c02bc2ba8aff0678bf7/Toaster%20Secure%20Scaffold%20RC-0.8.2.tar.gz" } ] }