Skip to content

Commit

Permalink
Merge pull request #99 from iovation/3.7-DEV
Browse files Browse the repository at this point in the history
3.7 dev to master
  • Loading branch information
Brad Porter authored Jan 8, 2020
2 parents aa2caed + 7f0414d commit c08f61c
Showing 12 changed files with 105 additions and 14 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG for LaunchKey Python SDK
==================================

3.7.0
-----

* Add device ID list to `AuthorizationRequest` object
* Update CLI to display device ID list upon authorization request

3.6.0
-----

3 changes: 2 additions & 1 deletion examples/cli/cli.py
Original file line number Diff line number Diff line change
@@ -133,7 +133,8 @@ def authorize(ctx, service_id, username, context, title, ttl, push_title,
"Authorization request successful",
{
"Auth Request": auth.auth_request,
"Push Package": auth.push_package
"Push Package": auth.push_package,
"Device IDs": auth.device_ids
},
color=SUCCESS_COLOR
)
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ Feature: Service Client Authorization Request: Can Send Request

Background:
Given I created a Directory
And I have added an SDK Key to the Directory
And I created a Directory Service

Scenario: Making a request with a valid User an no linked Devices raises EntityNotFound
@@ -22,3 +23,9 @@ Feature: Service Client Authorization Request: Can Send Request
Scenario: Making a request including context with an invalid User Throws EntityNotFound
When I attempt to make an Authorization request with the context value "Hello iovation!"
Then a EntityNotFound error occurs

@device_testing
Scenario: Making a request with a valid user device parses the device IDs in the response
Given I have a linked Device
When I make an Authorization request
Then the Authorization Request response Device IDs matches the current Devices list
16 changes: 12 additions & 4 deletions features/steps/managers/directory_service_auths.py
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ class DirectoryServiceAuthsManager(BaseManager):
def __init__(self, organization_factory):
self.current_auth_response = None
self.previous_auth_response = None
self.current_auth_request = None
self.current_auth_request_id = None
self.previous_auth_request_id = None
super(DirectoryServiceAuthsManager, self, ).__init__(
@@ -43,7 +44,7 @@ def create_auth_request(self, service_id, user, context=None, policy=None,
push_body=None, denial_reasons=None):
client = self._get_service_client(service_id)
try:
self.current_auth_request_id = client.authorization_request(
current_auth_request = client.authorization_request(
user,
context=context,
policy=policy,
@@ -52,10 +53,14 @@ def create_auth_request(self, service_id, user, context=None, policy=None,
push_title=push_title,
push_body=push_body,
denial_reasons=denial_reasons
).auth_request
)

self.current_auth_request = current_auth_request
self.current_auth_request_id = current_auth_request.auth_request

except EntityNotFound:
sleep(2)
self.current_auth_request_id = client.authorization_request(
current_auth_request = client.authorization_request(
user,
context=context,
policy=policy,
@@ -64,7 +69,10 @@ def create_auth_request(self, service_id, user, context=None, policy=None,
push_title=push_title,
push_body=push_body,
denial_reasons=denial_reasons
).auth_request
)

self.current_auth_request = current_auth_request
self.current_auth_request_id = current_auth_request.auth_request

def get_auth_response(self, service_id, auth_request):
client = self._get_service_client(service_id)
29 changes: 28 additions & 1 deletion features/steps/service_auth_steps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from behave import given, when, then

from hamcrest import assert_that, equal_to

from launchkey.entities.service import GeoFence, AuthMethod, AuthMethodType, \
Requirement, AuthResponseReason

@@ -263,4 +265,29 @@ def parse_input(value):
"is not supported on all devices, so this may fail." %
(expected_method, methods[i], expected_method.method))
else:
raise Exception("Expected %s but got %s" % (expected_method, methods[i]))
raise Exception("Expected %s but got %s" % (expected_method,
methods[i]))


@then("the Authorization Request response Device IDs matches the current "
"Devices list")
def verify_device_ids_match_device_list(context):
request = context.directory_service_auths_manager.current_auth_request

if not request:
raise Exception("Expected an auth request to be present but got none.")

request_device_ids = request.device_ids

if not request_device_ids:
raise Exception("Expected device IDs to be present in auth request "
"but got %s instead." % request_device_ids)

current_directory = context.entity_manager.get_current_directory()
current_user_identifier = context.directory_device_manager. \
current_user_identifier
current_user_devices = context.directory_device_manager \
.retrieve_user_devices(current_user_identifier, current_directory.id)
current_user_device_ids = [d.id for d in current_user_devices]

assert_that(request_device_ids, equal_to(current_user_device_ids))
2 changes: 1 addition & 1 deletion launchkey/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""LaunchKey Service SDK module"""
SDK_VERSION = '3.6.0'
SDK_VERSION = '3.7.0'
LAUNCHKEY_PRODUCTION = "https://api.launchkey.com"
VALID_JWT_ISSUER_LIST = ["svc", "dir", "org"]
JOSE_SUPPORTED_JWE_ALGS = ['RSA-OAEP']
3 changes: 2 additions & 1 deletion launchkey/clients/service.py
Original file line number Diff line number Diff line change
@@ -171,7 +171,8 @@ def authorization_request(self, user, context=None, policy=None,
self._subject, **kwargs)
data = self._validate_response(response, AuthorizeValidator)
return AuthorizationRequest(data.get('auth_request'),
data.get('push_package'))
data.get('push_package'),
data.get('device_ids'))

@api_call
def get_advanced_authorization_response(self, authorization_request_id):
11 changes: 7 additions & 4 deletions launchkey/entities/service/__init__.py
Original file line number Diff line number Diff line change
@@ -479,21 +479,24 @@ def __repr__(self):

class AuthorizationRequest(object):
"""
Authorization Response object containing decrypted auth response
Authorization Request object containing decrypted auth response
and other related information
"""

def __init__(self, auth_request, push_package):
def __init__(self, auth_request, push_package, device_ids=None):
self.auth_request = auth_request
self.push_package = push_package
self.device_ids = device_ids

def __repr__(self):
return "AuthorizationRequest <" \
"auth_request=\"{auth_request}\", " \
"push_package=\"{push_package}\">".\
"push_package=\"{push_package}\", " \
"device_ids=\"{device_ids}\">".\
format(
auth_request=self.auth_request,
push_package=self.push_package
push_package=self.push_package,
device_ids=self.device_ids
)


1 change: 1 addition & 0 deletions launchkey/entities/validation.py
Original file line number Diff line number Diff line change
@@ -270,6 +270,7 @@ class AuthorizeValidator(Schema):
"""Authorize entity validator"""
auth_request = validators.String(not_empty=True)
push_package = validators.String(if_missing=None, not_empty=True)
device_ids = ForEach(validators.String(), if_missing=None)
allow_extra_fields = True


18 changes: 17 additions & 1 deletion tests/test_entities_service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import unittest

import json
from uuid import uuid4

from mock import MagicMock, patch
from ddt import data, unpack, ddt
from formencode import Invalid
@@ -1583,7 +1585,21 @@ def test_repr(self):
self.assertEqual(
str(auth_request),
'AuthorizationRequest <auth_request="auth", '
'push_package="package">'
'push_package="package", '
'device_ids="None">'
)

faux_device_id = str(uuid4())
auth_request_with_device_ids = AuthorizationRequest(
auth_request='auth',
push_package='package',
device_ids=[faux_device_id])

self.assertEqual(
str(auth_request_with_device_ids),
'AuthorizationRequest <auth_request="auth", '
'push_package="package", '
'device_ids="[\'%s\']">' % faux_device_id
)


12 changes: 12 additions & 0 deletions tests/test_service_client.py
Original file line number Diff line number Diff line change
@@ -83,6 +83,18 @@ def test_authorization_request_response_has_push_package(self):
self._response.data = {"auth_request": "auth", "push_package": "expected package"}
self.assertEqual('expected package', self._service_client.authorization_request(ANY).push_package)

def test_authorization_request_response_has_device_ids(self):
expected_device_ids = ["expected_device_id"]
self._response.data = {
"auth_request": "auth",
"push_package": "expected package",
"device_ids": expected_device_ids
}

self.assertEqual(
expected_device_ids,
self._service_client.authorization_request(ANY).device_ids)

def test_authorization_request_invalid_policy_input(self):
self._response.data = {"auth_request": ANY}
with self.assertRaises(InvalidParameters):
11 changes: 10 additions & 1 deletion tests/test_validation.py
Original file line number Diff line number Diff line change
@@ -15,9 +15,11 @@
class TestAuthorizeValidator(TestCase):

def setUp(self):
self._expected_device_ids = ['expected_device_id']
self._data = {
'auth_request': 'Expected Auth Request',
'push_package': 'Expected Push Package'
'push_package': 'Expected Push Package',
'device_ids': self._expected_device_ids
}
self._validator = AuthorizeValidator()

@@ -62,6 +64,13 @@ def test_push_package_returns_unchanged_string(self):
actual = self._validator.to_python(self._data)
self.assertIn('push_package', actual)
self.assertEqual(actual['push_package'], expected)
self.assertEqual(actual["device_ids"], self._expected_device_ids)

def test_device_ids_may_be_missing(self):
del self._data["device_ids"]
actual = self._validator.to_python(self._data)
self.assertIn('device_ids', actual)
self.assertIsNone(actual['device_ids'])


@ddt

0 comments on commit c08f61c

Please sign in to comment.