1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
.. _tans:
Working with TANs
=================
Many operations in FinTS will require a form of two-step authentication, called TANs. TANs are
mostly required for operations that move money or change details of a bank account. TANs can be
generated with a multitude of methods, including paper lists, smartcard readers, SMS messages, and
smartphone apps.
TAN methods
-----------
Before doing any operations involving TANs, you should get a list of supported TAN mechanisms:
.. code-block:: python
mechanisms = client.get_tan_mechanisms()
The returned dictionary maps identifiers (generally: three-digit numerals) to instances of a
:func:`~fints.formals.TwoStepParametersCommon` subclass with varying fields, depending on the
version of the two-step process and the bank.
The `name` field of these objects provides a user-friendly name of the TAN mechanism that you
can display to the user to choose from. To select a TAN mechanism, you can use
:func:`~fints.client.FinTS3PinTanClient.set_tan_mechanism`, which takes the identifier used as
key in the :func:`~fints.client.FinTS3PinTanClient.get_tan_mechanisms` return value.
If the ``description_required`` attribute for the TAN mechanism is :attr:`~fints.formals.DescriptionRequired.MUST`,
you will need to get a list of TAN media with :func:`~fints.client.FinTS3PinTanClient.get_tan_media` and select the
appropriate one with :func:`~fints.client.FinTS3PinTanClient.set_tan_medium`.
Have a look at the source code of :func:`~fints.utils.minimal_interactive_cli_bootstrap` for an example on how to
ask the user for these properties.
You may not change the active TAN mechanism or TAN medium within a standing dialog (see :ref:`client-dialog-state`).
The selection of the active TAN mechanism/medium is stored with the persistent client data (see :ref:`client-state`).
.. autoclass:: fints.client.FinTS3PinTanClient
:members: get_tan_mechanisms, set_tan_mechanism, get_current_tan_mechanism, get_tan_media, set_tan_medium
:noindex:
:undoc-members:
TAN challenges
--------------
When you try to perform an operation that requires a TAN to proceed, you will receive an object containing
the bank's challenge (and some internal data to continue the operation once the TAN has been processed):
.. autoclass:: fints.client.NeedTANResponse
:undoc-members:
:members:
The ``challenge`` attribute will contain human-readable instructions on how to proceed.
The ``challenge_html`` attribute will possibly contain a nicer, formatted, HTML version of the challenge text
that you should prefer if your primary interface can render HTML. The contents are guaranteed to be proper and
clean (by using the `bleach` library): They can be used with `mark_safe` in Django.
The ``challenge_hhduc`` attribute will contain the challenge to be used with a TAN generator device using the
Hand Held Device Unidirectional Coupling specification (such as a Flicker-Code).
Flicker-Code / optiTAN
----------------------
If you want to use chipTAN with an optical TAN device, we provide utilities to print the flicker code on
a unix terminal. Just pass the ``challenge_hhd_uc`` value to this method:
.. autofunction:: fints.hhd.flicker.terminal_flicker_unix
You should probably catch for ``KeyboardInterrupts`` to allow the user to abort the displaying and to continue
with the TAN:
.. code-block:: python
try:
terminal_flicker_unix(result.challenge_hhduc)
except KeyboardInterrupt:
pass
photoTAN
--------
If you want to use photoTAN, use the ``challenge_matrix`` attribute to access the image file, e.g. by writing it to
a file:
.. code-block:: python
with open("tan.png", "wb") as writer:
writer.write(result.challenge_matrix[1])
writer.close()
Sending the TAN
---------------
Once obtained the TAN, you can send it with the ``send_tan`` client method:
.. autoclass:: fints.client.FinTS3PinTanClient
:members: send_tan
:noindex:
For example:
.. code-block:: python
tan = input('Please enter the TAN code: ')
result = client.send_tan(result, tan)
Storing and restoring TAN state
-------------------------------
The :func:`~fints.client.NeedTANResponse.get_data` method and
:func:`~fints.client.NeedRetryResponse.from_data` factory method can be used to store and restore
a TAN state object between steps.
.. autoclass:: fints.client.NeedRetryResponse
:undoc-members:
:members: from_data
You SHOULD use this facility together with the client and dialog state restoration facilities:
.. code-block:: python
:caption: First step
client = FinTS3PinTanClient(...)
# Optionally: choose a tan mechanism with
# client.set_tan_mechanism(…)
with client:
response = client.sepa_transfer(...)
dialog_data = client.pause_dialog()
client_data = client.deconstruct()
tan_data = response.get_data()
.. code-block:: python
:caption: Second step
tan_request = NeedRetryResponse.from_data(tan_data)
print("TAN request: {}".format(tan_request.challenge))
tan = input('Enter TAN: ')
.. code-block:: python
:caption: Third step
tan_request = NeedRetryResponse.from_data(tan_data)
client = FinTS3PinTanClient(..., from_data=client_data)
with client.resume_dialog(dialog_data):
response = client.send_tan(tan_request, tan)
print(response.status)
print(response.responses)
Reference
---------
.. autoclass:: fints.formals.TwoStepParameters2
:noindex:
:undoc-members:
:members:
:inherited-members:
:member-order: bysource
:exclude-members: is_unset, naive_parse, print_nested
.. autoclass:: fints.formals.TwoStepParameters3
:noindex:
:undoc-members:
:members:
:inherited-members:
:member-order: bysource
:exclude-members: is_unset, naive_parse, print_nested
.. autoclass:: fints.formals.TwoStepParameters5
:noindex:
:undoc-members:
:members:
:inherited-members:
:member-order: bysource
:exclude-members: is_unset, naive_parse, print_nested
|