diff --git a/bankid/asyncclient.py b/bankid/asyncclient.py index b5ac6b4..2257c3a 100644 --- a/bankid/asyncclient.py +++ b/bankid/asyncclient.py @@ -1,8 +1,8 @@ -from typing import Optional, Tuple, Dict, Any, Awaitable +from typing import Optional, Tuple, Dict, Any import httpx -from bankid.base import BankIDClientBaseclass +from bankid.baseclient import BankIDClientBaseclass from bankid.exceptions import get_json_error_class diff --git a/bankid/base.py b/bankid/baseclient.py similarity index 100% rename from bankid/base.py rename to bankid/baseclient.py diff --git a/bankid/syncclient.py b/bankid/syncclient.py index 67d5fc9..8da625c 100644 --- a/bankid/syncclient.py +++ b/bankid/syncclient.py @@ -2,7 +2,7 @@ import httpx -from bankid.base import BankIDClientBaseclass +from bankid.baseclient import BankIDClientBaseclass from bankid.exceptions import get_json_error_class diff --git a/docs/api_reference.rst b/docs/api_reference.rst index 47e0232..cb7ec4c 100644 --- a/docs/api_reference.rst +++ b/docs/api_reference.rst @@ -4,10 +4,22 @@ API Reference ============= -:mod:`bankid.jsonclient` -- Clients -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:mod:`bankid.syncclient` -- Base Client (parent) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: bankid.baseclient + :members: + +:mod:`bankid.syncclient` -- Synchronous Client +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: bankid.syncclient + :members: + +:mod:`bankid.asyncclient` -- Asynchronous Client +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. automodule:: bankid.jsonclient +.. automodule:: bankid.asyncclient :members: :mod:`bankid.exceptions` -- Exceptions diff --git a/docs/certutils.rst b/docs/certutils.rst index cdaa656..2f814fd 100644 --- a/docs/certutils.rst +++ b/docs/certutils.rst @@ -44,7 +44,7 @@ into one certificate and one key part and converts it from `.p12 or .pfx `_ format to `pem `_. These can then be used for testing purposes, by sending in ``test_server=True`` -keyword in the :py:class:`~BankIDClient` or :py:class:`~BankIDJSONClient`. +keyword in the :py:class:`~BankIDClient` or :py:class:`~BankIdAsyncClient`. Splitting certificates diff --git a/docs/examples.rst b/docs/examples.rst index 2365cd0..3061f3f 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,30 +1,71 @@ .. _examples: +=================== Generating QR codes -------------------- +=================== -PyBankID cannot generate QR codes for you, but there is an example application in the +PyBankID can generate QR codes for you. There is an example application in the `examples folder of the repo `_ where a Flask application called ``qrdemo`` shows one way to do authentication with animated QR codes. -The content for the QR code is generated by this method: +Below follows the app's README file: -.. code-block:: python +QR Authentication Example +------------------------- - import hashlib - import hmac - from math import floor - import time +Making a simple authentication via QR code solution using Flask, Flask-Caching and PyBankID. - def generate_qr_code_content(qr_start_token: str, start_t: float, qr_start_secret: str): - """Given QR start token, time.time() when initiated authentication call was made and the - QR start secret, calculate the current QR code content to display. - """ - elapsed_seconds_since_call = int(floor(time.time() - start_t)) - qr_auth_code = hmac.new( - qr_start_secret.encode(), - msg=str(elapsed_seconds_since_call).encode(), - digestmod=hashlib.sha256, - ).hexdigest() - return f"bankid.{qr_start_token}.{elapsed_seconds_since_call}.{qr_auth_code}" +Running the application +~~~~~~~~~~~~~~~~~~~~~~~ +1. Navigate your terminal to the same folder that this README resides in. +2. Create a virtualenv: ``python -m venv .venv`` +3. Activate it. +4. Install requirements: ``pip install -r requirements.txt`` +5. Run Flask app: + + 1. From Bash: + + ```bash + $ export FLASK_APP=qrdemo.app:app + $ flask run -h 0.0.0.0 + ``` + 2. From Powershell: + + ```powershell + > $env:FLASK_APP = "qrdemo.app:app" + > flask run -h 0.0.0.0 + ``` + +The app can now be accessed from the running computer on ``http://127.0.0.1:5000``, ``http://localhost:5000`` or from an +external device on the same network on ``http://:5000``. + + +Basic workflow +~~~~~~~~~~~~~~ + +These are the steps that the application takes: + +1. Ask the user for Swedish Personal Identity Number (PN) or initiate an authentication without. +2. Upon POSTing that PN to the backend, initiate a BankID ``authenticate`` session. This generates tokens that + one can create QR codes from using the ``generate_qr_code_content`` method. +3. Continuously update the QR code according to the description in the BankID Relying Party Guidelines + Version: 3.6 (see below, Chapter 4). The new QR code content to display MUST be fetched from the backend since + the ``qrStartSecret`` must never be shown to the user for the authentication to be trustworthy. +4. Also make ``collect`` calls to the BankID servers continuously and monitor if signing is complete or failed. +5. Redirect when complete or failed. + + +Missing components +~~~~~~~~~~~~~~~~~~ + +There are a few shortcuts taken here: + +- There is no error handling of ``status: failed`` results when collecting the authentication response. +- There is no ``Recommended User Messages (RFA)`` handling. It merely displays the ``status`` and ``hintCode`` from the collect response. +- The Cache is a memory cache on this single instance web app. + +References +~~~~~~~~~~ + +[BankID Integration Guide](https://www.bankid.com/en/utvecklare/guider/teknisk-integrationsguide/) diff --git a/docs/get_started.rst b/docs/get_started.rst index 55e54a4..e1dcd9c 100644 --- a/docs/get_started.rst +++ b/docs/get_started.rst @@ -3,7 +3,7 @@ Getting Started =============== -PyBankID use BankID JSON API version 5.1 released in April 2020. +PyBankID use BankID JSON API version 6.0 released in May 2023. Installation ------------ @@ -19,11 +19,11 @@ Dependencies PyBankID makes use of the following external packages: -* `httpx==0.24.1 `_ -* `importlib-resources==5.12.0 `_ +* `httpx`_ +* `importlib-resources>=5.12.0 `_ Using the client ----------------------- +---------------- PyBankID provide both a synchronous and an asynchronous client for communication with BankID services. Example below will use the asynchronous @@ -34,7 +34,7 @@ Get started by importing and initializing the client: .. code-block:: python >>> from bankid import AsyncBankIDJSONClient - >>> client = AsyncBankIDJSONClient(certificates=( + >>> client = BankIdAsyncClient(certificates=( ... 'path/to/certificate.pem', ... 'path/to/key.pem', ... )) @@ -48,8 +48,7 @@ is initiated as such: .. code-block:: python - >>> await client.authenticate(end_user_ip='194.168.2.25', - ... personal_number="YYYYMMDDXXXX") + >>> await client.authenticate(end_user_ip='194.168.2.25') { 'orderRef': 'ee3421ea-2096-4000-8130-82648efe0927', 'autoStartToken': 'e8df5c3c-c67b-4a01-bfe5-fefeab760beb', @@ -61,9 +60,10 @@ and a sign order is initiated in a similar fashion: .. code-block:: python - >>> await client.sign(end_user_ip='194.168.2.25', - ... user_visible_data="The information to sign.", - ... personal_number="YYYYMMDDXXXX") + >>> await client.sign( + ... end_user_ip='194.168.2.25', + ... user_visible_data="The information to sign." + ...) { 'orderRef': 'ee3421ea-2096-4000-8130-82648efe0927', 'autoStartToken': 'e8df5c3c-c67b-4a01-bfe5-fefeab760beb', @@ -71,28 +71,44 @@ and a sign order is initiated in a similar fashion: 'qrStartSecret': 'b4214886-3b5b-46ab-bc08-6862fddc0e06' } -Since we are using BankID ``v5.1`` JSON API, the `personal_number` can now be omitted when calling -`authenticate` and `sign`. See `BankID Relying Party Guidelines `_ -for more information about this. +If you want to ascertain that only one individual can authenticate or sign, you can +specify this using the ``requirement`` keyword: + +.. code-block:: python + + >>> await client.sign( + ... end_user_ip='194.168.2.25', + ... user_visible_data="The information to sign." + ... requirement={"personalNumber": "YYYYMMDDXXXX"} + ...) + { + 'orderRef': 'ee3421ea-2096-4000-8130-82648efe0927', + 'autoStartToken': 'e8df5c3c-c67b-4a01-bfe5-fefeab760beb', + 'qrStartToken': '01f94e28-857f-4d8a-bf8e-6c5a24466658', + 'qrStartSecret': 'b4214886-3b5b-46ab-bc08-6862fddc0e06' + } + +If someone else than the one you specified tries to authenticate or sign, the +BankID app will state that the request is not intended for the user. The status of an order can then be studied by polling with the ``collect`` method using the received ``orderRef``: .. code-block:: python - >>> await client.collect(order_ref="a9b791c3-459f-492b-bf61-23027876140b") + >>> await client.collect("a9b791c3-459f-492b-bf61-23027876140b") { 'hintCode': 'outstandingTransaction', 'orderRef': 'a9b791c3-459f-492b-bf61-23027876140b', 'status': 'pending' } - >>> await client.collect(order_ref="a9b791c3-459f-492b-bf61-23027876140b") + >>> await client.collect("a9b791c3-459f-492b-bf61-23027876140b") { 'hintCode': 'userSign', 'orderRef': 'a9b791c3-459f-492b-bf61-23027876140b', 'status': 'pending' } - >>> await client.collect(order_ref="a9b791c3-459f-492b-bf61-23027876140b") + >>> await client.collect("a9b791c3-459f-492b-bf61-23027876140b") { 'completionData': { 'cert': { @@ -116,31 +132,27 @@ with the ``collect`` method using the received ``orderRef``: } Please note that the ``collect`` method should be used sparingly: in the -`BankID Relying Party Guidelines `_ +`BankID Integration Guide `_ it is specified that *"collect should be called every two seconds and must not be called more frequent than once per second"*. Synchronous client ----------------------- +------------------ The synchronous client is used in the same way as the asynchronous client, but the -methods are blocking. The synchronous client call the aynchronous client under the -hood. +methods are blocking. The asynchronous guide above can be used as a reference for the synchronous client -as well, by simply removing the `await` keyword. +as well, by simply removing the ``await`` keyword. .. code-block:: python - >>> from bankid import BankIDJSONClient - >>> client = BankIDJSONClient(certificates=( + >>> from bankid import BankIdClient + >>> client = BankIdClient(certificates=( ... 'path/to/certificate.pem', ... 'path/to/key.pem', ... )) - >>> client.authenticate( - ... end_user_ip='194.168.2.25', - ... personal_number="YYYYMMDDXXXX", - ... ) + >>> client.authenticate(end_user_ip='194.168.2.25') { 'orderRef': 'ee3421ea-2096-4000-8130-82648efe0927', 'autoStartToken': 'e8df5c3c-c67b-4a01-bfe5-fefeab760beb', diff --git a/docs/index.rst b/docs/index.rst index 239f014..07223a2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,9 +23,14 @@ providing authentication and signing functionality to end users. This package provides a simplifying interface for initiating authentication and signing orders and then collecting the results from the BankID servers. +The only supported BankID API version supported by PyBankID from version 1.0.0 +is v6.0, which means that the Secure Start solution is the only supported way +of providing BankID services. PyBankID versions prior to 1.0.0 will not +work after 1st of May 2024. + If you intend to use PyBankID in your project, you are advised to read -the `BankID Relying Party Guidelines -`_ before +the `BankID Integration Guide +`_ before doing anything else. There, one can find information about how the BankID methods are defined and how to use them. diff --git a/examples/qrdemo/README.md b/examples/qrdemo/README.md index b6d27b1..a2a0582 100644 --- a/examples/qrdemo/README.md +++ b/examples/qrdemo/README.md @@ -28,7 +28,7 @@ external device on the same network on `http://:500 These are the steps that the application takes: -1. Ask the user for Swedish Personal Identity Number (PN). +1. Ask the user for Swedish Personal Identity Number (PN) or initiate an authentication without. 2. Upon POSTing that PN to the backend, initiate a BankID `authenticate` session. This generates tokens that one can create QR codes from using the `generate_qr_code_content` method. 3. Continuously update the QR code according to the description in the BankID Relying Party Guidelines @@ -48,5 +48,4 @@ There are a few shortcuts taken here: ## References -[BankID Relying Party Guidelines -Version: 3.6](https://www.bankid.com/assets/bankid/rp/bankid-relying-party-guidelines-v3.6.pdf) +[BankID Integration Guide](https://www.bankid.com/en/utvecklare/guider/teknisk-integrationsguide/)