Пример #1
0
        /// <summary>
        /// Creates the appropriate <see cref="BotFrameworkAuthentication" /> instance.
        /// </summary>
        /// <param name="channelService">The Channel Service.</param>
        /// <param name="validateAuthority">The validate authority value to use.</param>
        /// <param name="toChannelFromBotLoginUrl">The to Channel from bot login url.</param>
        /// <param name="toChannelFromBotOAuthScope">The to Channel from bot oauth scope.</param>
        /// <param name="toBotFromChannelTokenIssuer">The to bot from Channel Token Issuer.</param>
        /// <param name="oAuthUrl">The oAuth url.</param>
        /// <param name="toBotFromChannelOpenIdMetadataUrl">The to bot from Channel Open Id Metadata url.</param>
        /// <param name="toBotFromEmulatorOpenIdMetadataUrl">The to bot from Emulator Open Id Metadata url.</param>
        /// <param name="callerId">The Microsoft app password.</param>
        /// <param name="credentialFactory">The <see cref="ServiceClientCredentialsFactory" /> to use to create credentials.</param>
        /// <param name="authConfiguration">The <see cref="AuthenticationConfiguration" /> to use.</param>
        /// <param name="httpClientFactory">The <see cref="IHttpClientFactory" /> to use.</param>
        /// <param name="logger">The <see cref="ILogger" /> to use.</param>
        /// <returns>A new <see cref="BotFrameworkAuthentication" /> instance.</returns>
        public static BotFrameworkAuthentication Create(
            string channelService,
            bool validateAuthority,
            string toChannelFromBotLoginUrl,
            string toChannelFromBotOAuthScope,
            string toBotFromChannelTokenIssuer,
            string oAuthUrl,
            string toBotFromChannelOpenIdMetadataUrl,
            string toBotFromEmulatorOpenIdMetadataUrl,
            string callerId,
            ServiceClientCredentialsFactory credentialFactory,
            AuthenticationConfiguration authConfiguration,
            IHttpClientFactory httpClientFactory,
            ILogger logger)
        {
            if (
                !string.IsNullOrEmpty(toChannelFromBotLoginUrl) ||
                !string.IsNullOrEmpty(toChannelFromBotOAuthScope) ||
                !string.IsNullOrEmpty(toBotFromChannelTokenIssuer) ||
                !string.IsNullOrEmpty(oAuthUrl) ||
                !string.IsNullOrEmpty(toBotFromChannelOpenIdMetadataUrl) ||
                !string.IsNullOrEmpty(toBotFromEmulatorOpenIdMetadataUrl) ||
                !string.IsNullOrEmpty(callerId))
            {
                // if we have any of the 'parameterized' properties defined we'll assume this is the parameterized code

                return(new ParameterizedBotFrameworkAuthentication(
                           validateAuthority,
                           toChannelFromBotLoginUrl,
                           toChannelFromBotOAuthScope,
                           toBotFromChannelTokenIssuer,
                           oAuthUrl,
                           toBotFromChannelOpenIdMetadataUrl,
                           toBotFromEmulatorOpenIdMetadataUrl,
                           callerId,
                           credentialFactory,
                           authConfiguration,
                           httpClientFactory,
                           logger));
            }
            else
            {
                // else apply the built in default behavior, which is either the public cloud or the gov cloud depending on whether we have a channelService value present

                if (string.IsNullOrEmpty(channelService))
                {
                    return(new PublicCloudBotFrameworkAuthentication(credentialFactory, authConfiguration, httpClientFactory, logger));
                }
                else if (channelService == GovernmentAuthenticationConstants.ChannelService)
                {
                    return(new GovernmentCloudBotFrameworkAuthentication(credentialFactory, authConfiguration, httpClientFactory, logger));
                }
                else
                {
                    // The ChannelService value is used an indicator of which built in set of constants to use. If it is not recognized, a full configuration is expected.

                    throw new ArgumentException("The provided ChannelService value is not supported.");
                }
            }
        }
 public ParameterizedBotFrameworkAuthentication(
     string channelService,
     bool validateAuthority,
     string toChannelFromBotLoginUrl,
     string toChannelFromBotOAuthScope,
     string toBotFromChannelTokenIssuer,
     string oAuthUrl,
     string toBotFromChannelOpenIdMetadataUrl,
     string toBotFromEmulatorOpenIdMetadataUrl,
     string callerId,
     ServiceClientCredentialsFactory credentialFactory,
     AuthenticationConfiguration authConfiguration,
     HttpClient httpClient = null,
     ILogger logger        = null)
 {
     _channelService              = channelService;
     _validateAuthority           = validateAuthority;
     _toChannelFromBotLoginUrl    = toChannelFromBotLoginUrl;
     _toChannelFromBotOAuthScope  = toChannelFromBotOAuthScope;
     _toBotFromChannelTokenIssuer = toBotFromChannelTokenIssuer;
     _oAuthUrl = oAuthUrl;
     _toBotFromChannelOpenIdMetadataUrl  = toBotFromChannelOpenIdMetadataUrl;
     _toBotFromEmulatorOpenIdMetadataUrl = toBotFromEmulatorOpenIdMetadataUrl;
     _callerId          = callerId;
     _credentialFactory = credentialFactory;
     _authConfiguration = authConfiguration;
     _httpClient        = httpClient ?? _defaultHttpClient;
     _logger            = logger;
 }
 public ParameterizedBotFrameworkAuthentication(
     bool validateAuthority,
     string toChannelFromBotLoginUrl,
     string toChannelFromBotOAuthScope,
     string toBotFromChannelTokenIssuer,
     string oAuthUrl,
     string toBotFromChannelOpenIdMetadataUrl,
     string toBotFromEmulatorOpenIdMetadataUrl,
     string callerId,
     ServiceClientCredentialsFactory credentialFactory,
     AuthenticationConfiguration authConfiguration,
     IHttpClientFactory httpClientFactory,
     ILogger logger)
 {
     _validateAuthority           = validateAuthority;
     _toChannelFromBotLoginUrl    = toChannelFromBotLoginUrl;
     _toChannelFromBotOAuthScope  = toChannelFromBotOAuthScope;
     _toBotFromChannelTokenIssuer = toBotFromChannelTokenIssuer;
     _oAuthUrl = oAuthUrl;
     _toBotFromChannelOpenIdMetadataUrl  = toBotFromChannelOpenIdMetadataUrl;
     _toBotFromEmulatorOpenIdMetadataUrl = toBotFromEmulatorOpenIdMetadataUrl;
     _callerId          = callerId;
     _credentialFactory = credentialFactory;
     _authConfiguration = authConfiguration;
     _httpClientFactory = httpClientFactory;
     _logger            = logger ?? NullLogger.Instance;
 }
 public ConnectorFactoryImpl(string appId, string toChannelFromBotOAuthScope, string loginEndpoint, bool validateAuthority, ServiceClientCredentialsFactory credentialFactory, IHttpClientFactory httpClientFactory, ILogger logger)
 {
     _appId = appId;
     _toChannelFromBotOAuthScope = toChannelFromBotOAuthScope;
     _loginEndpoint     = loginEndpoint;
     _validateAuthority = validateAuthority;
     _credentialFactory = credentialFactory;
     _httpClientFactory = httpClientFactory;
     _logger            = logger;
 }
Пример #5
0
 protected BuiltinBotFrameworkAuthentication(string toChannelFromBotOAuthScope, string loginEndpoint, string callerId, string channelService, ServiceClientCredentialsFactory credentialFactory, AuthenticationConfiguration authConfiguration, HttpClient httpClient, ILogger logger)
 {
     _toChannelFromBotOAuthScope = toChannelFromBotOAuthScope;
     _loginEndpoint     = loginEndpoint;
     _callerId          = callerId;
     _channelService    = channelService;
     _credentialFactory = credentialFactory;
     _authConfiguration = authConfiguration;
     _httpClient        = httpClient;
     _logger            = logger;
 }
Пример #6
0
 public BotFrameworkClientImpl(
     ServiceClientCredentialsFactory credentialsFactory,
     IHttpClientFactory httpClientFactory,
     string loginEndpoint,
     ILogger logger)
 {
     _credentialsFactory = credentialsFactory;
     _httpClient         = httpClientFactory?.CreateClient() ?? new HttpClient();
     _loginEndpoint      = loginEndpoint;
     _logger             = logger ?? NullLogger.Instance;
     ConnectorClient.AddDefaultRequestHeaders(_httpClient);
 }
Пример #7
0
 public GovernmentCloudBotFrameworkAuthentication(ServiceClientCredentialsFactory credentialFactory, AuthenticationConfiguration authConfiguration, HttpClient httpClient = null, ILogger logger = null)
     : base(
         GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope,
         GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl,
         CallerIdConstants.USGovChannel,
         GovernmentAuthenticationConstants.ChannelService,
         credentialFactory,
         authConfiguration,
         httpClient,
         logger)
 {
 }
 public PublicCloudBotFrameworkAuthentication(ServiceClientCredentialsFactory credentialFactory, AuthenticationConfiguration authConfiguration, HttpClient httpClient = null, ILogger logger = null)
     : base(
         AuthenticationConstants.ToChannelFromBotOAuthScope,
         AuthenticationConstants.ToChannelFromBotLoginUrlTemplate,
         CallerIdConstants.PublicAzureChannel,
         null,
         credentialFactory,
         authConfiguration,
         httpClient,
         logger)
 {
 }
        /// <summary>
        /// Generates the appropriate callerId to write onto the activity, this might be null.
        /// </summary>
        /// <param name="credentialFactory">A <see cref="ServiceClientCredentialsFactory"/> to use.</param>
        /// <param name="claimsIdentity">The inbound claims.</param>
        /// <param name="callerId">The default callerId to use if this is not a skill.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>The callerId, this might be null.</returns>
        protected internal async Task <string> GenerateCallerIdAsync(ServiceClientCredentialsFactory credentialFactory, ClaimsIdentity claimsIdentity, string callerId, CancellationToken cancellationToken)
        {
            // Is the bot accepting all incoming messages?
            if (await credentialFactory.IsAuthenticationDisabledAsync(cancellationToken).ConfigureAwait(false))
            {
                // Return null so that the callerId is cleared.
                return(null);
            }

            // Is the activity from another bot?
            return(SkillValidation.IsSkillClaim(claimsIdentity.Claims)
                ? $"{CallerIdConstants.BotToBotPrefix}{JwtTokenValidation.GetAppIdFromClaims(claimsIdentity.Claims)}"
                : callerId);
        }
 /// <summary>
 /// Creates the appropriate cloud environment instance.
 /// </summary>
 /// <param name="channelService">The Channel Service.</param>
 /// <param name="validateAuthority">The validate authority value to use.</param>
 /// <param name="toChannelFromBotLoginUrl">The to Channel from bot login url.</param>
 /// <param name="toChannelFromBotOAuthScope">The to Channel from bot oauth scope.</param>
 /// <param name="toBotFromChannelTokenIssuer">The to bot from Channel Token Issuer.</param>
 /// <param name="oAuthUrl">The oAuth url.</param>
 /// <param name="toBotFromChannelOpenIdMetadataUrl">The to bot from Channel Open Id Metadata url.</param>
 /// <param name="toBotFromEmulatorOpenIdMetadataUrl">The to bot from Emulator Open Id Metadata url.</param>
 /// <param name="callerId">The Microsoft app password.</param>
 /// <param name="credentialFactory">The IServiceClientCredentialsFactory to use to create credentials.</param>
 /// <param name="authConfiguration">The AuthenticationConfiguration to use.</param>
 /// <param name="httpClient">The HttpClient to use.</param>
 /// <param name="logger">The ILogger instance to use.</param>
 /// <returns>A new cloud environment.</returns>
 public static BotFrameworkAuthentication Create(
     string channelService,
     bool validateAuthority,
     string toChannelFromBotLoginUrl,
     string toChannelFromBotOAuthScope,
     string toBotFromChannelTokenIssuer,
     string oAuthUrl,
     string toBotFromChannelOpenIdMetadataUrl,
     string toBotFromEmulatorOpenIdMetadataUrl,
     string callerId,
     ServiceClientCredentialsFactory credentialFactory,
     AuthenticationConfiguration authConfiguration,
     HttpClient httpClient,
     ILogger logger)
 {
     if (string.IsNullOrEmpty(channelService))
     {
         return(new PublicCloudBotFrameworkAuthentication(credentialFactory, authConfiguration, httpClient, logger));
     }
     else if (channelService == GovernmentAuthenticationConstants.ChannelService)
     {
         return(new GovernmentCloudBotFrameworkAuthentication(credentialFactory, authConfiguration, httpClient, logger));
     }
     else
     {
         return(new ParameterizedBotFrameworkAuthentication(
                    channelService,
                    validateAuthority,
                    toChannelFromBotLoginUrl,
                    toChannelFromBotOAuthScope,
                    toBotFromChannelTokenIssuer,
                    oAuthUrl,
                    toBotFromChannelOpenIdMetadataUrl,
                    toBotFromEmulatorOpenIdMetadataUrl,
                    callerId,
                    credentialFactory,
                    authConfiguration,
                    httpClient,
                    logger));
     }
 }
Пример #11
0
        // The following code is based on SkillValidation.AuthenticateChannelToken
        private async Task <ClaimsIdentity> SkillValidation_AuthenticateChannelTokenAsync(string authHeader, ServiceClientCredentialsFactory credentialFactory, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfiguration, CancellationToken cancellationToken)
        {
            var tokenValidationParameters =
                new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuers   = new[]
                {
                    // TODO: presumably this table should also come from configuration
                    "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/",               // Auth v3.1, 1.0 token
                    "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0", // Auth v3.1, 2.0 token
                    "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",               // Auth v3.2, 1.0 token
                    "https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0", // Auth v3.2, 2.0 token
                    "https://sts.windows.net/cab8a31a-1906-4287-a0d8-4eef66b95f6e/",               // Auth for US Gov, 1.0 token
                    "https://login.microsoftonline.us/cab8a31a-1906-4287-a0d8-4eef66b95f6e/v2.0"   // Auth for US Gov, 2.0 token
                },
                ValidateAudience    = false,                                                       // Audience validation takes place manually in code.
                ValidateLifetime    = true,
                ClockSkew           = TimeSpan.FromMinutes(5),
                RequireSignedTokens = true
            };

            // TODO: what should the openIdMetadataUrl be here?
            var tokenExtractor = new JwtTokenExtractor(
                httpClient,
                tokenValidationParameters,
                _toBotFromEmulatorOpenIdMetadataUrl,
                AuthenticationConstants.AllowedSigningAlgorithms);

            var identity = await tokenExtractor.GetIdentityAsync(authHeader, channelId, authConfiguration.RequiredEndorsements).ConfigureAwait(false);

            await SkillValidation_ValidateIdentityAsync(identity, credentialFactory, cancellationToken).ConfigureAwait(false);

            return(identity);
        }
        // The following code is based on JwtTokenValidation.AuthenticateRequest
        private async Task <ClaimsIdentity> JwtTokenValidation_AuthenticateRequestAsync(Activity activity, string authHeader, ServiceClientCredentialsFactory credentialFactory, AuthenticationConfiguration authConfiguration, HttpClient httpClient, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(authHeader))
            {
                var isAuthDisabled = await credentialFactory.IsAuthenticationDisabledAsync(cancellationToken).ConfigureAwait(false);

                if (isAuthDisabled)
                {
                    // In the scenario where Auth is disabled, we still want to have the
                    // IsAuthenticated flag set in the ClaimsIdentity. To do this requires
                    // adding in an empty claim.
                    return(new ClaimsIdentity(new List <Claim>(), "anonymous"));
                }

                // No Auth Header. Auth is required. Request is not authorized.
                throw new UnauthorizedAccessException();
            }

            var claimsIdentity = await JwtTokenValidation_ValidateAuthHeaderAsync(authHeader, credentialFactory, activity.ChannelId, authConfiguration, activity.ServiceUrl, httpClient, cancellationToken).ConfigureAwait(false);

            AppCredentials.TrustServiceUrl(activity.ServiceUrl);

            return(claimsIdentity);
        }
 public DelegatingCredentialProvider(ServiceClientCredentialsFactory credentialFactory)
 {
     _credentialFactory = credentialFactory ?? throw new ArgumentNullException(nameof(credentialFactory));
 }
Пример #14
0
        private async Task GovernmentChannelValidation_ValidateIdentityAsync(ClaimsIdentity identity, ServiceClientCredentialsFactory credentialFactory, string serviceUrl, CancellationToken cancellationToken)
        {
            if (identity == null)
            {
                // No valid identity. Not Authorized.
                throw new UnauthorizedAccessException();
            }

            if (!identity.IsAuthenticated)
            {
                // The token is in some way invalid. Not Authorized.
                throw new UnauthorizedAccessException();
            }

            // Now check that the AppID in the claimset 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
            var audienceClaim = identity.Claims.FirstOrDefault(
                c => c.Issuer == _toBotFromChannelTokenIssuer && c.Type == AuthenticationConstants.AudienceClaim);

            if (audienceClaim == null)
            {
                // The relevant audience Claim MUST be present. Not Authorized.
                throw new UnauthorizedAccessException();
            }

            // 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.
            var appIdFromClaim = audienceClaim.Value;

            if (string.IsNullOrWhiteSpace(appIdFromClaim))
            {
                // Claim is present, but doesn't have a value. Not Authorized.
                throw new UnauthorizedAccessException();
            }

            if (!await credentialFactory.IsValidAppIdAsync(appIdFromClaim, cancellationToken).ConfigureAwait(false))
            {
                // The AppId is not valid. Not Authorized.
                throw new UnauthorizedAccessException($"Invalid AppId passed on token: {appIdFromClaim}");
            }

            if (serviceUrl != null)
            {
                var serviceUrlClaim = identity.Claims.FirstOrDefault(claim => claim.Type == AuthenticationConstants.ServiceUrlClaim)?.Value;
                if (string.IsNullOrWhiteSpace(serviceUrlClaim))
                {
                    // Claim must be present. Not Authorized.
                    throw new UnauthorizedAccessException();
                }

                if (!string.Equals(serviceUrlClaim, serviceUrl, StringComparison.OrdinalIgnoreCase))
                {
                    // Claim must match. Not Authorized.
                    throw new UnauthorizedAccessException();
                }
            }
        }
Пример #15
0
        // The following code is based on GovernmentChannelValidation.AuthenticateChannelToken

        private async Task <ClaimsIdentity> GovernmentChannelValidation_AuthenticateChannelTokenAsync(string authHeader, ServiceClientCredentialsFactory credentialFactory, string serviceUrl, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig, CancellationToken cancellationToken)
        {
            var tokenValidationParameters = GovernmentChannelValidation_GetTokenValidationParameters();

            var tokenExtractor = new JwtTokenExtractor(
                httpClient,
                tokenValidationParameters,
                _toBotFromChannelOpenIdMetadataUrl,
                AuthenticationConstants.AllowedSigningAlgorithms);

            var identity = await tokenExtractor.GetIdentityAsync(authHeader, channelId, authConfig.RequiredEndorsements).ConfigureAwait(false);

            await GovernmentChannelValidation_ValidateIdentityAsync(identity, credentialFactory, serviceUrl, cancellationToken).ConfigureAwait(false);

            return(identity);
        }
Пример #16
0
        // The following code is based on EmulatorValidation.AuthenticateEmulatorToken
        private async Task <ClaimsIdentity> EmulatorValidation_AuthenticateEmulatorTokenAsync(string authHeader, ServiceClientCredentialsFactory credentialFactory, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfiguration, CancellationToken cancellationToken)
        {
            var toBotFromEmulatorTokenValidationParameters =
                new TokenValidationParameters()
            {
                ValidateIssuer = true,
                ValidIssuers   = new[]
                {
                    // TODO: presumably this table should also come from configuration
                    "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/",               // Auth v3.1, 1.0 token
                    "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0", // Auth v3.1, 2.0 token
                    "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",               // Auth v3.2, 1.0 token
                    "https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0", // Auth v3.2, 2.0 token
                    "https://sts.windows.net/cab8a31a-1906-4287-a0d8-4eef66b95f6e/",               // Auth for US Gov, 1.0 token
                    "https://login.microsoftonline.us/cab8a31a-1906-4287-a0d8-4eef66b95f6e/v2.0",  // Auth for US Gov, 2.0 token
                },
                ValidateAudience    = false,                                                       // Audience validation takes place manually in code.
                ValidateLifetime    = true,
                ClockSkew           = TimeSpan.FromMinutes(5),
                RequireSignedTokens = true,
            };

            var tokenExtractor = new JwtTokenExtractor(
                httpClient,
                toBotFromEmulatorTokenValidationParameters,
                _toBotFromEmulatorOpenIdMetadataUrl,
                AuthenticationConstants.AllowedSigningAlgorithms);

            var identity = await tokenExtractor.GetIdentityAsync(authHeader, channelId, authConfiguration.RequiredEndorsements).ConfigureAwait(false);

            if (identity == null)
            {
                // No valid identity. Not Authorized.
                throw new UnauthorizedAccessException("Invalid Identity");
            }

            if (!identity.IsAuthenticated)
            {
                // The token is in some way invalid. Not Authorized.
                throw new UnauthorizedAccessException("Token Not Authenticated");
            }

            // Now check that the AppID in the claimset 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.
            Claim versionClaim = identity.Claims.FirstOrDefault(c => c.Type == AuthenticationConstants.VersionClaim);

            if (versionClaim == null)
            {
                throw new UnauthorizedAccessException("'ver' claim is required on Emulator Tokens.");
            }

            string tokenVersion = versionClaim.Value;
            string appID        = string.Empty;

            // The Emulator, depending on Version, sends the AppId via either the
            // appid claim (Version 1) or the Authorized Party claim (Version 2).
            if (string.IsNullOrWhiteSpace(tokenVersion) || tokenVersion == "1.0")
            {
                // either no Version or a version of "1.0" means we should look for
                // the claim in the "appid" claim.
                Claim appIdClaim = identity.Claims.FirstOrDefault(c => c.Type == AuthenticationConstants.AppIdClaim);
                if (appIdClaim == null)
                {
                    // No claim around AppID. Not Authorized.
                    throw new UnauthorizedAccessException("'appid' claim is required on Emulator Token version '1.0'.");
                }

                appID = appIdClaim.Value;
            }
            else if (tokenVersion == "2.0")
            {
                // Emulator, "2.0" puts the AppId in the "azp" claim.
                Claim appZClaim = identity.Claims.FirstOrDefault(c => c.Type == AuthenticationConstants.AuthorizedParty);
                if (appZClaim == null)
                {
                    // No claim around AppID. Not Authorized.
                    throw new UnauthorizedAccessException("'azp' claim is required on Emulator Token version '2.0'.");
                }

                appID = appZClaim.Value;
            }
            else
            {
                // Unknown Version. Not Authorized.
                throw new UnauthorizedAccessException($"Unknown Emulator Token version '{tokenVersion}'.");
            }

            if (!await credentialFactory.IsValidAppIdAsync(appID, cancellationToken).ConfigureAwait(false))
            {
                throw new UnauthorizedAccessException($"Invalid AppId passed on token: {appID}");
            }

            return(identity);
        }
Пример #17
0
        private async Task SkillValidation_ValidateIdentityAsync(ClaimsIdentity identity, ServiceClientCredentialsFactory credentialFactory, CancellationToken cancellationToken)
        {
            if (identity == null)
            {
                // No valid identity. Not Authorized.
                throw new UnauthorizedAccessException("Invalid Identity");
            }

            if (!identity.IsAuthenticated)
            {
                // The token is in some way invalid. Not Authorized.
                throw new UnauthorizedAccessException("Token Not Authenticated");
            }

            var versionClaim = identity.Claims.FirstOrDefault(c => c.Type == AuthenticationConstants.VersionClaim);

            if (versionClaim == null)
            {
                // No version claim
                throw new UnauthorizedAccessException($"'{AuthenticationConstants.VersionClaim}' claim is required on skill Tokens.");
            }

            // Look for the "aud" claim, but only if issued from the Bot Framework
            var audienceClaim = identity.Claims.FirstOrDefault(c => c.Type == AuthenticationConstants.AudienceClaim)?.Value;

            if (string.IsNullOrWhiteSpace(audienceClaim))
            {
                // Claim is not present or doesn't have a value. Not Authorized.
                throw new UnauthorizedAccessException($"'{AuthenticationConstants.AudienceClaim}' claim is required on skill Tokens.");
            }

            if (!await credentialFactory.IsValidAppIdAsync(audienceClaim, cancellationToken).ConfigureAwait(false))
            {
                // The AppId is not valid. Not Authorized.
                throw new UnauthorizedAccessException("Invalid audience.");
            }

            var appId = JwtTokenValidation.GetAppIdFromClaims(identity.Claims);

            if (string.IsNullOrWhiteSpace(appId))
            {
                // Invalid appId
                throw new UnauthorizedAccessException("Invalid appId.");
            }
        }
Пример #18
0
        private async Task <ClaimsIdentity> JwtTokenValidation_AuthenticateTokenAsync(string authHeader, ServiceClientCredentialsFactory credentialFactory, string channelId, AuthenticationConfiguration authConfiguration, string serviceUrl, HttpClient httpClient, CancellationToken cancellationToken)
        {
            if (SkillValidation.IsSkillToken(authHeader))
            {
                return(await SkillValidation_AuthenticateChannelTokenAsync(authHeader, credentialFactory, httpClient, channelId, authConfiguration, cancellationToken).ConfigureAwait(false));
            }

            if (EmulatorValidation.IsTokenFromEmulator(authHeader))
            {
                return(await EmulatorValidation_AuthenticateEmulatorTokenAsync(authHeader, credentialFactory, httpClient, channelId, authConfiguration, cancellationToken).ConfigureAwait(false));
            }

            return(await GovernmentChannelValidation_AuthenticateChannelTokenAsync(authHeader, credentialFactory, serviceUrl, httpClient, channelId, authConfiguration, cancellationToken).ConfigureAwait(false));
        }
Пример #19
0
        private async Task <ClaimsIdentity> JwtTokenValidation_ValidateAuthHeaderAsync(string authHeader, ServiceClientCredentialsFactory credentialFactory, string channelId, AuthenticationConfiguration authConfiguration, string serviceUrl, HttpClient httpClient, CancellationToken cancellationToken)
        {
            var identity = await JwtTokenValidation_AuthenticateTokenAsync(authHeader, credentialFactory, channelId, authConfiguration, serviceUrl, httpClient, cancellationToken).ConfigureAwait(false);

            await JwtTokenValidation_ValidateClaimsAsync(authConfiguration, identity.Claims).ConfigureAwait(false);

            return(identity);
        }
Пример #20
0
        // The following code is based on JwtTokenValidation.AuthenticateRequest
        private async Task <ClaimsIdentity> JwtTokenValidation_AuthenticateRequestAsync(Activity activity, string authHeader, ServiceClientCredentialsFactory credentialFactory, AuthenticationConfiguration authConfiguration, HttpClient httpClient, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(authHeader))
            {
                var isAuthDisabled = await credentialFactory.IsAuthenticationDisabledAsync(cancellationToken).ConfigureAwait(false);

                if (!isAuthDisabled)
                {
                    // No Auth Header. Auth is required. Request is not authorized.
                    throw new UnauthorizedAccessException();
                }

                // Check if the activity is for a skill call and is coming from the Emulator.
                if (activity.ChannelId == Channels.Emulator && activity.Recipient?.Role == RoleTypes.Skill)
                {
                    // Return an anonymous claim with an anonymous skill AppId
                    return(SkillValidation.CreateAnonymousSkillClaim());
                }

                // In the scenario where Auth is disabled, we still want to have the
                // IsAuthenticated flag set in the ClaimsIdentity. To do this requires
                // adding in an empty claim.
                return(new ClaimsIdentity(new List <Claim>(), AuthenticationConstants.AnonymousAuthType));
            }

            // Validate the header and extract claims.
            var claimsIdentity = await JwtTokenValidation_ValidateAuthHeaderAsync(authHeader, credentialFactory, activity.ChannelId, authConfiguration, activity.ServiceUrl, httpClient, cancellationToken).ConfigureAwait(false);

            AppCredentials.TrustServiceUrl(activity.ServiceUrl);
            return(claimsIdentity);
        }