Skip to content

Commit

Permalink
Feature[PAM]: Revoke token functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
650elx authored Dec 16, 2021
1 parent 6beedc6 commit bd3d4ae
Show file tree
Hide file tree
Showing 18 changed files with 324 additions and 177 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/run_acceptance_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ jobs:
token: ${{ secrets.GH_TOKEN }}
- name: Install Python dependencies and run acceptance tests
run: |
cp sdk-specifications/features/access/authorization-failure-reporting.feature tests/acceptance/pam
cp sdk-specifications/features/access/grant-token.feature tests/acceptance/pam
cp sdk-specifications/features/access/revoke-token.feature tests/acceptance/pam
sudo pip3 install -r requirements-dev.txt
behave --junit tests/acceptance/pam
- name: Expose acceptance tests reports
Expand Down
17 changes: 13 additions & 4 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: python
version: 5.4.0
version: 5.5.0
schema: 1
scm: github.com/pubnub/python
sdks:
Expand All @@ -18,7 +18,7 @@ sdks:
distributions:
- distribution-type: library
distribution-repository: package
package-name: pubnub-5.1.3
package-name: pubnub-5.5.0
location: https://pypi.org/project/pubnub/
supported-platforms:
supported-operating-systems:
Expand Down Expand Up @@ -97,8 +97,8 @@ sdks:
-
distribution-type: library
distribution-repository: git release
package-name: pubnub-5.1.3
location: https://github.com/pubnub/python/releases/download/v5.1.3/pubnub-5.1.3.tar.gz
package-name: pubnub-5.5.0
location: https://github.com/pubnub/python/releases/download/v5.5.0/pubnub-5.5.0.tar.gz
supported-platforms:
supported-operating-systems:
Linux:
Expand Down Expand Up @@ -169,6 +169,14 @@ sdks:
license-url: https://github.com/aio-libs/aiohttp/blob/master/LICENSE.txt
is-required: Required
changelog:
- date: 2021-12-16
version: v5.5.0
changes:

- date: 2021-12-16
version: v5.4.0
changes:

- version: v5.4.0
date: 2021-10-07
changes:
Expand Down Expand Up @@ -479,6 +487,7 @@ features:
- ACCESS-GRANT-TOKEN
- ACCESS-PARSE-TOKEN
- ACCESS-SET-TOKEN
- ACCESS-REVOKE-TOKEN
channel-groups:
- CHANNEL-GROUPS-ADD-CHANNELS
- CHANNEL-GROUPS-REMOVE-CHANNELS
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v5.5.0
December 16 2021

## v5.4.0
December 16 2021

## [v5.4.0](https://github.com/pubnub/python/releases/tag/v5.4.0)

[Full Changelog](https://github.com/pubnub/python/compare/v5.3.1...v5.4.0)
Expand Down
30 changes: 0 additions & 30 deletions pubnub/endpoints/access/revoke.py

This file was deleted.

43 changes: 43 additions & 0 deletions pubnub/endpoints/access/revoke_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from pubnub.enums import PNOperationType, HttpMethod
from pubnub.endpoints.endpoint import Endpoint
from pubnub.models.consumer.v3.access_manager import PNRevokeTokenResult
from pubnub import utils


class RevokeToken(Endpoint):
REVOKE_TOKEN_PATH = "/v3/pam/%s/grant/%s"

def __init__(self, pubnub, token):
Endpoint.__init__(self, pubnub)
self.token = token

def validate_params(self):
self.validate_subscribe_key()
self.validate_secret_key()

def create_response(self, envelope):
return PNRevokeTokenResult(envelope)

def is_auth_required(self):
return False

def request_timeout(self):
return self.pubnub.config.non_subscribe_request_timeout

def connect_timeout(self):
return self.pubnub.config.connect_timeout

def http_method(self):
return HttpMethod.DELETE

def custom_params(self):
return {}

def build_path(self):
return RevokeToken.REVOKE_TOKEN_PATH % (self.pubnub.config.subscribe_key, utils.url_encode(self.token))

def operation_type(self):
return PNOperationType.PNAccessManagerRevokeToken

def name(self):
return "RevokeToken"
2 changes: 2 additions & 0 deletions pubnub/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ class PNOperationType(object):
PNFireOperation = 25
PNSignalOperation = 26

PNAccessManagerRevokeToken = 40
PNAccessManagerGrantToken = 41

PNAddMessageAction = 42
PNGetMessageActions = 43
PNDeleteMessageAction = 44
Expand Down
5 changes: 3 additions & 2 deletions pubnub/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ def endpoint_name_for_operation(operation_type):
PNOperationType.PNAccessManagerRevoke: 'pam',
PNOperationType.PNTimeOperation: 'pam',

PNOperationType.PNAccessManagerGrantToken: 'pamv3',
PNOperationType.PNAccessManagerRevokeToken: 'pamv3',

PNOperationType.PNSignalOperation: 'sig',

PNOperationType.PNSetUuidMetadataOperation: 'obj',
Expand All @@ -488,8 +491,6 @@ def endpoint_name_for_operation(operation_type):
PNOperationType.PNRemoveMembershipsOperation: 'obj',
PNOperationType.PNManageMembershipsOperation: 'obj',

PNOperationType.PNAccessManagerGrantToken: 'pamv3',

PNOperationType.PNAddMessageAction: 'msga',
PNOperationType.PNGetMessageActions: 'msga',
PNOperationType.PNDeleteMessageAction: 'msga',
Expand Down
8 changes: 8 additions & 0 deletions pubnub/models/consumer/v3/access_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ def __str__(self):

def get_token(self):
return self.token


class PNRevokeTokenResult:
def __init__(self, result):
self.status = result['status']

def __str__(self):
return "Revoke token success with status: %s" % self.status
8 changes: 4 additions & 4 deletions pubnub/pubnub_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from .endpoints.access.audit import Audit
from .endpoints.access.grant import Grant
from .endpoints.access.grant_token import GrantToken
from .endpoints.access.revoke import Revoke
from .endpoints.access.revoke_token import RevokeToken
from .endpoints.channel_groups.add_channel_to_channel_group import AddChannelToChannelGroup
from .endpoints.channel_groups.list_channels_in_channel_group import ListChannelsInChannelGroup
from .endpoints.channel_groups.remove_channel_from_channel_group import RemoveChannelFromChannelGroup
Expand Down Expand Up @@ -65,7 +65,7 @@

class PubNubCore:
"""A base class for PubNub Python API implementations"""
SDK_VERSION = "5.4.0"
SDK_VERSION = "5.5.0"
SDK_NAME = "PubNub-Python"

TIMESTAMP_DIVIDER = 1000
Expand Down Expand Up @@ -170,8 +170,8 @@ def grant(self):
def grant_token(self):
return GrantToken(self)

def revoke(self):
return Revoke(self)
def revoke_token(self, token):
return RevokeToken(self, token)

def audit(self):
return Audit(self)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='pubnub',
version='5.4.0',
version='5.5.0',
description='PubNub Real-time push service in the cloud',
author='PubNub',
author_email='support@pubnub.com',
Expand Down
61 changes: 51 additions & 10 deletions tests/acceptance/pam/steps/given_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pubnub.models.consumer.v3.channel import Channel
from pubnub.models.consumer.v3.group import Group
from pubnub.models.consumer.v3.uuid import UUID
from tests.helper import PAM_TOKEN_WITH_ALL_PERMS_GRANTED
from tests.helper import PAM_TOKEN_WITH_ALL_PERMS_GRANTED, PAM_TOKEN_EXPIRED, PAM_TOKEN_WITH_PUBLISH_ENABLED


@given("I have a keyset with access manager enabled")
Expand All @@ -22,6 +22,33 @@ def step_impl(context):
}


@given("I have a keyset with access manager enabled - without secret key")
def step_impl(context):
pubnub_instance = PubNub(pnconf_pam_acceptance_copy())
pubnub_instance.config.secret_key = None
context.peer_without_secret_key = pubnub_instance


@given("a valid token with permissions to publish with channel {channel}")
def step_impl(context, channel):
context.token = PAM_TOKEN_WITH_PUBLISH_ENABLED


@given("an expired token with permissions to publish with channel {channel}")
def step_impl(context, channel):
context.token = PAM_TOKEN_EXPIRED


@given("the token string {token}")
def step_impl(context, token):
context.token = token.strip("'")


@given("a token")
def step_impl(context):
context.token = PAM_TOKEN_WITH_PUBLISH_ENABLED


@given("the TTL {ttl}")
def step_impl(context, ttl):
context.TTL = ttl
Expand Down Expand Up @@ -209,17 +236,17 @@ def step_impl(context):

@given("I have a known token containing UUID pattern Permissions")
def step_impl(context):
context.token_to_parse = PAM_TOKEN_WITH_ALL_PERMS_GRANTED
context.token = PAM_TOKEN_WITH_ALL_PERMS_GRANTED


@given("I have a known token containing UUID resource permissions")
def step_impl(context):
context.token_to_parse = PAM_TOKEN_WITH_ALL_PERMS_GRANTED
context.token = PAM_TOKEN_WITH_ALL_PERMS_GRANTED


@given("I have a known token containing an authorized UUID")
def step_impl(context):
context.token_to_parse = PAM_TOKEN_WITH_ALL_PERMS_GRANTED
context.token = PAM_TOKEN_WITH_ALL_PERMS_GRANTED


@given("token resource permission READ")
Expand Down Expand Up @@ -254,29 +281,43 @@ def step_impl(context):

@given("the error status code is {status}")
def step_impl(context, status):
assert context.grant_call_error["status"] == int(status)
assert context.pam_call_error["status"] == int(status)


@given("the error message is {err_msg}")
def step_impl(context, err_msg):
assert context.grant_call_error["error"]["message"] == err_msg.strip("'")
assert context.pam_call_error["error"]["message"] == err_msg.strip("'")


@given("the error source is {err_source}")
def step_impl(context, err_source):
assert context.grant_call_error["error"]["source"] == err_source.strip("'")
assert context.pam_call_error["error"]["source"] == err_source.strip("'")


@given("the error detail message is {err_detail}")
def step_impl(context, err_detail):
assert context.grant_call_error["error"]["details"][0]["message"] == err_detail.strip("'")
err_detail = err_detail.strip("'")
if err_detail == "not empty":
assert context.pam_call_error["error"]["details"][0]["message"]
else:
assert context.pam_call_error["error"]["details"][0]["message"] == err_detail


@given("the error detail location is {err_detail_location}")
def step_impl(context, err_detail_location):
assert context.grant_call_error["error"]["details"][0]["location"] == err_detail_location.strip("'")
assert context.pam_call_error["error"]["details"][0]["location"] == err_detail_location.strip("'")


@given("the error detail location type is {err_detail_location_type}")
def step_impl(context, err_detail_location_type):
assert context.grant_call_error["error"]["details"][0]["locationType"] == err_detail_location_type.strip("'")
assert context.pam_call_error["error"]["details"][0]["locationType"] == err_detail_location_type.strip("'")


@given("the error service is {service_name}")
def step_impl(context, service_name):
assert context.pam_call_error["service"] == service_name.strip("'")


@given("the auth error message is {message}")
def step_impl(context, message):
assert context.pam_call_error["message"] == message.strip("'")
24 changes: 21 additions & 3 deletions tests/acceptance/pam/steps/then_steps.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import json
from behave import then
from pubnub.exceptions import PubNubException


@then("the token contains the TTL 60")
Expand Down Expand Up @@ -58,10 +60,26 @@ def step_impl(context, channel_group):

@then("I see the error message {error} and details {error_details}")
def step_impl(context, error, error_details):
assert context.grant_call_error["error"]["message"] == error.strip("'")
assert context.grant_call_error["error"]["details"][0]["message"] == error_details.strip("'")
assert context.pam_call_error["error"]["message"] == error.strip("'")
assert context.pam_call_error["error"]["details"][0]["message"] == error_details.strip("'")


@then("an error is returned")
def step_impl(context):
assert context.grant_call_error
assert context.pam_call_error


@then("I get confirmation that token has been revoked")
def step_impl(context):
assert context.revoke_result.result.status == 200


@then("an auth error is returned")
def step_impl(context):
assert isinstance(context.pam_call_result, PubNubException)
context.pam_call_error = json.loads(context.pam_call_result._errormsg)


@then("the result is successful")
def step_impl(context):
assert context.publish_result.result.timetoken
Loading

0 comments on commit bd3d4ae

Please sign in to comment.