LaunchKey Python SDK
Project description
Python SDK for TruValidate Multifactor Authentication API
For use in implementing TruValidate Multifactor Authentication.
Description
Use to more easily interact with TransUnion’s TruValidate Multifactor Authentication API.
A more in-depth look at this SDK can be found at the official docs.
Examples
CLI Example
Flask Webhooks Example
Installation
$ easy_install launchkey
or
$ pip install launchkey
Usage
Using TruValidate Multifactor Authentication Clients
The TruValidate Multifactor Authentication SDK is broken into credential based factories with access to functionality based clients.
Factories
Factories are based on the credentials supplied. The Organization Factory uses Organization credentials, the Directory Factory uses Directory credentials, and the Service Factory uses Service credentials. Each factory provides clients which are accessible to the factory. The availability is based on the hierarchy of the entities themselves. Below is a matrix of available services for each factory.
Factory |
Organization Client |
Directory Client |
Service Client |
---|---|---|---|
Organization |
Yes |
Yes |
Yes |
Directory |
No |
Yes |
Yes |
Service |
No |
No |
Yes |
Utilizing Single Purpose Keys
In the case that separate encryption and signature keys are being used. The initial key given to a factory will be used to sign requests, and any additional keys can be added after instantiation.
from launchkey.factories import OrganizationFactory
organization_id = "37d98bb9-ac71-44b7-9ac0-5d75e31e627a"
organization_signature_private_key = open("organization_signature_private_key.key").read()
organization_encryption_private_key = open("organization_encryption_private_key.key").read()
organization_factory = OrganizationFactory(organization_id, organization_signature_private_key)
organization_factory.add_encryption_private_key(organization_encryption_private_key)
from launchkey.factories import DirectoryFactory
directory_id = "37d98bb9-ac71-44b7-9ac0-5d75e31e627a"
directory_signature_private_key = open("directory_signature_private_key.key").read()
directory_encryption_private_key = open("directory_encryption_private_key.key").read()
directory_factory = DirectoryFactory(directory_id, directory_signature_private_key)
directory_factory.add_encryption_private_key(directory_encryption_private_key)
from launchkey.factories import ServiceFactory
service_id = "37d98bb9-ac71-44b7-9ac0-5d75e31e627a"
service_signature_private_key = open("service_signature_private_key.key").read()
service_encryption_private_key = open("service_encryption_private_key.key").read()
service_factory = ServiceFactory(organization_id, service_signature_private_key)
service_factory.add_encryption_private_key(service_encryption_private_key)
Using individual clients
from launchkey.factories import ServiceFactory, DirectoryFactory
directory_id = "37d98bb9-ac71-44b7-9ac0-5d75e31e627a"
directory_private_key = open('directory_private_key.key').read()
service_id = "9ecc57e0-fb0f-4971-ba12-399b630158b0"
service_private_key = open('service_private_key.key').read()
directory_factory = DirectoryFactory(directory_id, directory_private_key)
directory_client = directory_factory.make_directory_client()
service_factory = ServiceFactory(service_id, service_private_key)
service_client = service_factory.make_service_client()
Using a hierarchical client
from launchkey.factories import OrganizationFactory
organization_id = "bff1602d-a7b3-4dbe-875e-218c197e9ea6"
organization_private_key = open('organization_private_key.key').read()
directory_id = "37d98bb9-ac71-44b7-9ac0-5d75e31e627a"
service_id = "9ecc57e0-fb0f-4971-ba12-399b630158b0"
user = "my_unique_internal_identifier"
organization_factory = OrganizationFactory(
organization_id, organization_private_key)
directory_client = organization_factory.make_directory_client(directory_id)
service_client = organization_factory.make_service_client(service_id)
Linking And Managing Users
In order to link a user you will need to start the linking process then display the qrcode to them, give them the code, or both.
link_data = directory_client.link_device(user)
linking_code = link_data.code
qr_url = link_data.qrcode
If desired you can retrieve the user’s devices and unlink then directly from the SDK
devices = directory_client.get_linked_devices(user)
directory_client.unlink_device(user, devices[0].id)
You can also end all of a user’s sessions
directory_client.end_all_service_sessions(user)
Logging A User In
Create an auth request to initiate the login process
auth = service_client.authorization_request(user)
auth_request_id = auth.auth_request
Using Dynamic Policies
from launchkey.entities.service import AuthPolicy
# Require 2 factors and don't allow any jailbroken or rooted devices
policy = AuthPolicy(any=2, jailbreak_protection=True)
# Also make it so the user can only log in from the Portland area
policy.add_geofence(
latitude=45.48805749706375, longitude=-122.70492553710936, radius=27500)
auth_request_id = service_client.authorization_request(user, policy=policy)
Check whether a response has been received and check whether it has been authorized
from launchkey.exceptions import RequestTimedOut
from time import sleep
response = None
try:
while response is None:
response = service_client.get_authorization_response(auth_request_id)
if response is not None:
if response.authorized is True:
# User accepted the auth, now create a session
service_client.session_start(user, auth_request_id)
else:
# User denied the auth request
else:
sleep(1)
except RequestTimedOut:
# The user did not respond to the request in the timeout period (5 minutes)
When a user logs out
service_client.session_end(user)
TOTP
A user can have TOTP configured via the generate_user_totp method on the DirectoryClient.
identifier = "my-permanent-unique-user-identifier"
configuration = directory_client.generate_user_totp(identifier)
print(" Secret: " + configuration.secret)
print(" Algorithm: " + configuration.algorithm)
print(" Period: " + configuration.period)
print(" Digits: " + configuration.digits)
TOTP configurations can be removed via the generate_user_totp method on the DirectoryClient.
identifier = "my-permanent-unique-user-identifier"
directory_client.remove_user_totp(identifier)
Finally codes can be validated via the verify_totp method on the ServiceClient.
identifier = "my-permanent-unique-user-identifier"
otp = "569874"
valid = service_client.verify_totp(identifier, otp)
if valid:
# Handle success scenario
else:
# Handle failure scenario
Dealing with Webhooks
Webhooks can be used in opposition to polling. This means we will hit your app on either an auth response or logout request.
You will use the same handle_webhook method for both login and logout.
Note that request.headers must be a dictionary like object.
from flask import Flask, request
from launchkey.entities.service import AuthorizationResponse, \
SessionEndRequest
app = Flask(__name__)
# Path defined in your Service Callback URL value
@app.route('/launchkey', methods = ['POST'])
def launchkey_webhook():
package = service_client.handle_webhook(request.data, request.headers,
request.method, request.path)
if isinstance(package, AuthorizationResponse):
if package.authorized is True:
# User accepted the auth, now create a session
service_client.session_start(user, auth_request_id)
else:
# User denied the auth
handle_denial()
elif isinstance(package, SessionEndRequest):
# The package will have the user hash, so use it to log the user out
# based on however you are handling it
logout_user_from_my_app(package.service_user_hash)
Running Tests
Running tests is as simple as:
python setup.py test
Validating Code
The TruValidate Multifactor Authentication Service SDK supports and number of python versions and has fairly strict coding guidelines. Tests require a number of Python versions. The best way to manage these versions is with pyenv. You will need to register all of the versions with pyenv. There are a couple ways to do that. An example of doing it globally is:
pyenv local 3.6.13 3.7.10 3.8.9 3.9.4 pypy3.7-7.3.3
Install dependencies via Pipenv
pipenv install –dev
Run validation:
pipenv run tox
Contributing
Fork it
Create your feature branch (git checkout -b my-new-feature)
- Conform to the following standards:
PEP-8
Relative imports for same level or submodules
Verify your code passes unit tests (python setup.py test)
- Verify your code passes tests, linting, and PEP-8 on all supported python
versions (tox)
Commit your changes (git commit -am ‘Add some feature’)
Push to the branch (git push origin my-new-feature)
Create new Pull Request
CHANGELOG for LaunchKey Python SDK
4.0.1
Updated dependencies and fixed security issue for PyLint in dev dependencies
4.0.0
Removed Python 2 support
Removed Python 3.6 support
Updated JOSE Transport to include the SDK type, SDK version, and OS version in the User Agent
3.9.1
Bumped urllib3 due to a security vulnerability
3.9.0
Updated CLI to support separate encryption and signature keys
Altered JOSE transport to ensure only the designated signing key is used for signing requests
Added the add_encryption_private_key method to all factories and deprecated add_additional_private_key
Added KeyType Enum
Added additional key_type parameter to add_service_public_key
Added additional key_type parameter to add_directory_public_key
3.8.1
Fixed an issue where the SDK would improperly report which key was used when the encryption and signature keys differed
Fixed an issue where the SDK would fail to validate webhook signature verification if the signature key was not the one returned in the public-key endpoint
3.8.0
Added TOTP generate_user_totp and remove_user_totp to Directory Client and verify_totp to Service Client
3.7.0
Add device ID list to AuthorizationRequest object
Update CLI to display device ID list upon authorization request
3.6.0
Bug fix to ensure that requests do not follow redirects
Bug fix to ensure that public key is cached using kid header of JWT found within a response header
Added Policies: ConditionalGeofence, MethodAmount, Factors, Legacy
Added Requirement enum
enum34 only required on python versions < 3.4
Deprecated: TimeFence
Deprecated: ServiceSecurityPolicy
Deprecated: get_service_policy method on ServiceManagingBaseClient class
Deprecated: set_service_policy method on ServiceManagingBaseClient class
Deprecated: get_authorization_response method on ServiceClient class
Deprecated: handle_webhook method on ServiceClient class
Added: get_advanced_service_policy method on ServiceManagingBaseClient class
Added: set_advanced_service_policy method on ServiceManagingBaseClient class
Added: get_advanced_authorization_response method on ServiceClient class
Added: handle_advanced_webhook method on ServiceClient class
Added: AdvancedAuthorizationResponse class
Added: AuthorizationResponsePolicy class
3.5.0
Added get_all_directory_sdk_keys method to Organization client
Added integration testing suite
Added device failure sensor type
Added auth_methods and auth_policy attributes to the AuthorizationResponse object
Added handle_webhook as well as DeviceLinkCompletionResponse into the DirectoryClient
Updated the OrganizationClient update_directory() method and Directory object to include a webhook_url kwarg / attribute
Added Webhook example app
3.4.0
Added example CLI to codebase
Added ttl parameter to the DirectoryClient link_device method
Added cancel_authorization_request method to the ServiceClient
Fixed bug in ServiceClient which prevented handling of session end webhook request data when presented as a bytearray
3.3.1
Updated HTTP transport to no longer use sessions due to a bug that was causing BadStatusLine exceptions on long lived connections.
3.3.0
Added tooling around code quality and ensured that CI build would fail without meeting expectations.
Added dynamic auth TTL and title functionality
Added dynamic auth push message body and title functionality
Added auth busy signal error handling
Added new auth response format
Added auth denial context functionality
3.2.0
Remove PyCrypto and replace with pycryptodomex that is already required by PyJWKEST
Fixed geofence missing name bug
Added more expected error conditions to pydocs
Removed version lock for pytz requirement
Added 3rd party push enhancements
Added tox config for local testing in multiple versions of Python
Added missing response validation
Added full webhook validation
Cleaned up error handling and raising for webhooks
Switch RequestsTransport to use session in order to provide connection sharing between requests
3.1.1
Added patch method for transports
Support for many new endpoints added involving Organization, Directory, and Service management
Moved all entity objects into their own submodule
Added UUID validation for factory entity IDs
3.0.2
Improved 401 error handling
Bug fix for SessionEndRequest object
Service PINs bug fix
3.0.1
Typo and manifest fixes
Added Unauthorized status code error handler
Nose version lock for test requirements
3.0.0
Complete revamp for new V3 LaunchKey API
2.0.1
Make tests run under Python 3.5+
Make PEP-8 compliant (deprecated some non-PEP-8 compliant functions)
1.3.0
Python 3 compatibility.
Ability to send policies in auth request.
1.2.7
Update manifest for new CHANGES file
1.2.6
Fix for bad build regarding CHANGES.md
1.2.5
Remove references to LK Identifier as the API no longer returns it.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file launchkey-4.0.1.tar.gz
.
File metadata
- Download URL: launchkey-4.0.1.tar.gz
- Upload date:
- Size: 52.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.8.11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4443a0f56ef3d4139f1390c93e7770ed8b0f674256773b99056ee144a2f042d5 |
|
MD5 | 6cb4493fb5672eea8f3139c7cf82b67b |
|
BLAKE2b-256 | d8f6debf5ed3dac8d1a4cdf5ddbe89b86e0ba394c8722ce698f5c879899c6228 |
File details
Details for the file launchkey-4.0.1-py2.py3-none-any.whl
.
File metadata
- Download URL: launchkey-4.0.1-py2.py3-none-any.whl
- Upload date:
- Size: 57.1 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.8.11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0e6762891de9a5dea4d33fb07eaf92c8ea6a96f3a8b9457458a82cefeb7427ce |
|
MD5 | 70a55898382b9fd702e54ce0ea7df403 |
|
BLAKE2b-256 | dfd57011e69889d50f65181f000f52c81367381e5f84e7e71aae33856c452a3b |