Skip to content

Commit

Permalink
Add samples for SAS token authentication; add note to readme accordin…
Browse files Browse the repository at this point in the history
…gly (#13267)

* Add samples for SAS token authentication; add note to readme accordingly.
  • Loading branch information
KieranBrantnerMagee authored Aug 22, 2020
1 parent 37ff4f1 commit d334964
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 2 deletions.
5 changes: 3 additions & 2 deletions sdk/eventhub/azure-eventhub/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,18 @@ Both [sync version](https://github.com/Azure/azure-sdk-for-python/tree/master/sd
- [recv_for_period.py](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/sync_samples/recv_for_period.py) ([async version](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/async_samples/recv_for_period_async.py)) - Examples to receive events for a period of time:
- Receive events for a period of time


- [client_identity_authentication.py](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/sync_samples/client_identity_authentication.py) ([async version](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/async_samples/client_identity_authentication_async.py)) - Examples for authentication by Azure Active Directory:
- Authenticating and creating the client utilizing the `azure.identity` library


- [proxy.py](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/sync_samples/proxy.py) ([async version](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/async_samples/proxy_async.py)) - Examples to send and receive events behind a proxy:
- Send and receive events behind a proxy

- [iot_hub_connection_string_receive_async.py](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/async_samples/iot_hub_connection_string_receive_async.py) - Examples to receive events from an IoT Hub:
- Convert an IoT Hub connection string to the built-in Event Hub endpoint and receive events from it

- [authenticate_with_sas_token.py]<!--(https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventhub/azure-eventhub/samples/sync_samples/authenticate_with_sas_token.py)-->
- Utilize a SAS token to authenticate when creating an Event Hub client.

## Prerequisites
- Python 2.7, 3.5 or later.
- **Microsoft Azure Subscription:** To use Azure services, including Azure Event Hubs, you'll need a subscription.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

"""
Example to demonstrate utilizing SAS (Shared Access Signature) tokens to authenticate with ServiceBus
"""

# pylint: disable=C0111

import asyncio
import os
import time
import hmac
import hashlib
import base64
try:
from urllib.parse import quote as url_parse_quote
except ImportError:
from urllib import pathname2url as url_parse_quote

from azure.core.credentials import AccessToken
from azure.eventhub.aio import EventHubConsumerClient


def generate_sas_token(uri, sas_name, sas_value, token_ttl):
"""Performs the signing and encoding needed to generate a sas token from a sas key."""
sas = sas_value.encode('utf-8')
expiry = str(int(time.time() + token_ttl))
string_to_sign = (uri + '\n' + expiry).encode('utf-8')
signed_hmac_sha256 = hmac.HMAC(sas, string_to_sign, hashlib.sha256)
signature = url_parse_quote(base64.b64encode(signed_hmac_sha256.digest()))
return 'SharedAccessSignature sr={}&sig={}&se={}&skn={}'.format(uri, signature, expiry, sas_name)


class CustomizedSASCredential(object):
def __init__(self, token, expiry):
"""
:param str token: The token string
:param float expiry: The epoch timestamp
"""
self.token = token
self.expiry = expiry
self.token_type = b"servicebus.windows.net:sastoken"

async def get_token(self, *scopes, **kwargs):
"""
This method is automatically called when token is about to expire.
"""
return AccessToken(self.token, self.expiry)


# Target namespace and hub must also be specified. Consumer group is set to default unless required otherwise.
FULLY_QUALIFIED_NAMESPACE = os.environ['EVENT_HUB_HOSTNAME']
EVENTHUB_NAME = os.environ['EVENT_HUB_NAME']
CONSUMER_GROUP = "$Default"

# The following part creates a SAS token. Users can use any way to create a SAS token.
SAS_POLICY = os.environ['EVENT_HUB_SAS_POLICY']
SAS_KEY = os.environ['EVENT_HUB_SAS_KEY']

async def create_with_sas_token():
uri = "sb://{}/{}".format(FULLY_QUALIFIED_NAMESPACE, EVENTHUB_NAME)
token_ttl = 3000 # seconds
sas_token = generate_sas_token(uri, SAS_POLICY, SAS_KEY, token_ttl)
# end of creating a SAS token

consumer_client = EventHubConsumerClient(
fully_qualified_namespace=FULLY_QUALIFIED_NAMESPACE,
eventhub_name=EVENTHUB_NAME,
consumer_group=CONSUMER_GROUP,
credential=CustomizedSASCredential(sas_token, time.time() + token_ttl),
logging_enable=True
)

async def on_event(context, event):
print(context.partition_id, ":", event)

async with consumer_client:
await consumer_client.receive(
on_event,
starting_position=-1
)


loop = asyncio.get_event_loop()
loop.run_until_complete(create_with_sas_token())
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

"""
Example to demonstrate utilizing SAS (Shared Access Signature) tokens to authenticate with ServiceBus
"""

# pylint: disable=C0111

import os
import time
import hmac
import hashlib
import base64
try:
from urllib.parse import quote as url_parse_quote
except ImportError:
from urllib import pathname2url as url_parse_quote

from azure.core.credentials import AccessToken
from azure.eventhub import EventHubConsumerClient


def generate_sas_token(uri, sas_name, sas_value, token_ttl):
"""Performs the signing and encoding needed to generate a sas token from a sas key."""
sas = sas_value.encode('utf-8')
expiry = str(int(time.time() + token_ttl))
string_to_sign = (uri + '\n' + expiry).encode('utf-8')
signed_hmac_sha256 = hmac.HMAC(sas, string_to_sign, hashlib.sha256)
signature = url_parse_quote(base64.b64encode(signed_hmac_sha256.digest()))
return 'SharedAccessSignature sr={}&sig={}&se={}&skn={}'.format(uri, signature, expiry, sas_name)


class CustomizedSASCredential(object):
def __init__(self, token, expiry):
"""
:param str token: The token string
:param float expiry: The epoch timestamp
"""
self.token = token
self.expiry = expiry
self.token_type = b"servicebus.windows.net:sastoken"

def get_token(self, *scopes, **kwargs):
"""
This method is automatically called when token is about to expire.
"""
return AccessToken(self.token, self.expiry)


# Target namespace and hub must also be specified. Consumer group is set to default unless required otherwise.
FULLY_QUALIFIED_NAMESPACE = os.environ['EVENT_HUB_HOSTNAME']
EVENTHUB_NAME = os.environ['EVENT_HUB_NAME']
CONSUMER_GROUP = "$Default"

# The following part creates a SAS token. Users can use any way to create a SAS token.
SAS_POLICY = os.environ['EVENT_HUB_SAS_POLICY']
SAS_KEY = os.environ['EVENT_HUB_SAS_KEY']

uri = "sb://{}/{}".format(FULLY_QUALIFIED_NAMESPACE, EVENTHUB_NAME)
token_ttl = 3000 # seconds
sas_token = generate_sas_token(uri, SAS_POLICY, SAS_KEY, token_ttl)
# end of creating a SAS token

consumer_client = EventHubConsumerClient(
fully_qualified_namespace=FULLY_QUALIFIED_NAMESPACE,
eventhub_name=EVENTHUB_NAME,
consumer_group=CONSUMER_GROUP,
credential=CustomizedSASCredential(sas_token, time.time() + token_ttl),
logging_enable=True
)

with consumer_client:
consumer_client.receive(
lambda pc, event: print(pc.partition_id, ":", event),
starting_position=-1
)

0 comments on commit d334964

Please sign in to comment.