Skip to content

Commit

Permalink
refactored little bit
Browse files Browse the repository at this point in the history
  • Loading branch information
akhilputhiry committed Apr 26, 2019
1 parent 8b38206 commit ed885f1
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 68 deletions.
4 changes: 4 additions & 0 deletions .codecov.yml
@@ -0,0 +1,4 @@
coverage:
status:
project: off
patch: off
10 changes: 10 additions & 0 deletions keycloak/constants.py
@@ -0,0 +1,10 @@
#! -*- coding: utf-8 -*-

""" Constants used in this package """


# pylint: disable=too-few-public-methods
class TokenType:
""" Different types of token """
BASIC = 'Basic'
BEARER = 'Bearer'
38 changes: 12 additions & 26 deletions keycloak/mixins/authorization.py
Expand Up @@ -2,11 +2,12 @@

""" This mixin takes care of all functionalities associated with authorization """

import base64

import requests
from cached_property import cached_property

from ..utils import b64encode, auth_header
from ..constants import TokenType


class AuthorizationMixin:
"""
Expand All @@ -15,7 +16,7 @@ class AuthorizationMixin:
"""

@cached_property
def basic_authorization_header(self):
def basic_auth_header(self):
"""
Method to prepare the authorization header
Expand All @@ -26,16 +27,13 @@ def basic_authorization_header(self):
# construct authorization string
authorization = '{}:{}'.format(self.config.client_id, self.config.client_secret)

# convert to bytes
authorization = bytes(authorization, 'utf-8')

# perform base64 encoding
authorization = base64.b64encode(authorization)
# base64 encode
authorization = b64encode(authorization)

# convert to str
authorization = authorization.decode('utf-8')
# prepare header
headers = auth_header(authorization, TokenType.BASIC)

return 'Basic {}'.format(authorization)
return headers

# pylint: disable=dangerous-default-value
def retrieve_ticket(self, resources=[]):
Expand All @@ -48,18 +46,13 @@ def retrieve_ticket(self, resources=[]):
Raises:
HTTPError
"""
# prepare headers
headers = {
'Authorization': 'Bearer %s' % self.pat['access_token']
}

# retrieve permission ticket
try:
self.log.info('Retrieving permission ticket from keycloak server')
response = requests.post(
self.config.permission_endpoint,
json=resources,
headers=headers
headers=self.pat_auth_header
)
response.raise_for_status()
except requests.exceptions.HTTPError as ex:
Expand Down Expand Up @@ -94,9 +87,7 @@ def retrieve_rpt(self, aat, ticket=None):
payload.update({'audience': self.config.client_id})

# prepare headers
headers = {
'Authorization': 'Bearer {}'.format(aat)
}
headers = auth_header(aat, TokenType.BEARER)

# fetch RPT token
try:
Expand Down Expand Up @@ -129,18 +120,13 @@ def validate_rpt(self, rpt):
'token': rpt
}

# prepare headers
headers = {
'Authorization': self.basic_authorization_header
}

# introspect token
try:
self.log.info('Introspecting RPT token')
response = requests.post(
self.config.introspection_endpoint,
data=payload,
headers=headers
headers=self.basic_auth_header
)
response.raise_for_status()
except requests.exceptions.HTTPError as ex:
Expand Down
19 changes: 7 additions & 12 deletions keycloak/mixins/permission.py
Expand Up @@ -4,6 +4,9 @@

import requests

from ..utils import auth_header
from ..constants import TokenType


class PermissionMixin:
"""
Expand All @@ -27,9 +30,7 @@ def list_permission(self, aat):
HTTPError
"""
# prepare headers
headers = {
'Authorization': 'Bearer %s' % aat
}
headers = auth_header(aat, TokenType.BEARER)

# fetch list of policies
try:
Expand All @@ -55,9 +56,7 @@ def create_permission(self, aat, resource_id, permission={}):
endpoint = self.config.policy_endpoint + '/' + resource_id

# prepare headers
headers = {
'Authorization': 'Bearer %s' % aat
}
headers = auth_header(aat, TokenType.BEARER)

# prepare payload
permission.update({
Expand Down Expand Up @@ -89,9 +88,7 @@ def update_permission(self, aat, permission_id, permission={}):
endpoint = self.config.policy_endpoint + '/' + permission_id

# prepare headers
headers = {
'Authorization': 'Bearer %s' % aat
}
headers = auth_header(aat, TokenType.BEARER)

# update permission
try:
Expand All @@ -114,9 +111,7 @@ def delete_permission(self, aat, permission_id):
endpoint = self.config.policy_endpoint + '/' + permission_id

# prepare headers
headers = {
'Authorization': 'Bearer %s' % aat
}
headers = auth_header(aat, TokenType.BEARER)

# delete permission
try:
Expand Down
39 changes: 21 additions & 18 deletions keycloak/mixins/resource.py
Expand Up @@ -4,7 +4,10 @@

import json
import requests
from cached_property import cached_property, cached_property_with_ttl
from cached_property import cached_property_with_ttl

from ..utils import auth_header
from ..constants import TokenType


class ResourceMixin:
Expand All @@ -27,23 +30,20 @@ def pat(self):
'grant_type': 'client_credentials'
}

# prepare headers
headers = {
'Authorization': self.basic_authorization_header
}

# retrieve PAT
response = requests.post(self.config.token_endpoint, data=payload, headers=headers)
response = requests.post(
self.config.token_endpoint,
data=payload,
headers=self.basic_auth_header
)
response.raise_for_status()

return response.json()

@property
def headers(self):
def pat_auth_header(self):
""" Common headers used within the class """
return {
'Authorization': 'Bearer {}'.format(self.pat['access_token'])
}
return auth_header(self.pat['access_token'], TokenType.BEARER)

def list_resource(self):
"""
Expand All @@ -55,7 +55,10 @@ def list_resource(self):

# list resource
self.log.info('Fetching list of resources')
response = requests.get(self.config.resource_registration_endpoint, headers=self.headers)
response = requests.get(
self.config.resource_registration_endpoint,
headers=self.pat_auth_header
)
response.raise_for_status()

return response.json()
Expand All @@ -78,7 +81,7 @@ def create_resource(self, resource={}):
response = requests.post(
self.config.resource_registration_endpoint,
json=resource,
headers=self.headers
headers=self.pat_auth_header
)
response.raise_for_status()
return response.json()
Expand All @@ -95,7 +98,7 @@ def read_resource(self, resource_id):
endpoint = self.config.resource_registration_endpoint + resource_id

# create resource
response = requests.get(endpoint, headers=self.headers)
response = requests.get(endpoint, headers=self.pat_auth_header)
response.raise_for_status()

return response.json()
Expand All @@ -113,7 +116,7 @@ def update_resource(self, resource_id, resource):
endpoint = self.config.resource_registration_endpoint + resource_id

# update resource
response = requests.put(endpoint, json=resource, headers=self.headers)
response = requests.put(endpoint, json=resource, headers=self.pat_auth_header)
response.raise_for_status()

return response.json()
Expand All @@ -130,7 +133,7 @@ def delete_resource(self, resource_id):
endpoint = self.config.resource_registration_endpoint + resource_id

# create resource
response = requests.delete(endpoint, headers=self.headers)
response = requests.delete(endpoint, headers=self.pat_auth_header)
response.raise_for_status()

return response.json()
Expand Down Expand Up @@ -192,8 +195,8 @@ def register_resources(self, resources_file):
for record in records:

# parse resource and permissions
resource = record.get('resource')
permissions = record.get('permissions')
resource = record.get('resource', [])
permissions = record.get('permissions', [])

# create resource
self.log.info('Processing resource %s', resource['name'])
Expand Down
37 changes: 37 additions & 0 deletions keycloak/utils.py
Expand Up @@ -2,6 +2,43 @@

""" utility functions """

import base64


def b64encode(string):
"""
Method to encode string using base64
Args:
string (str): data to be encoded
Returns:
str
"""
# convert to bytes
string = bytes(string, 'utf-8')

# perform base64 encoding
string = base64.b64encode(string)

# convert to str
return string.decode('utf-8')


def auth_header(token_val, token_type):
"""
Method to generate authorization header to be used with the requests
Args:
token_val (str): authentication token
token_type (str): token type eg: Basic, Bearer etc
Returns:
dict
"""
return {
'Authorization': '{} {}'.format(token_type, token_val)
}

def fix_padding(encoded_string):
"""
Expand Down
11 changes: 5 additions & 6 deletions tests/mixins/authorization.py
Expand Up @@ -2,11 +2,11 @@
from unittest.mock import MagicMock, PropertyMock, patch


def test_basic_authorization_header(keycloak_client):
""" Test case for basic_authorization_header """
authorization = keycloak_client.basic_authorization_header
def test_basic_auth_header(keycloak_client):
""" Test case for basic_auth_header """
authorization = keycloak_client.basic_auth_header
assert authorization is not None
assert authorization == 'Basic Zmxhc2stYXBwOjFmNDlmMDU3LWJiZjktNDM4OS1hOTBmLTNjNTk3MmY1NTY0YQ=='
assert authorization == {'Authorization': 'Basic Zmxhc2stYXBwOjFmNDlmMDU3LWJiZjktNDM4OS1hOTBmLTNjNTk3MmY1NTY0YQ=='}


@patch('keycloak.mixins.resource.ResourceMixin.pat', new_callable=PropertyMock)
Expand Down Expand Up @@ -47,8 +47,7 @@ def test_validate_rpt(mock_post, keycloak_client):
""" Test case for validate_rpt """
mock_post.return_value.json = MagicMock()
payload = {'token_type_hint': 'requesting_party_token', 'token': 'token123456789'}
headers = {'Authorization': keycloak_client.basic_authorization_header}
introspection_endpoint = 'https://keycloak.dev.lti-mosaic.com/auth/realms/akhil-poc/protocol/openid-connect/token/introspect'
keycloak_client.validate_rpt('token123456789')
mock_post.assert_called_once_with(introspection_endpoint, data=payload, headers=headers)
mock_post.assert_called_once_with(introspection_endpoint, data=payload, headers=keycloak_client.basic_auth_header)
mock_post.return_value.json.assert_called_once()
12 changes: 6 additions & 6 deletions tests/mixins/resource.py
Expand Up @@ -18,13 +18,13 @@ def test_headers(mock_pat, keycloak_client):
""" Test case for headers """
mock_pat.return_value = {'access_token': 'token123456789'}
headers = {'Authorization': 'Bearer token123456789'}
result = keycloak_client.headers
result = keycloak_client.pat_auth_header
assert result == headers
mock_pat.assert_called_once()


@patch('keycloak.mixins.resource.requests.get')
@patch('keycloak.mixins.resource.ResourceMixin.headers', new_callable=PropertyMock)
@patch('keycloak.mixins.resource.ResourceMixin.pat_auth_header', new_callable=PropertyMock)
def test_list_resource(mock_headers, mock_get, keycloak_client):
""" Test case for list_resource """
headers = {'Authorization': 'token123456789'}
Expand All @@ -36,7 +36,7 @@ def test_list_resource(mock_headers, mock_get, keycloak_client):


@patch('keycloak.mixins.resource.requests.post')
@patch('keycloak.mixins.resource.ResourceMixin.headers', new_callable=PropertyMock)
@patch('keycloak.mixins.resource.ResourceMixin.pat_auth_header', new_callable=PropertyMock)
def test_create_resource(mock_headers, mock_post, keycloak_client):
""" Test case for list_resource """
resource = {}
Expand All @@ -49,7 +49,7 @@ def test_create_resource(mock_headers, mock_post, keycloak_client):


@patch('keycloak.mixins.resource.requests.get')
@patch('keycloak.mixins.resource.ResourceMixin.headers', new_callable=PropertyMock)
@patch('keycloak.mixins.resource.ResourceMixin.pat_auth_header', new_callable=PropertyMock)
def test_read_resource(mock_headers, mock_get, keycloak_client):
""" Test case for list_resource """
resource_id = '123456789'
Expand All @@ -63,7 +63,7 @@ def test_read_resource(mock_headers, mock_get, keycloak_client):


@patch('keycloak.mixins.resource.requests.put')
@patch('keycloak.mixins.resource.ResourceMixin.headers', new_callable=PropertyMock)
@patch('keycloak.mixins.resource.ResourceMixin.pat_auth_header', new_callable=PropertyMock)
def test_update_resource(mock_headers, mock_put, keycloak_client):
""" Test case for list_resource """
resource_id = '123456789'
Expand All @@ -78,7 +78,7 @@ def test_update_resource(mock_headers, mock_put, keycloak_client):


@patch('keycloak.mixins.resource.requests.delete')
@patch('keycloak.mixins.resource.ResourceMixin.headers', new_callable=PropertyMock)
@patch('keycloak.mixins.resource.ResourceMixin.pat_auth_header', new_callable=PropertyMock)
def test_delete_resource(mock_headers, mock_delete, keycloak_client):
""" Test case for list_resource """
resource_id = '123456789'
Expand Down

0 comments on commit ed885f1

Please sign in to comment.