-
Notifications
You must be signed in to change notification settings - Fork 305
Axsuarez/gov support #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Axsuarez/gov support #278
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
aa13103
Gov support with unit tests. Coveralls badge fixed to point correct b…
axelsrz 0adcb43
pylint and black compliance
axelsrz 7d5d0e7
pylint fix
axelsrz ae8ae8f
Fixes in BF connector and emulator validation
axelsrz f2da4d4
Merge branch 'master' into axsuarez/gov-support
axelsrz 9fe64c2
Merge branch 'master' into axsuarez/gov-support
axelsrz ac2904d
Added check to env variables for BF Adapter
axelsrz 3f49129
Merge branch 'master' into axsuarez/gov-support
axelsrz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
libraries/botframework-connector/botframework/connector/auth/authentication_constants.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. | ||
| from abc import ABC | ||
|
|
||
|
|
||
| class AuthenticationConstants(ABC): | ||
|
|
||
| # TO CHANNEL FROM BOT: Login URL | ||
| # | ||
| # DEPRECATED: DO NOT USE | ||
| TO_CHANNEL_FROM_BOT_LOGIN_URL = ( | ||
| "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token" | ||
| ) | ||
|
|
||
| # TO CHANNEL FROM BOT: Login URL prefix | ||
| TO_CHANNEL_FROM_BOT_LOGIN_URL_PREFIX = "https://login.microsoftonline.com/" | ||
|
|
||
| # TO CHANNEL FROM BOT: Login URL token endpoint path | ||
| TO_CHANNEL_FROM_BOT_TOKEN_ENDPOINT_PATH = "/oauth2/v2.0/token" | ||
|
|
||
| # TO CHANNEL FROM BOT: Default tenant from which to obtain a token for bot to channel communication | ||
| DEFAULT_CHANNEL_AUTH_TENANT = "botframework.com" | ||
|
|
||
| # TO CHANNEL FROM BOT: OAuth scope to request | ||
| TO_CHANNEL_FROM_BOT_OAUTH_SCOPE = "https://api.botframework.com/.default" | ||
|
|
||
| # TO BOT FROM CHANNEL: Token issuer | ||
| TO_BOT_FROM_CHANNEL_TOKEN_ISSUER = "https://api.botframework.com" | ||
|
|
||
| # Application Setting Key for the OpenIdMetadataUrl value. | ||
| BOT_OPEN_ID_METADATA_KEY = "BotOpenIdMetadata" | ||
|
|
||
| # Application Setting Key for the ChannelService value. | ||
| CHANNEL_SERVICE = "ChannelService" | ||
|
|
||
| # Application Setting Key for the OAuthUrl value. | ||
| OAUTH_URL_KEY = "OAuthApiEndpoint" | ||
|
|
||
| # Application Settings Key for whether to emulate OAuthCards when using the emulator. | ||
| EMULATE_OAUTH_CARDS_KEY = "EmulateOAuthCards" | ||
|
|
||
| # TO BOT FROM CHANNEL: OpenID metadata document for tokens coming from MSA | ||
| TO_BOT_FROM_CHANNEL_OPEN_ID_METADATA_URL = ( | ||
| "https://login.botframework.com/v1/.well-known/openidconfiguration" | ||
| ) | ||
|
|
||
| # TO BOT FROM ENTERPRISE CHANNEL: OpenID metadata document for tokens coming from MSA | ||
| TO_BOT_FROM_ENTERPRISE_CHANNEL_OPEN_ID_METADATA_URL_FORMAT = ( | ||
| "https://{channelService}.enterprisechannel.botframework.com" | ||
| "/v1/.well-known/openidconfiguration" | ||
| ) | ||
|
|
||
| # TO BOT FROM EMULATOR: OpenID metadata document for tokens coming from MSA | ||
| TO_BOT_FROM_EMULATOR_OPEN_ID_METADATA_URL = ( | ||
| "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration" | ||
| ) | ||
|
|
||
| # Allowed token signing algorithms. Tokens come from channels to the bot. The code | ||
| # that uses this also supports tokens coming from the emulator. | ||
| ALLOWED_SIGNING_ALGORITHMS = ["RS256", "RS384", "RS512"] | ||
|
|
||
| # "azp" Claim. | ||
| # Authorized party - the party to which the ID Token was issued. | ||
| # This claim follows the general format set forth in the OpenID Spec. | ||
| # http://openid.net/specs/openid-connect-core-1_0.html#IDToken | ||
| AUTHORIZED_PARTY = "azp" | ||
|
|
||
| """ | ||
| Audience Claim. From RFC 7519. | ||
| https://tools.ietf.org/html/rfc7519#section-4.1.3 | ||
| The "aud" (audience) claim identifies the recipients that the JWT is | ||
| intended for. Each principal intended to process the JWT MUST | ||
| identify itself with a value in the audience claim.If the principal | ||
| processing the claim does not identify itself with a value in the | ||
| "aud" claim when this claim is present, then the JWT MUST be | ||
| rejected.In the general case, the "aud" value is an array of case- | ||
| sensitive strings, each containing a StringOrURI value.In the | ||
| special case when the JWT has one audience, the "aud" value MAY be a | ||
| single case-sensitive string containing a StringOrURI value.The | ||
| interpretation of audience values is generally application specific. | ||
| Use of this claim is OPTIONAL. | ||
| """ | ||
| AUDIENCE_CLAIM = "aud" | ||
|
|
||
| """ | ||
| Issuer Claim. From RFC 7519. | ||
| https://tools.ietf.org/html/rfc7519#section-4.1.1 | ||
| The "iss" (issuer) claim identifies the principal that issued the | ||
| JWT. The processing of this claim is generally application specific. | ||
| The "iss" value is a case-sensitive string containing a StringOrURI | ||
| value. Use of this claim is OPTIONAL. | ||
| """ | ||
| ISSUER_CLAIM = "iss" | ||
|
|
||
| """ | ||
| From RFC 7515 | ||
| https://tools.ietf.org/html/rfc7515#section-4.1.4 | ||
| The "kid" (key ID) Header Parameter is a hint indicating which key | ||
| was used to secure the JWS. This parameter allows originators to | ||
| explicitly signal a change of key to recipients. The structure of | ||
| the "kid" value is unspecified. Its value MUST be a case-sensitive | ||
| string. Use of this Header Parameter is OPTIONAL. | ||
| When used with a JWK, the "kid" value is used to match a JWK "kid" | ||
| parameter value. | ||
| """ | ||
| KEY_ID_HEADER = "kid" | ||
|
|
||
| # Token version claim name. As used in Microsoft AAD tokens. | ||
| VERSION_CLAIM = "ver" | ||
|
|
||
| # App ID claim name. As used in Microsoft AAD 1.0 tokens. | ||
| APP_ID_CLAIM = "appid" | ||
|
|
||
| # Service URL claim name. As used in Microsoft Bot Framework v3.1 auth. | ||
| SERVICE_URL_CLAIM = "serviceurl" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
...aries/botframework-connector/botframework/connector/auth/enterprise_channel_validation.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. | ||
|
|
||
| from abc import ABC | ||
|
|
||
| from .authentication_constants import AuthenticationConstants | ||
| from .channel_validation import ChannelValidation | ||
| from .claims_identity import ClaimsIdentity | ||
| from .credential_provider import CredentialProvider | ||
| from .jwt_token_extractor import JwtTokenExtractor | ||
| from .verify_options import VerifyOptions | ||
|
|
||
|
|
||
| class EnterpriseChannelValidation(ABC): | ||
|
|
||
| TO_BOT_FROM_ENTERPRISE_CHANNEL_TOKEN_VALIDATION_PARAMETERS = VerifyOptions( | ||
| issuer=[AuthenticationConstants.TO_BOT_FROM_CHANNEL_TOKEN_ISSUER], | ||
| audience=None, | ||
| clock_tolerance=5 * 60, | ||
| ignore_expiration=False, | ||
| ) | ||
|
|
||
| @staticmethod | ||
| async def authenticate_channel_token( | ||
| auth_header: str, | ||
| credentials: CredentialProvider, | ||
| channel_id: str, | ||
| channel_service: str, | ||
| ) -> ClaimsIdentity: | ||
| endpoint = ( | ||
| ChannelValidation.open_id_metadata_endpoint | ||
| if ChannelValidation.open_id_metadata_endpoint | ||
| else AuthenticationConstants.TO_BOT_FROM_ENTERPRISE_CHANNEL_OPEN_ID_METADATA_URL_FORMAT.replace( | ||
| "{channelService}", channel_service | ||
| ) | ||
| ) | ||
| token_extractor = JwtTokenExtractor( | ||
| EnterpriseChannelValidation.TO_BOT_FROM_ENTERPRISE_CHANNEL_TOKEN_VALIDATION_PARAMETERS, | ||
| endpoint, | ||
| AuthenticationConstants.ALLOWED_SIGNING_ALGORITHMS, | ||
| ) | ||
|
|
||
| identity: ClaimsIdentity = await token_extractor.get_identity_from_auth_header( | ||
| auth_header, channel_id | ||
| ) | ||
| return await EnterpriseChannelValidation.validate_identity( | ||
| identity, credentials | ||
| ) | ||
|
|
||
| @staticmethod | ||
| async def authenticate_channel_token_with_service_url( | ||
| auth_header: str, | ||
| credentials: CredentialProvider, | ||
| service_url: str, | ||
| channel_id: str, | ||
| channel_service: str, | ||
| ) -> ClaimsIdentity: | ||
| identity: ClaimsIdentity = await EnterpriseChannelValidation.authenticate_channel_token( | ||
| auth_header, credentials, channel_id, channel_service | ||
| ) | ||
|
|
||
| service_url_claim: str = identity.get_claim_value( | ||
| AuthenticationConstants.SERVICE_URL_CLAIM | ||
| ) | ||
| if service_url_claim != service_url: | ||
| raise Exception("Unauthorized. service_url claim do not match.") | ||
|
|
||
| return identity | ||
|
|
||
| @staticmethod | ||
| async def validate_identity( | ||
| identity: ClaimsIdentity, credentials: CredentialProvider | ||
| ) -> ClaimsIdentity: | ||
| if identity is None: | ||
| # No valid identity. Not Authorized. | ||
| raise Exception("Unauthorized. No valid identity.") | ||
|
|
||
| if not identity.is_authenticated: | ||
| # The token is in some way invalid. Not Authorized. | ||
| raise Exception("Unauthorized. Is not authenticated.") | ||
|
|
||
| # Now check that the AppID in the claim set matches | ||
| # what we're looking for. Note that in a multi-tenant bot, this value | ||
| # comes from developer code that may be reaching out to a service, hence the | ||
| # Async validation. | ||
|
|
||
| # Look for the "aud" claim, but only if issued from the Bot Framework | ||
| if ( | ||
| identity.get_claim_value(AuthenticationConstants.ISSUER_CLAIM) | ||
| != AuthenticationConstants.TO_BOT_FROM_CHANNEL_TOKEN_ISSUER | ||
| ): | ||
| # The relevant Audience Claim MUST be present. Not Authorized. | ||
| raise Exception("Unauthorized. Issuer claim MUST be present.") | ||
|
|
||
| # The AppId from the claim in the token must match the AppId specified by the developer. | ||
| # In this case, the token is destined for the app, so we find the app ID in the audience claim. | ||
| aud_claim: str = identity.get_claim_value( | ||
| AuthenticationConstants.AUDIENCE_CLAIM | ||
| ) | ||
| if not await credentials.is_valid_appid(aud_claim or ""): | ||
| # The AppId is not valid or not present. Not Authorized. | ||
| raise Exception( | ||
| f"Unauthorized. Invalid AppId passed on token: { aud_claim }" | ||
| ) | ||
|
|
||
| return identity | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this for?