8000 add validate_auth_header to JwtTokenValidation, update samples, BotFr… · openvelora/botbuilder-python@ac3e37f · GitHub
[go: up one dir, main page]

Skip to content

Commit ac3e37f

Browse files
committed
add validate_auth_header to JwtTokenValidation, update samples, BotFrameworkAdapter and test)auth.py
1 parent 6388b1a commit ac3e37f

File tree

13 files changed

+76
-28
lines changed

13 files changed

+76
-28
lines changed

libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,35 @@ def __init__(self, settings: BotFrameworkAdapterSettings):
2626
self._credentials = MicrosoftAppCredentials(self.settings.app_id, self.settings.app_password)
2727
self._credential_provider = SimpleCredentialProvider(self.settings.app_id, self.settings.app_password)
2828

29-
async def process_request(self, req, auth_header: str, logic: Callable):
30-
request = await self.parse_request(req)
29+
async def process_activity(self, req, auth_header: str, logic: Callable):
30+
request = self.parse_request(req)
3131
auth_header = auth_header or ''
3232

33-
await self.authenticate_request(request, auth_header)
34-
context = self.create_context(request)
33+
claims_identity = await JwtTokenValidation.authenticate_request(request,
34+
auth_header,
35+
self._credential_provider)
3536

37+
context = BotContext(self, request)
38+
# context.services.add("bot_identity", claims_identity)
39+
# connector_client = await self.create_connector_client_async(activity.service_url, claims_identity)
40+
# context.services.add("connector_client", connector_client)
3641
return await self.run_pipeline(context, logic)
3742

3843
async def authenticate_request(self, request: Activity, auth_header: str):
39-
await JwtTokenValidation.assert_valid_activity(request, auth_header, self._credential_provider)
44+
await JwtTokenValidation.authenticate_request(request, auth_header, self._credential_provider)
4045

4146
def create_context(self, activity):
4247
return BotContext(self, activity)
4348

4449
@staticmethod
45-
async def parse_request(req):
50+
def parse_request(req): # Why on earth is this asynchronous?
4651
"""
4752
Parses and validates request
4853
:param req:
4954
:return:
5055
"""
5156

52-
async def validate_activity(activity: Activity):
57+
def validate_activity(activity: Activity):
5358
if not isinstance(activity.type, str):
5459
raise TypeError('BotFrameworkAdapter.parse_request(): invalid or missing activity type.')
5560
return True
@@ -59,15 +64,15 @@ async def validate_activity(activity: Activity):
5964
if hasattr(req, 'body'):
6065
try:
6166
activity = Activity().deserialize(req.body)
62-
is_valid_activity = await validate_activity(activity)
67+
is_valid_activity = validate_activity(activity)
6368
if is_valid_activity:
6469
return activity
6570
except BaseException as e:
6671
raise e
6772
elif 'body' in req:
6873
try:
6974
activity = Activity().deserialize(req['body'])
70-
is_valid_activity = await validate_activity(activity)
75+
is_valid_activity = validate_activity(activity)
7176
if is_valid_activity:
7277
return activity
7378
except BaseException as e:
@@ -76,7 +81,7 @@ async def validate_activity(activity: Activity):
7681
raise TypeError('BotFrameworkAdapter.parse_request(): received invalid activity')
7782
else:
7883
# The `req` has already been deserialized to an Activity, so verify the Activity.type and return it.
79-
is_valid_activity = await validate_activity(req)
84+
is_valid_activity = validate_activity(req)
8085
if is_valid_activity:
8186
return req
8287

@@ -124,7 +129,7 @@ async def send(self, activities: List[Activity]):
124129

125130
async def receive(self, auth_header: str, activity: Activity):
126131
try:
127-
await JwtTokenValidation.assert_valid_activity(activity, auth_header, self._credential_provider)
132+
await JwtTokenValidation.authenticate_request(activity, auth_header, self._credential_provider)
128133
except BaseException as e:
129134
raise e
130135
else:

libraries/botframework-connector/botframework/connector/auth/channel_validation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
import asyncio
25

36
from .verify_options import VerifyOptions

libraries/botframework-connector/botframework/connector/auth/claims_identity.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
class Claim:
25
def __init__(self, claim_type: str, value):
36
self.type = claim_type

libraries/botframework-connector/botframework/connector/auth/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
class Constants: # pylint: disable=too-few-public-methods
25
TO_BOT_FROM_CHANNEL_TOKEN_ISSUER = "https://api.botframework.com"
36

libraries/botframework-connector/botframework/connector/auth/credential_provider.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
class CredentialProvider:
25
"""CredentialProvider.
36
This class allows Bots to provide their own implemention

libraries/botframework-connector/botframework/connector/auth/emulator_validation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
import asyncio
25
import jwt
36

libraries/botframework-connector/botframework/connector/auth/jwt_token_extractor.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
import asyncio
25
import json
36
from datetime import datetime, timedelta
Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
from botbuilder.schema import Activity
25

36
from .emulator_validation import EmulatorValidation
47
from .channel_validation import ChannelValidation
5-
from .microsoft_app_credentials import MicrosoftAppCredentials
8+
from .claims_identity import ClaimsIdentity
69
from .credential_provider import CredentialProvider
10+
from .microsoft_app_credentials import MicrosoftAppCredentials
11+
712

813
class JwtTokenValidation:
914

1015
@staticmethod
11-
async def assert_valid_activity(activity: Activity, auth_header: str, credentials: CredentialProvider):
16+
async def authenticate_request(activity: Activity, auth_header: str, credentials: CredentialProvider):
1217
"""Validates the security tokens required by the Bot Framework Protocol. Throws on any exceptions.
1318
1419
:param activity: The incoming Activity from the Bot Framework or the Emulator
@@ -25,17 +30,31 @@ async def assert_valid_activity(activity: Activity, auth_header: str, credential
2530
is_auth_disabled = await credentials.is_authentication_disabled()
2631
if is_auth_disabled:
2732
# We are on the anonymous code path.
28-
return
33+
return ClaimsIdentity({}, True) # Not sure if this should be true or not.
2934

3035
# No Auth Header. Auth is required. Request is not authorized.
3136
raise Exception('Unauthorized Access. Request is not authorized')
3237

33-
using_emulator = EmulatorValidation.is_token_from_emulator(auth_header)
34-
if using_emulator:
35-
await EmulatorValidation.authenticate_emulator_token(auth_header, credentials)
36-
else:
37-
await ChannelValidation.authenticate_token_service_url(
38-
auth_header, credentials, activity.service_url)
38+
claims_identity = await JwtTokenValidation.validate_auth_header(auth_header, credentials, activity.service_url)
3939

4040
# On the standard Auth path, we need to trust the URL that was incoming.
4141
MicrosoftAppCredentials.trust_service_url(activity.service_url)
42+
43+
return claims_identity
44+
45+
@staticmethod
46+
async def validate_auth_header(auth_header: str,
47+
credentials: CredentialProvider,
48+
service_url: str) -> ClaimsIdentity:
49+
if type(auth_header) != str or not auth_header.replace(' ', ''):
50+
raise TypeError('JwtTokenValidation.validate_auth_header(): Invalid auth_header received.')
51+
52+
using_emulator: bool = EmulatorValidation.is_token_from_emulator(auth_header)
53+
54+
if using_emulator:
55+
return await EmulatorValidation.authenticate_emulator_token(auth_header, credentials)
56+
else:
57+
if service_url is not None:
58+
return await ChannelValidation.authenticate_token_service_url(auth_header, credentials, service_url)
59+
else:
60+
return await ChannelValidation.authenticate_token(auth_header, credentials)

libraries/botframework-connector/botframework/connector/auth/microsoft_app_credentials.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
from datetime import datetime, timedelta
25
from urllib.parse import urlparse
36

libraries/botframework-connector/botframework/connector/auth/verify_options.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
14
class VerifyOptions:
25
def __init__(self, issuer, audience, clock_tolerance, ignore_expiration):
36
self.issuer = issuer

0 commit comments

Comments
 (0)
0