Skip to main content

LaunchKey Python SDK

Project description

Python SDK for LaunchKey API

https://travis-ci.org/iovation/launchkey-python.svg?branch=master

For use in implementing LaunchKey.

Description

Use to more easily interact with iovation’s LaunchKey API.

A more in-depth look at this SDK can be found at the official docs.

Examples

CLI Example

Go to the CLI code

Flask Webhooks Example

Go to the Example App code

Installation

$ easy_install launchkey

or

$ pip install launchkey

Usage

Using LaunchKey Clients

The LaunchKey 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

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 LaunchKey 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 global 2.7.15 3.4.9 3.5.6 3.6.6 3.7.0 3.8-dev pypy3.5-6.0.0 pypy2.7-6.0.0

Install dependencies via Pipenv

pipenv install –dev

Run validation:

pipenv run tox

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Conform to the following standards:
    • PEP-8
    • Relative imports for same level or submodules
  4. Verify your code passes unit tests (python setup.py test)
  5. Verify your code passes tests, linting, and PEP-8 on all supported python
    versions (tox)
  6. Commit your changes (git commit -am ‘Add some feature’)
  7. Push to the branch (git push origin my-new-feature)
  8. Create new Pull Request

CHANGELOG for LaunchKey Python SDK

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for launchkey, version 3.8.0
Filename, size File type Python version Upload date Hashes
Filename, size launchkey-3.8.0-py2.py3-none-any.whl (60.3 kB) File type Wheel Python version py2.py3 Upload date Hashes View
Filename, size launchkey-3.8.0.tar.gz (47.0 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page