Local Data Provider Development Mode¶
Deprecated since version 0.2.4: As of version 0.2.4 it’s possible to run locally within a gunicorn container, as this is equivalently simple to configure and considerably easier to use for unit testing and similar purposes, support for the SSL local dev mode described here should be considered obsolete.
Warning
Please note! This should not be used in production. It is solely to help make your life simpler, when developing a data provider, by allowing you to run everything locally with full SSL support enabled.
You may want to run your Flask app locally when testing, but the security requirements of OE3 mean you really need
to use HTTPS, and have everything validate correctly. In addition, to make use of the AccessTokenValidator
you need
any test clients to present valid client certificates. This can all get rather messy, so this library includes a couple
of helper functions to allow you to run your app locally using Flask’s built-in development server.
Obtaining a valid server certificate¶
To run on localhost
or 127.0.0.1
you will need a corresponding SSL certificate, and you’ll need to get the
signing chain for that certificate into Python’s list of trusted CAs. For this we recommend the minimal CA project
that can be found at https://github.com/jsha/minica - this will create a certificate for your server as well as a root
certificate. You need to add this root certificate to the certifi
CA, assuming your root is called minica.pem
(the default) you can install it with:
> cat minica.pem >> `python3 -m certifi`
This must be done on any virtual environment that’s going to make calls to your server as it will be used when validating the server certificate. Ensure that you have any virtual environment activated before running this command, it will install into whatever python is currently active.
Running in dev mode¶
Once you have a certificate for your server to hand, and have installed the appropriate root cert, you can use the
helper functions in ib1.openenergy.support.flask_ssl_dev
to run your app.
The function get_command_line_ssl_args
can be used to parse command line arguments and add help functionality, putting
this in your app then calling it with myapp.py --help
will produce output similar to this:
tom@sparkles:~/Desktop/certs$ python myapp.py --help
usage: app.py [-h] [-sk SERVER_PRIVATE_KEY] [-sc SERVER_CERTIFICATE] [-ck CLIENT_PRIVATE_KEY]
[-cc CLIENT_CERTIFICATE] [-cid CLIENT_ID]
optional arguments:
-h, --help show this help message and exit
-sk SERVER_PRIVATE_KEY, --server_private_key SERVER_PRIVATE_KEY
Server private key file, default "127.0.0.1/key.pem"
-sc SERVER_CERTIFICATE, --server_certificate SERVER_CERTIFICATE
Server certificate file, default "127.0.0.1/cert.pem"
-ck CLIENT_PRIVATE_KEY, --client_private_key CLIENT_PRIVATE_KEY
Client private key file, default "a.key"
-cc CLIENT_CERTIFICATE, --client_certificate CLIENT_CERTIFICATE
Client certificate file, default "a.pem"
-cid CLIENT_ID, --client_id CLIENT_ID
OAuth2 client ID for calls made from this app
You can set defaults for certificate locations and client ID in the call to get_command_line_ssl_args
. This function
produces a SSLOptions
object from which properties can be extracted to run your app with run_app
The example data provider from Providing OE Shared Data, repeated below, uses get_command_line_ssl_args
on line 12
to get locations of certificate files as well as the OAuth2 client ID, these are then passed both to the
AccessTokenValidator
on line 18 and the call to actually run the app with run_app
on line 37.
1import logging
2
3import flask
4
5from ib1.openenergy.support import AccessTokenValidator
6from ib1.openenergy.support.flask_ssl_dev import get_command_line_ssl_args, run_app
7
8logging.basicConfig(level=logging.INFO)
9
10LOG = logging.getLogger('ib1.oe.testapp')
11
12options = get_command_line_ssl_args(default_client_private_key='a.key',
13 default_client_certificate='a.pem',
14 default_server_private_key='127.0.0.1/key.pem',
15 default_server_certificate='127.0.0.1/cert.pem',
16 default_client_id='kZuAsn7UYZ98WWh29hDPf')
17
18validator = AccessTokenValidator(client_id=options.client_id, certificate=options.client_certificate,
19 private_key=options.client_private_key,
20 issuer_url='https://matls-auth.directory.energydata.org.uk/')
21app = flask.Flask(__name__)
22
23
24@app.route('/')
25@validator.introspects(scope='')
26def homepage():
27 """
28 This is a very simple route that doesn't do much, but as it's decorated with the validator
29 token introspection endpoint it will trigger inspection of the supplied bearer token via the
30 directory introspection point, and the resultant object will be passed as flask.g.introspection_response.
31 """
32 LOG.info(f'home: received MTLS HTTPS request from {flask.request.remote_addr}')
33 LOG.info(f'home: token introspection response is {flask.g.introspection_response}')
34 return flask.send_from_directory(directory='/home/tom/Desktop/data-provider',
35 filename='Postcode_level_all_meters_electricity_2019.csv')
36
37
38run_app(app=app,
39 server_private_key=options.server_private_key,
40 server_certificate=options.server_certificate)