Skip to content

Commit 305a746

Browse files
authored
[webpubsub] fix jwt token + reverse proxy endpoint (Azure#22587)
1 parent e7e4764 commit 305a746

File tree

10 files changed

+175
-58
lines changed

10 files changed

+175
-58
lines changed

sdk/webpubsub/azure-messaging-webpubsubservice/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Bugs Fixed
1010

11+
- fix authentication who use a `reverse_proxy_endpoint` with either `WebPubSubServiceClient.from_connection_string` or pass in an `AzureKeyCredential` for authentication #22587
12+
1113
### Other Changes
1214

1315
## 1.0.0 (2021-11-10)

sdk/webpubsub/azure-messaging-webpubsubservice/azure/messaging/webpubsubservice/_patch.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,14 @@ class JwtCredentialPolicy(SansIOHTTPPolicy):
140140

141141
NAME_CLAIM_TYPE = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
142142

143-
def __init__(self, credential, user=None):
144-
# type: (AzureKeyCredential, typing.Optional[str]) -> None
143+
def __init__(
144+
self,
145+
credential: AzureKeyCredential,
146+
*,
147+
user: typing.Optional[str] = None,
148+
origin_endpoint: typing.Optional[str] = None,
149+
reverse_proxy_endpoint: typing.Optional[str] = None,
150+
) -> None:
145151
"""Create a new instance of the policy associated with the given credential.
146152
147153
:param credential: The azure.core.credentials.AzureKeyCredential instance to use
@@ -151,6 +157,8 @@ def __init__(self, credential, user=None):
151157
"""
152158
self._credential = credential
153159
self._user = user
160+
self._original_url = origin_endpoint
161+
self._reverse_proxy_endpoint = reverse_proxy_endpoint
154162

155163
def on_request(self, request):
156164
# type: (PipelineRequest) -> typing.Union[None, typing.Awaitable[None]]
@@ -159,8 +167,11 @@ def on_request(self, request):
159167
:param request: Request to be modified before sent from next policy.
160168
:type request: ~azure.core.pipeline.PipelineRequest
161169
"""
170+
url = request.http_request.url
171+
if self._reverse_proxy_endpoint:
172+
url = url.replace(self._reverse_proxy_endpoint, self._original_url, 1)
162173
request.http_request.headers["Authorization"] = "Bearer " + self._encode(
163-
request.http_request.url
174+
url
164175
)
165176
return super(JwtCredentialPolicy, self).on_request(request)
166177

@@ -266,7 +277,12 @@ def _configure(
266277
self.authentication_policy = kwargs.get('authentication_policy')
267278
if self.credential and not self.authentication_policy:
268279
if isinstance(self.credential, AzureKeyCredential):
269-
self.authentication_policy = JwtCredentialPolicy(self.credential, kwargs.get('user'))
280+
self.authentication_policy = JwtCredentialPolicy(
281+
self.credential,
282+
user=kwargs.get("user"),
283+
origin_endpoint=kwargs.get("origin_endpoint"),
284+
reverse_proxy_endpoint=kwargs.get("reverse_proxy_endpoint")
285+
)
270286
else:
271287
self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs)
272288

sdk/webpubsub/azure-messaging-webpubsubservice/azure/messaging/webpubsubservice/aio/_patch.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,12 @@ def _configure(
112112
self.authentication_policy = kwargs.get('authentication_policy')
113113
if self.credential and not self.authentication_policy:
114114
if isinstance(self.credential, AzureKeyCredential):
115-
self.authentication_policy = JwtCredentialPolicy(self.credential, kwargs.get('user'))
115+
self.authentication_policy = JwtCredentialPolicy(
116+
self.credential,
117+
user=kwargs.get("user"),
118+
origin_endpoint=kwargs.get("origin_endpoint"),
119+
reverse_proxy_endpoint=kwargs.get("reverse_proxy_endpoint")
120+
)
116121
else:
117122
self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs)
118123

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
interactions:
2+
- request:
3+
body: '{"Hello": "reverse_proxy_endpoint!"}'
4+
headers:
5+
Accept:
6+
- application/json, text/json
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '36'
13+
Content-Type:
14+
- application/json
15+
User-Agent:
16+
- azsdk-python-messaging-webpubsubservice/1.0.1 Python/3.9.7 (macOS-12.1-x86_64-i386-64bit)
17+
method: POST
18+
uri: https://myservice.webpubsub.azure.com/api/hubs/hub/:send?api-version=2021-10-01
19+
response:
20+
body:
21+
string: ''
22+
headers:
23+
api-supported-versions:
24+
- '2021-10-01'
25+
connection:
26+
- keep-alive
27+
content-length:
28+
- '0'
29+
date:
30+
- Thu, 20 Jan 2022 21:53:17 GMT
31+
strict-transport-security:
32+
- max-age=15724800; includeSubDomains
33+
status:
34+
code: 202
35+
message: Accepted
36+
version: 1
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
interactions:
2+
- request:
3+
body: '{"Hello": "reverse_proxy_endpoint!"}'
4+
headers:
5+
Accept:
6+
- application/json, text/json
7+
Content-Length:
8+
- '36'
9+
Content-Type:
10+
- application/json
11+
User-Agent:
12+
- azsdk-python-messaging-webpubsubservice/1.0.1 Python/3.9.7 (macOS-12.1-x86_64-i386-64bit)
13+
method: POST
14+
uri: https://myservice.webpubsub.azure.com/api/hubs/hub/:send?api-version=2021-10-01
15+
response:
16+
body:
17+
string: ''
18+
headers:
19+
api-supported-versions: '2021-10-01'
20+
connection: keep-alive
21+
content-length: '0'
22+
date: Thu, 20 Jan 2022 21:55:24 GMT
23+
strict-transport-security: max-age=15724800; includeSubDomains
24+
status:
25+
code: 202
26+
message: Accepted
27+
url: https://webpubsub-yyc.webpubsub.azure.com/api/hubs/hub/:send?api-version=2021-10-01
28+
version: 1

sdk/webpubsub/azure-messaging-webpubsubservice/tests/test_reverse_proxy.py

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,45 @@
99
from azure.messaging.webpubsubservice._operations._operations import build_send_to_all_request
1010
from azure.core.credentials import AzureKeyCredential
1111
from devtools_testutils.fake_credential import FakeTokenCredential
12+
from testcase import WebpubsubTest, WebpubsubPowerShellPreparer
13+
from azure.identity import DefaultAzureCredential
1214

13-
def test_reverse_proxy_endpoint_redirection_azure_key_credential():
14-
def _callback(pipeline_request):
15-
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
16-
raise ValueError("Success!")
17-
wps_endpoint = "https://wps.contoso.com/"
18-
apim_endpoint = "https://apim.contoso.com/"
19-
credential = AzureKeyCredential("abcdabcdabcdabcdabcdabcdabcdabcd")
20-
client = WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint)
21-
request = build_send_to_all_request('Hub', content='test_webpubsub_send_request', content_type='text/plain')
15+
class WebpubsubReverseProxyTest(WebpubsubTest):
2216

23-
with pytest.raises(ValueError) as ex:
24-
client.send_request(request, raw_request_hook=_callback)
25-
assert "Success!" in str(ex.value)
17+
def test_reverse_proxy_endpoint_redirection_azure_key_credential(self):
18+
def _callback(pipeline_request):
19+
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
20+
raise ValueError("Success!")
21+
wps_endpoint = "https://wps.contoso.com/"
22+
apim_endpoint = "https://apim.contoso.com/"
23+
credential = AzureKeyCredential("abcdabcdabcdabcdabcdabcdabcdabcd")
24+
client = WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint)
25+
request = build_send_to_all_request('Hub', content='test_webpubsub_send_request', content_type='text/plain')
2626

27-
def test_reverse_proxy_endpoint_redirection_identity():
28-
def _callback(pipeline_request):
29-
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
30-
raise ValueError("Success!")
31-
wps_endpoint = "https://wps.contoso.com/"
32-
apim_endpoint = "https://apim.contoso.com/"
33-
credential = FakeTokenCredential()
34-
client = WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint)
35-
request = build_send_to_all_request('Hub', content='test_webpubsub_send_request', content_type='text/plain')
27+
with pytest.raises(ValueError) as ex:
28+
client.send_request(request, raw_request_hook=_callback)
29+
assert "Success!" in str(ex.value)
3630

37-
with pytest.raises(ValueError) as ex:
38-
client.send_request(request, raw_request_hook=_callback)
39-
assert "Success!" in str(ex.value)
31+
def test_reverse_proxy_endpoint_redirection_identity(self):
32+
def _callback(pipeline_request):
33+
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
34+
raise ValueError("Success!")
35+
wps_endpoint = "https://wps.contoso.com/"
36+
apim_endpoint = "https://apim.contoso.com/"
37+
credential = FakeTokenCredential()
38+
client = WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint)
39+
request = build_send_to_all_request('Hub', content='test_webpubsub_send_request', content_type='text/plain')
40+
41+
with pytest.raises(ValueError) as ex:
42+
client.send_request(request, raw_request_hook=_callback)
43+
assert "Success!" in str(ex.value)
44+
45+
@WebpubsubPowerShellPreparer()
46+
def test_reverse_proxy_call(self, webpubsub_connection_string, webpubsub_reverse_proxy_endpoint):
47+
client = self.create_client(
48+
connection_string=webpubsub_connection_string,
49+
hub='hub',
50+
logging_enable=True,
51+
reverse_proxy_endpoint=webpubsub_reverse_proxy_endpoint
52+
)
53+
client.send_to_all({'Hello': 'reverse_proxy_endpoint!'})

sdk/webpubsub/azure-messaging-webpubsubservice/tests/test_reverse_proxy_async.py

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,47 @@
1010
from azure.core.credentials import AzureKeyCredential
1111
from devtools_testutils.fake_async_credential import AsyncFakeCredential
1212

13-
@pytest.mark.asyncio
14-
async def test_reverse_proxy_endpoint_redirection():
15-
def _callback(pipeline_request):
16-
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
17-
raise ValueError("Success!")
18-
wps_endpoint = "https://wps.contoso.com/"
19-
apim_endpoint = "https://apim.contoso.com/"
20-
credential = AzureKeyCredential("abcdabcdabcdabcdabcdabcdabcdabcd")
21-
request = build_send_to_all_request("Hub", content='test_webpubsub_send_request', content_type='text/plain')
22-
async with WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint) as client:
23-
with pytest.raises(ValueError) as ex:
24-
await client.send_request(request, raw_request_hook=_callback)
25-
assert "Success!" in str(ex.value)
13+
from testcase import WebpubsubPowerShellPreparer
14+
from testcase_async import WebpubsubAsyncTest
15+
16+
class WebpubsubReverseProxyTestAsync(WebpubsubAsyncTest):
17+
18+
@pytest.mark.asyncio
19+
async def test_reverse_proxy_endpoint_redirection(self):
20+
def _callback(pipeline_request):
21+
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
22+
raise ValueError("Success!")
23+
wps_endpoint = "https://wps.contoso.com/"
24+
apim_endpoint = "https://apim.contoso.com/"
25+
credential = AzureKeyCredential("abcdabcdabcdabcdabcdabcdabcdabcd")
26+
request = build_send_to_all_request("Hub", content='test_webpubsub_send_request', content_type='text/plain')
27+
async with WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint) as client:
28+
with pytest.raises(ValueError) as ex:
29+
await client.send_request(request, raw_request_hook=_callback)
30+
assert "Success!" in str(ex.value)
31+
32+
@pytest.mark.asyncio
33+
async def test_reverse_proxy_endpoint_redirection_identity(self):
34+
def _callback(pipeline_request):
35+
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
36+
raise ValueError("Success!")
37+
wps_endpoint = "https://wps.contoso.com/"
38+
apim_endpoint = "https://apim.contoso.com/"
39+
credential = AsyncFakeCredential()
40+
request = build_send_to_all_request('Hub', content='test_webpubsub_send_request', content_type='text/plain')
41+
async with WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint) as client:
42+
with pytest.raises(ValueError) as ex:
43+
await client.send_request(request, raw_request_hook=_callback)
44+
assert "Success!" in str(ex.value)
45+
46+
@pytest.mark.asyncio
47+
@WebpubsubPowerShellPreparer()
48+
async def test_reverse_proxy_call(self, webpubsub_connection_string, webpubsub_reverse_proxy_endpoint):
49+
client = self.create_client(
50+
connection_string=webpubsub_connection_string,
51+
hub='hub',
52+
logging_enable=True,
53+
reverse_proxy_endpoint=webpubsub_reverse_proxy_endpoint
54+
)
55+
await client.send_to_all({'Hello': 'reverse_proxy_endpoint!'})
2656

27-
@pytest.mark.asyncio
28-
async def test_reverse_proxy_endpoint_redirection_identity():
29-
def _callback(pipeline_request):
30-
assert pipeline_request.http_request.url.startswith("https://apim.contoso.com/")
31-
raise ValueError("Success!")
32-
wps_endpoint = "https://wps.contoso.com/"
33-
apim_endpoint = "https://apim.contoso.com/"
34-
credential = AsyncFakeCredential()
35-
request = build_send_to_all_request('Hub', content='test_webpubsub_send_request', content_type='text/plain')
36-
async with WebPubSubServiceClient(wps_endpoint, "Hub", credential, reverse_proxy_endpoint=apim_endpoint) as client:
37-
with pytest.raises(ValueError) as ex:
38-
await client.send_request(request, raw_request_hook=_callback)
39-
assert "Success!" in str(ex.value)

sdk/webpubsub/azure-messaging-webpubsubservice/tests/test_smoke.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# license information.
66
# -------------------------------------------------------------------------
77
import pytest
8-
from requests.packages.urllib3.connection import connection
98
from testcase import WebpubsubTest, WebpubsubPowerShellPreparer
109
from azure.messaging.webpubsubservice._operations._operations import build_send_to_all_request
1110
from azure.core.exceptions import ServiceRequestError

sdk/webpubsub/azure-messaging-webpubsubservice/tests/testcase.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def __init__(self, method_name, **kwargs):
1515

1616
def create_client(self, endpoint=None, hub=None, reverse_proxy_endpoint=None, **kwargs):
1717
if kwargs.get("connection_string"):
18-
return WebPubSubServiceClient.from_connection_string(kwargs.pop("connection_string"), hub)
18+
return WebPubSubServiceClient.from_connection_string(kwargs.pop("connection_string"), hub, **kwargs)
1919
credential = self.get_credential(WebPubSubServiceClient)
2020
return self.create_client_from_credential(
2121
WebPubSubServiceClient,

sdk/webpubsub/azure-messaging-webpubsubservice/tests/testcase_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(self, method_name, **kwargs):
1414

1515
def create_client(self, endpoint=None, hub=None, reverse_proxy_endpoint=None, **kwargs):
1616
if kwargs.get("connection_string"):
17-
return WebPubSubServiceClient.from_connection_string(kwargs.pop("connection_string"), hub)
17+
return WebPubSubServiceClient.from_connection_string(kwargs.pop("connection_string"), hub, **kwargs)
1818
credential = self.get_credential(WebPubSubServiceClient, is_async=True)
1919
return self.create_client_from_credential(
2020
WebPubSubServiceClient,

0 commit comments

Comments
 (0)