Note: The default ITS GitLab runner is a shared resource and is subject to slowdowns during heavy usage.
You can run your own GitLab runner that is dedicated just to your group if you need to avoid processing delays.

Commit f37e5fdc authored by John C Boufford's avatar John C Boufford
Browse files

added some documentation.

parent 148aeed8
...@@ -5,8 +5,10 @@ import logging ...@@ -5,8 +5,10 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Create Two Factor Authentication to the API Directory.
class ApiDirectory: class ApiDirectory:
# Constructor
def __init__(self, client_id, secret, scope, token_url, timeout=10): def __init__(self, client_id, secret, scope, token_url, timeout=10):
self.client_id = client_id self.client_id = client_id
self.secret = secret self.secret = secret
...@@ -14,6 +16,7 @@ class ApiDirectory: ...@@ -14,6 +16,7 @@ class ApiDirectory:
self.token_url = token_url self.token_url = token_url
self.timeout = timeout self.timeout = timeout
# Validates that the minimal values have been set to connect to the API Directory.
def _validate_initialization(self): def _validate_initialization(self):
if (self.client_id is None if (self.client_id is None
or self.secret is None or self.secret is None
...@@ -21,6 +24,7 @@ class ApiDirectory: ...@@ -21,6 +24,7 @@ class ApiDirectory:
or self.token_url is None): or self.token_url is None):
raise Exception("Invalid class configuration") raise Exception("Invalid class configuration")
# internal method to request an access bearer token.
def _find_token(self): def _find_token(self):
data = { data = {
'grant_type': 'client_credentials', 'grant_type': 'client_credentials',
...@@ -43,7 +47,7 @@ class ApiDirectory: ...@@ -43,7 +47,7 @@ class ApiDirectory:
return response.json() return response.json()
# gets access token from find_token # internal method to parse the access token.
def _find_access_token(self): def _find_access_token(self):
token = self._find_token() token = self._find_token()
if ('access_token' in token): if ('access_token' in token):
...@@ -63,6 +67,7 @@ class ApiDirectory: ...@@ -63,6 +67,7 @@ class ApiDirectory:
return access_token return access_token
# public method for building the https header needed for calling the API Directory.
def build_headers(self): def build_headers(self):
self._validate_initialization() self._validate_initialization()
bearer = self._find_access_token() bearer = self._find_access_token()
......
...@@ -2,12 +2,14 @@ import unittest ...@@ -2,12 +2,14 @@ import unittest
from apidirectory import ApiDirectory from apidirectory import ApiDirectory
# Test calling the API tirectory.
class ApiDirectoryTest(unittest.TestCase): class ApiDirectoryTest(unittest.TestCase):
client_id = "e06fb405-c58e-4334-b746-dd5969575bf2" client_id = "e06fb405-c58e-4334-b746-dd5969575bf2"
secret = "G5oT3vL1uK8xS7rO5sJ4nH7bK5iB6hN5jN5dI0nL8tO5bG4tT5" secret = "G5oT3vL1uK8xS7rO5sJ4nH7bK5iB6hN5jN5dI0nL8tO5bG4tT5"
scope = "iamgroups" scope = "iamgroups"
token_url = "https://apigw-tst.it.umich.edu/um/inst/oauth2/token" token_url = "https://apigw-tst.it.umich.edu/um/inst/oauth2/token"
# Test the construtor.
def test_constructor(self): def test_constructor(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
self.assertEqual(api.client_id, self.client_id) self.assertEqual(api.client_id, self.client_id)
...@@ -16,10 +18,10 @@ class ApiDirectoryTest(unittest.TestCase): ...@@ -16,10 +18,10 @@ class ApiDirectoryTest(unittest.TestCase):
self.assertEqual(api.token_url, self.token_url) self.assertEqual(api.token_url, self.token_url)
self.assertEqual(api.timeout, 10) self.assertEqual(api.timeout, 10)
# Test the header.
def test_build_header(self): def test_build_header(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
header = api.build_headers() header = api.build_headers()
map = header
self.assertEqual(map['x-ibm-client-id'], self.client_id) self.assertEqual(map['x-ibm-client-id'], self.client_id)
self.assertTrue('authorization' in map) self.assertTrue('authorization' in header)
...@@ -24,12 +24,9 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -24,12 +24,9 @@ class IamGroupCRUDTests(unittest.TestCase):
# The url_endpoint is obtain from the API directory # The url_endpoint is obtain from the API directory
# The api.build_headers builds the header needed for two factor oauth. # The api.build_headers builds the header needed for two factor oauth.
def test_1_create(self): def test_1_create(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
url_endpoint = 'create' url_endpoint = 'create'
url = IamGroupCRUDTests.url_base + '/' + url_endpoint url = IamGroupCRUDTests.url_base + '/' + url_endpoint
data = {'name': 'iamGroupTestJB'} data = {'name': 'iamGroupTestJB'}
response = requests.post( response = requests.post(
...@@ -43,14 +40,14 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -43,14 +40,14 @@ class IamGroupCRUDTests(unittest.TestCase):
print('JSON: {}'.format(response.json())) print('JSON: {}'.format(response.json()))
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
# The Read operation take a dn on the url. Because a dn contains spaces, commas and equals it # The Read operation takes a dn on the url. Because a dn contains spaces, commas and equals it
# needs to url encode. Note the test at the bottom of the unit test. # needs to url encode. Note the test at the bottom of the unit test.
def test_2_read(self): def test_2_read(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
dn = "cn=iamGroupTestJB,ou=user groups,ou=groups,dc=umich,dc=edu" dn = "cn=iamGroupTestJB,ou=user groups,ou=groups,dc=umich,dc=edu"
encoded_dn = urllib.parse.quote(dn) encoded = urllib.parse.quote(dn)
url_endpoint = 'profile/dn' url_endpoint = 'profile/dn'
url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded_dn url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded
response = requests.get( response = requests.get(
url=url, url=url,
...@@ -62,7 +59,8 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -62,7 +59,8 @@ class IamGroupCRUDTests(unittest.TestCase):
print('JSON: {}'.format(response.json())) print('JSON: {}'.format(response.json()))
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
# note that the returned json is a group object which is a list. # note that the returned json is a dictionary object with a key of group.
# the value is a list of groups and each group is a dictionary.
map = response.json() map = response.json()
list = map['group'] list = map['group']
profile = list[0] profile = list[0]
...@@ -71,7 +69,6 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -71,7 +69,6 @@ class IamGroupCRUDTests(unittest.TestCase):
# update. There are many update operations. I am showing how to modifiy a moderator. # update. There are many update operations. I am showing how to modifiy a moderator.
def test_3_update(self): def test_3_update(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
url_endpoint = 'update/moderator' url_endpoint = 'update/moderator'
url = IamGroupCRUDTests.url_base + '/' + url_endpoint url = IamGroupCRUDTests.url_base + '/' + url_endpoint
data = {'dn': 'cn=iamGroupTestJB,ou=user groups,ou=groups,dc=umich,dc=edu', data = {'dn': 'cn=iamGroupTestJB,ou=user groups,ou=groups,dc=umich,dc=edu',
...@@ -93,15 +90,16 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -93,15 +90,16 @@ class IamGroupCRUDTests(unittest.TestCase):
def test_4_delete(self): def test_4_delete(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
dn = "cn=iamGroupTestJB,ou=user groups,ou=groups,dc=umich,dc=edu" dn = "cn=iamGroupTestJB,ou=user groups,ou=groups,dc=umich,dc=edu"
encoded_dn = urllib.parse.quote(dn) encoded = urllib.parse.quote(dn)
url_endpoint = 'delete' url_endpoint = 'delete'
url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded_dn url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded
response = requests.get( response = requests.get(
url=url, url=url,
headers=api.build_headers(), headers=api.build_headers(),
timeout=10 timeout=10
) )
print('Response: {}'.format(response)) print('Response: {}'.format(response))
print('JSON: {}'.format(response.json())) print('JSON: {}'.format(response.json()))
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
...@@ -120,15 +118,16 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -120,15 +118,16 @@ class IamGroupCRUDTests(unittest.TestCase):
def test_isValid(self): def test_isValid(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
name = "iamGroupTestJB" name = "iamGroupTestJB"
encoded_name = urllib.parse.quote(name) encoded = urllib.parse.quote(name)
url_endpoint = 'mygroup/isValidName' url_endpoint = 'mygroup/isValidName'
url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded_name url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded
response = requests.get( response = requests.get(
url=url, url=url,
headers=api.build_headers(), headers=api.build_headers(),
timeout=10 timeout=10
) )
print('Response: {}'.format(response)) print('Response: {}'.format(response))
print('JSON: {}'.format(response.json())) print('JSON: {}'.format(response.json()))
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
...@@ -140,15 +139,16 @@ class IamGroupCRUDTests(unittest.TestCase): ...@@ -140,15 +139,16 @@ class IamGroupCRUDTests(unittest.TestCase):
def test_isValid_failed(self): def test_isValid_failed(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
name = "jbouffor" name = "jbouffor"
encoded_name = urllib.parse.quote(name) encoded = urllib.parse.quote(name)
url_endpoint = 'mygroup/isValidName' url_endpoint = 'mygroup/isValidName'
url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded_name url = IamGroupCRUDTests.url_base + '/' + url_endpoint + "/" + encoded
response = requests.get( response = requests.get(
url=url, url=url,
headers=api.build_headers(), headers=api.build_headers(),
timeout=10 timeout=10
) )
print('Response: {}'.format(response)) print('Response: {}'.format(response))
print('JSON: {}'.format(response.json())) print('JSON: {}'.format(response.json()))
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
......
...@@ -90,12 +90,13 @@ class IamGroupSearchTests(unittest.TestCase): ...@@ -90,12 +90,13 @@ class IamGroupSearchTests(unittest.TestCase):
headers=api.build_headers(), headers=api.build_headers(),
timeout=10 timeout=10
) )
print(api.build_headers())
print('Response: {}'.format(response)) print('Response: {}'.format(response))
print('JSON: {}'.format(response.json())) print('JSON: {}'.format(response.json()))
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
# find a person using a uniqname. returns the persons dn in the json.
# often it is used in a type ahead feature.
def test_find_person_by_uniqname(self): def test_find_person_by_uniqname(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
url_endpoint = 'find/person' url_endpoint = 'find/person'
...@@ -115,11 +116,12 @@ class IamGroupSearchTests(unittest.TestCase): ...@@ -115,11 +116,12 @@ class IamGroupSearchTests(unittest.TestCase):
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
# Used to find if a name is a group dn or a person dn or places where it needs to be a person or group.
def test_find_group_by_name_or_person(self): def test_find_group_by_name_or_person(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
url_endpoint = 'find/both' url_endpoint = 'find/both'
uniqname = "post-its-notes" uniqname = "post-its-notes"
# Since uniqname are alpha numeric without spaces this is not really needed. # Since group names can contain spaces it should be encoded.
encoded = urllib.parse.quote(uniqname) encoded = urllib.parse.quote(uniqname)
url = IamGroupSearchTests.url_base + '/' + url_endpoint + '/' + encoded url = IamGroupSearchTests.url_base + '/' + url_endpoint + '/' + encoded
...@@ -134,9 +136,10 @@ class IamGroupSearchTests(unittest.TestCase): ...@@ -134,9 +136,10 @@ class IamGroupSearchTests(unittest.TestCase):
self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(response.status_code, requests.codes.ok)
# Finds a group by name. Often used in a type ahead feature.
def test_find_group_by_name(self): def test_find_group_by_name(self):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
url_endpoint = 'find/typeahead' url_endpoint = 'find/group'
uniqname = "post-its-notes" uniqname = "post-its-notes"
# Since uniqname are alpha numeric without spaces this is not really needed. # Since uniqname are alpha numeric without spaces this is not really needed.
encoded = urllib.parse.quote(uniqname) encoded = urllib.parse.quote(uniqname)
......
...@@ -90,6 +90,7 @@ class IamGroupUpdateTests(unittest.TestCase): ...@@ -90,6 +90,7 @@ class IamGroupUpdateTests(unittest.TestCase):
# Adds an owner to the existing group. # Adds an owner to the existing group.
# replace ErrorsTo attribute # replace ErrorsTo attribute
# Adds a Request To attribute # Adds a Request To attribute
# This is how the api was designed. First lookup the group. Make your modification. Then submit the changes.
def update_group_management_attributes(self): def update_group_management_attributes(self):
# lookup the group. # lookup the group.
...@@ -132,6 +133,7 @@ class IamGroupUpdateTests(unittest.TestCase): ...@@ -132,6 +133,7 @@ class IamGroupUpdateTests(unittest.TestCase):
self.apply_update(data, 'update/privacySetting') self.apply_update(data, 'update/privacySetting')
# Sample update method to reduce the repetitiveness in the other examples.
def apply_update(self, data, url_endpoint): def apply_update(self, data, url_endpoint):
print("updating " + url_endpoint) print("updating " + url_endpoint)
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
...@@ -151,6 +153,7 @@ class IamGroupUpdateTests(unittest.TestCase): ...@@ -151,6 +153,7 @@ class IamGroupUpdateTests(unittest.TestCase):
map = response.json() map = response.json()
return map return map
# Sample lookup based on dn to reduce repetitiveness of the other examples.
def lookup(self, dn): def lookup(self, dn):
api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url) api = ApiDirectory(self.client_id, self.secret, self.scope, self.token_url)
encoded = urllib.parse.quote(dn) encoded = urllib.parse.quote(dn)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment