Example #1
0
        public void CreateAnonymousSkillClaimTest()
        {
            var sut = SkillValidation.CreateAnonymousSkillClaim();

            Assert.Equal(AuthenticationConstants.AnonymousSkillAppId, JwtTokenValidation.GetAppIdFromClaims(sut.Claims));
            Assert.Equal(AuthenticationConstants.AnonymousAuthType, sut.AuthenticationType);
        }
        public async Task <(bool IsAuthenticated, string ErrorMessage)> Validate(HttpRequest request)
        {
            if (!request.Headers.TryGetValue("Authorization", out StringValues authorizationHeader))
            {
                return(false, "Missing 'Authorization' header");
            }

            var credential = new SimpleCredentialProvider(
                _configuration.GetValue <string>("Bot:Id"),
                _configuration.GetValue <string>("Bot:Password"));

            try
            {
                var claimsIdentity = await JwtTokenValidation.ValidateAuthHeader(authorizationHeader, credential, null, null);

                if (!claimsIdentity.IsAuthenticated)
                {
                    return(false, "The request fails to pass auth check.");
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to check authentication.");
                return(false, $"Failed to check authentication: {ex.Message}");
            }

            return(true, string.Empty);
        }
Example #3
0
        public async Task <IActionResult> BotMessages(string instanceId, int routeCounter)
        {
            if (routeCounter > 1)
            {
                // Node is gone. Return 404, bot should queue messages until the connection is reestablished.
                return(NotFound());
            }

            IActionResult result;

            if (instanceId == _instanceId)
            {
                // This is the node with the web socket, send the message
                var activity = await HttpHelper.ReadRequestAsync <Activity>(Request);

                var authHeader     = Request.Headers["Authorization"];
                var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _channelProvider);

                var resultTcs = new TaskCompletionSource <ResourceResponse>();
                if (!_replyBuffer.Post(Tuple.Create(activity, resultTcs)))
                {
                    return(new InternalServerErrorResult());
                }
                var receiveResponse = await resultTcs.Task;
                result = Ok();
            }
            else
            {
                // The websocket is on another node, route to it
                result = await RerouteAsync(instanceId, routeCounter);
            }

            return(result);
        }
Example #4
0
        /// <summary>
        /// This method can be called from inside a POST method on any Controller implementation.  If the activity is Not an Invoke, and
        /// DeliveryMode is Not ExpectReplies, and this is NOT a Get request to upgrade to WebSockets, then the activity will be enqueued
        /// to be processed on a background thread.
        /// </summary>
        /// <remarks>
        /// Note, this is an ImmediateAccept and BackgroundProcessing override of:
        /// Task IBotFrameworkHttpAdapter.ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken = default);
        /// </remarks>
        /// <param name="httpRequest">The HTTP request object, typically in a POST handler by a Controller.</param>
        /// <param name="httpResponse">The HTTP response object.</param>
        /// <param name="bot">The bot implementation.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive
        ///     notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        async Task IBotFrameworkHttpAdapter.ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken = default)
        {
            if (httpRequest == null)
            {
                throw new ArgumentNullException(nameof(httpRequest));
            }

            if (httpResponse == null)
            {
                throw new ArgumentNullException(nameof(httpResponse));
            }

            if (bot == null)
            {
                throw new ArgumentNullException(nameof(bot));
            }

            // Get is a socket exchange request, so should be processed by base BotFrameworkHttpAdapter
            if (httpRequest.Method == HttpMethods.Get)
            {
                await base.ProcessAsync(httpRequest, httpResponse, bot, cancellationToken);
            }
            else
            {
                // Deserialize the incoming Activity
                var activity = await HttpHelper.ReadRequestAsync <Activity>(httpRequest).ConfigureAwait(false);

                if (string.IsNullOrEmpty(activity?.Type))
                {
                    httpResponse.StatusCode = (int)HttpStatusCode.BadRequest;
                }
                else if (activity.Type == ActivityTypes.Invoke || activity.DeliveryMode == DeliveryModes.ExpectReplies)
                {
                    // NOTE: Invoke and ExpectReplies cannot be performed async, the response must be written before the calling thread is released.
                    await base.ProcessAsync(httpRequest, httpResponse, bot, cancellationToken);
                }
                else
                {
                    // Grab the auth header from the inbound http request
                    var authHeader = httpRequest.Headers["Authorization"];

                    try
                    {
                        // If authentication passes, queue a work item to process the inbound activity with the bot
                        var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, CredentialProvider, ChannelProvider, HttpClient).ConfigureAwait(false);

                        // Queue the activity to be processed by the ActivityBackgroundService
                        _activityTaskQueue.QueueBackgroundActivity(claimsIdentity, activity);

                        // Activity has been queued to process, so return Ok immediately
                        httpResponse.StatusCode = (int)HttpStatusCode.OK;
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // handle unauthorized here as this layer creates the http response
                        httpResponse.StatusCode = (int)HttpStatusCode.Unauthorized;
                    }
                }
            }
        }
Example #5
0
        /// <summary>
        /// Creates a turn context and runs the middleware pipeline for an incoming activity.
        /// </summary>
        /// <param name="authHeader">The HTTP authentication header of the request.</param>
        /// <param name="activity">The incoming activity.</param>
        /// <param name="callback">The code to run at the end of the adapter's middleware
        /// pipeline.</param>
        /// <returns>A task that represents the work queued to execute. If the activity type
        /// was 'Invoke' and the corresponding key (channelId + activityId) was found
        /// then an InvokeResponse is returned, otherwise null is returned.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="activity"/> is <c>null</c>.</exception>
        /// <exception cref="UnauthorizedAccessException">
        /// authentication failed.</exception>
        /// <remarks>Call this method to reactively send a message to a conversation.
        /// <para>This method registers the following services for the turn.<list type="bullet">
        /// <item><see cref="IIdentity"/> (key = "BotIdentity"), a claims identity for the bot.</item>
        /// <item><see cref="IConnectorClient"/>, the channel connector client to use this turn.</item>
        /// </list></para>
        /// </remarks>
        /// <seealso cref="ContinueConversation(string, ConversationReference, Func{ITurnContext, Task})"/>
        /// <seealso cref="BotAdapter.RunPipeline(ITurnContext, Func{ITurnContext, Task}, System.Threading.CancellationTokenSource)"/>
        public async Task <InvokeResponse> ProcessActivity(string authHeader, Activity activity, Func <ITurnContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);
            var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient);

            using (var context = new TurnContext(this, activity))
            {
                context.Services.Add <IIdentity>("BotIdentity", claimsIdentity);
                var connectorClient = await this.CreateConnectorClientAsync(activity.ServiceUrl, claimsIdentity);

                context.Services.Add <IConnectorClient>(connectorClient);
                await base.RunPipeline(context, callback).ConfigureAwait(false);

                // Handle Invoke scenarios, which deviate from the request/response model in that
                // the Bot will return a specific body and return code.
                if (activity.Type == ActivityTypes.Invoke)
                {
                    Activity invokeResponse = context.Services.Get <Activity>(InvokeReponseKey);
                    if (invokeResponse == null)
                    {
                        // ToDo: Trace Here
                        throw new InvalidOperationException("Bot failed to return a valid 'invokeResponse' activity.");
                    }
                    else
                    {
                        return((InvokeResponse)invokeResponse.Value);
                    }
                }

                // For all non-invoke scenarios, the HTTP layers above don't have to mess
                // withthe Body and return codes.
                return(null);
            }
        }
 public static void SetDependency(ref IServiceCollection services, InternalApiCredential internalApiCredential, string authenticationInternalUrl,
                                  JwtTokenSettings jwtTokenSettings, JwtTokenValidation jwtTokenValidation)
 {
     services.AddSingleton <IBusinessApiAuthentication>(a => new BusinessApiAuthentication(internalApiCredential));
     services.AddScoped <IBusinessAuthentications>(a => new BusinessAuthentications(jwtTokenSettings, jwtTokenValidation));
     services.AddScoped <IBusinessUsers>(a => new BusinessUsers(a.GetService <IBusinessApiAuthentication>(), authenticationInternalUrl));
 }
Example #7
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
            ILogger logger,
            ExecutionContext context)
        {
            logger.LogInformation("Messages function received a request.");

            ISettings            settings            = new Settings(logger, context);
            IClippySetRepository clippySetRepository = new ClippySetRepository(logger, settings);
            IClippySetIndexer    clippySetIndexer    = new ClippySetIndexer(logger);
            ICredentialProvider  credentialProvider  = new SimpleCredentialProvider(settings.MicrosoftAppId, null);
            IChannelProvider     channelProvider     = new SimpleChannelProvider();

            Activity activity;

            try
            {
                var authorizationHeader = GetAuthorizationHeader(req);
                activity = await ParseRequestBody(req);

                await JwtTokenValidation.AuthenticateRequest(activity, authorizationHeader, credentialProvider, channelProvider);
            }
            catch (JsonReaderException e)
            {
                logger.LogDebug(e, "JSON parser failed to parse request payload.");
                return(new BadRequestResult());
            }
            catch (UnauthorizedAccessException e)
            {
                logger.LogDebug(e, "Request was not propertly authorized.");
                return(new UnauthorizedResult());
            }

            if (!activity.IsComposeExtensionQuery())
            {
                logger.LogDebug("Request payload was not a compose extension query.");
                return(new BadRequestObjectResult($"Clippy only supports compose extension query activity types."));
            }

            var queryValue = JObject.FromObject(activity.Value).ToObject <ComposeExtensionValue>();
            var query      = queryValue.GetParameterValue();

            var clippySet = await clippySetRepository.FetchClippySetAsync();

            await clippySetIndexer.IndexClippySetAsync(clippySet);

            var clippies = await clippySetIndexer.FindClippiesByQuery(query);

            var result = new ComposeExtensionResponse
            {
                ComposeExtensionResult = new ComposeExtensionResult
                {
                    Type             = "result",
                    AttachmentLayout = "grid",
                    Attachments      = clippies.Select(clippy => new ClippyComposeExtensionCard(clippy).ToAttachment()).ToArray()
                }
            };

            return(new OkObjectResult(result));
        }
Example #8
0
        /// <summary>
        /// This method is called from JwtTokenValidation.ValidateClaimsAsync
        /// </summary>
        /// <param name="claims"></param>
        public override Task ValidateClaimsAsync(IList <Claim> claims)
        {
            if (claims == null)
            {
                throw new ArgumentNullException(nameof(claims));
            }

            if (!claims.Any())
            {
                throw new UnauthorizedAccessException("ValidateClaimsAsync.claims parameter must contain at least one element.");
            }

            if (SkillValidation.IsSkillClaim(claims))
            {
                // if _allowedCallers has one item of '*', allow all parent bot calls and do not validate the appid from claims
                if (_allowedCallers.Count == 1 && _allowedCallers[0] == "*")
                {
                    return(Task.CompletedTask);
                }

                // Check that the appId claim in the skill request is in the list of skills configured for this bot.
                var appId = JwtTokenValidation.GetAppIdFromClaims(claims).ToUpperInvariant();
                if (_allowedCallers.Contains(appId))
                {
                    return(Task.CompletedTask);
                }

                throw new UnauthorizedAccessException($"Received a request from a bot with an app ID of \"{appId}\". To enable requests from this caller, add the app ID to your configuration file.");
            }

            throw new UnauthorizedAccessException($"ValidateClaimsAsync called without a Skill claim in claims.");
        }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            try
            {
                if (await Options.CredentialProvider.IsAuthenticationDisabledAsync())
                {
                    var anonymousPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Role, "Bot") }));
                    var anonynousContext   = new TokenValidatedContext(Context, Scheme, Options)
                    {
                        Principal = anonymousPrincipal
                    };
                    anonynousContext.Success();
                    return(anonynousContext.Result);
                }

                string         authHeader     = Request.Headers["Authorization"];
                ClaimsIdentity claimsIdentity = await JwtTokenValidation.ValidateAuthHeader(authHeader, Options.CredentialProvider, _httpClient);

                Logger.TokenValidationSucceeded();

                claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "Bot"));
                var principal = new ClaimsPrincipal(claimsIdentity);

                Context.User = principal;
                string jwtToken = JwtTokenExtractor.ExtractBearerTokenFromAuthHeader(authHeader);
                var    tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options)
                {
                    Principal     = principal,
                    SecurityToken = new JwtSecurityToken(jwtToken)
                };

                await Events.TokenValidated(tokenValidatedContext);

                if (tokenValidatedContext.Result != null)
                {
                    return(tokenValidatedContext.Result);
                }

                tokenValidatedContext.Success();
                return(tokenValidatedContext.Result);
            }
            catch (Exception ex)
            {
                Logger.ErrorProcessingMessage(ex);

                var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
                {
                    Exception = ex
                };

                await Events.AuthenticationFailed(authenticationFailedContext);

                if (authenticationFailedContext.Result != null)
                {
                    return(authenticationFailedContext.Result);
                }

                throw;
            }
        }
Example #10
0
        private async Task <ResourceResponse> ProcessActivityAsync(ClaimsIdentity claimsIdentity, string conversationId, string replyToActivityId, Activity activity, CancellationToken cancellationToken)
        {
            SkillConversationReference skillConversationReference;

            try
            {
                skillConversationReference = await _conversationIdFactory.GetSkillConversationReferenceAsync(conversationId, cancellationToken).ConfigureAwait(false);
            }
            catch (NotImplementedException)
            {
                // Attempt to get SkillConversationReference using deprecated method.
                // this catch should be removed once we remove the deprecated method.
                // We need to use the deprecated method for backward compatibility.
#pragma warning disable 618
                var conversationReference = await _conversationIdFactory.GetConversationReferenceAsync(conversationId, cancellationToken).ConfigureAwait(false);

#pragma warning restore 618
                skillConversationReference = new SkillConversationReference
                {
                    ConversationReference = conversationReference,
                    OAuthScope            = ChannelProvider != null && ChannelProvider.IsGovernment() ? GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope : AuthenticationConstants.ToChannelFromBotOAuthScope
                };
            }

            if (skillConversationReference == null)
            {
                throw new KeyNotFoundException();
            }

            ResourceResponse resourceResponse = null;

            var callback = new BotCallbackHandler(async(turnContext, ct) =>
            {
                turnContext.TurnState.Add(SkillConversationReferenceKey, skillConversationReference);
                activity.ApplyConversationReference(skillConversationReference.ConversationReference);
                turnContext.Activity.Id       = replyToActivityId;
                turnContext.Activity.CallerId = $"{CallerIdConstants.BotToBotPrefix}{JwtTokenValidation.GetAppIdFromClaims(claimsIdentity.Claims)}";
                switch (activity.Type)
                {
                case ActivityTypes.EndOfConversation:
                    await _conversationIdFactory.DeleteConversationReferenceAsync(conversationId, cancellationToken).ConfigureAwait(false);
                    ApplyEoCToTurnContextActivity(turnContext, activity);
                    await _bot.OnTurnAsync(turnContext, ct).ConfigureAwait(false);
                    break;

                case ActivityTypes.Event:
                    ApplyEventToTurnContextActivity(turnContext, activity);
                    await _bot.OnTurnAsync(turnContext, ct).ConfigureAwait(false);
                    break;

                default:
                    resourceResponse = await turnContext.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
                    break;
                }
            });

            await _adapter.ContinueConversationAsync(claimsIdentity, skillConversationReference.ConversationReference, skillConversationReference.OAuthScope, callback, cancellationToken).ConfigureAwait(false);

            return(resourceResponse ?? new ResourceResponse(Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)));
        }
Example #11
0
        /// <summary>
        /// Creates the connector client asynchronous.
        /// </summary>
        /// <param name="serviceUrl">The service URL.</param>
        /// <param name="claimsIdentity">The claims identity.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <returns>ConnectorClient instance.</returns>
        /// <exception cref="NotSupportedException">ClaimsIdentity cannot be null. Pass Anonymous ClaimsIdentity if authentication is turned off.</exception>
        private async Task <IConnectorClient> CreateConnectorClientAsync(string serviceUrl, ClaimsIdentity claimsIdentity, CancellationToken cancellationToken)
        {
            if (claimsIdentity == null)
            {
                throw new NotSupportedException("ClaimsIdentity cannot be null. Pass Anonymous ClaimsIdentity if authentication is turned off.");
            }

            // For requests from channel App Id is in Audience claim of JWT token. For emulator it is in AppId claim. For
            // unauthenticated requests we have anonymous identity provided auth is disabled.
            // For Activities coming from Emulator AppId claim contains the Bot's AAD AppId.
            var botAppIdClaim = claimsIdentity.Claims?.SingleOrDefault(claim => claim.Type == AuthenticationConstants.AudienceClaim);

            if (botAppIdClaim == null)
            {
                botAppIdClaim = claimsIdentity.Claims?.SingleOrDefault(claim => claim.Type == AuthenticationConstants.AppIdClaim);
            }

            // For anonymous requests (requests with no header) appId is not set in claims.
            AppCredentials appCredentials = null;

            if (botAppIdClaim != null)
            {
                var    botId = botAppIdClaim.Value;
                string scope = null;
                if (SkillValidation.IsSkillClaim(claimsIdentity.Claims))
                {
                    // The skill connector has the target skill in the OAuthScope.
                    scope = JwtTokenValidation.GetAppIdFromClaims(claimsIdentity.Claims);
                }

                appCredentials = await GetAppCredentialsAsync(botId, scope, cancellationToken).ConfigureAwait(false);
            }

            return(CreateConnectorClient(serviceUrl, appCredentials));
        }
        public void GetAppIdFromClaimsTests()
        {
            var v1Claims = new List <Claim>();
            var v2Claims = new List <Claim>();
            var appId    = Guid.NewGuid().ToString();

            // Empty list
            Assert.Null(JwtTokenValidation.GetAppIdFromClaims(v1Claims));

            // AppId there but no version (assumes v1)
            v1Claims.Add(new Claim(AuthenticationConstants.AppIdClaim, appId));
            Assert.Equal(appId, JwtTokenValidation.GetAppIdFromClaims(v1Claims));

            // AppId there with v1 version
            v1Claims.Add(new Claim(AuthenticationConstants.VersionClaim, "1.0"));
            Assert.Equal(appId, JwtTokenValidation.GetAppIdFromClaims(v1Claims));

            // v2 version but no azp
            v2Claims.Add(new Claim(AuthenticationConstants.VersionClaim, "2.0"));
            Assert.Null(JwtTokenValidation.GetAppIdFromClaims(v2Claims));

            // v2 version with azp
            v2Claims.Add(new Claim(AuthenticationConstants.AuthorizedParty, appId));
            Assert.Equal(appId, JwtTokenValidation.GetAppIdFromClaims(v2Claims));
        }
        public async Task ValidateClaimsTest()
        {
            var claims            = new List <Claim>();
            var defaultAuthConfig = new AuthenticationConfiguration();

            // No validator should pass.
            await JwtTokenValidation.ValidateClaimsAsync(defaultAuthConfig, claims);

            var mockValidator = new Mock <ClaimsValidator>();
            var authConfigWithClaimsValidator = new AuthenticationConfiguration()
            {
                ClaimsValidator = mockValidator.Object
            };

            // ClaimsValidator configured but no exception should pass.
            mockValidator.Setup(x => x.ValidateClaimsAsync(It.IsAny <List <Claim> >())).Returns(Task.CompletedTask);
            await JwtTokenValidation.ValidateClaimsAsync(authConfigWithClaimsValidator, claims);

            // Configure IClaimsValidator to fail
            mockValidator.Setup(x => x.ValidateClaimsAsync(It.IsAny <List <Claim> >())).Throws(new UnauthorizedAccessException("Invalid claims."));
            var exception = await Assert.ThrowsAsync <UnauthorizedAccessException>(
                async() => await JwtTokenValidation.ValidateClaimsAsync(authConfigWithClaimsValidator, claims));

            Assert.Equal("Invalid claims.", exception.Message);
        }
Example #14
0
        private async Task <ResourceResponse> ProcessActivityAsync(ClaimsIdentity claimsIdentity, string conversationId, string replyToActivityId, Activity activity, CancellationToken cancellationToken)
        {
            var skillConversationReference = await GetSkillConversationReferenceAsync(conversationId, cancellationToken).ConfigureAwait(false);

            ResourceResponse resourceResponse = null;

            var callback = new BotCallbackHandler(async(turnContext, ct) =>
            {
                turnContext.TurnState.Add(SkillConversationReferenceKey, skillConversationReference);
                activity.ApplyConversationReference(skillConversationReference.ConversationReference);
                turnContext.Activity.Id       = replyToActivityId;
                turnContext.Activity.CallerId = $"{CallerIdConstants.BotToBotPrefix}{JwtTokenValidation.GetAppIdFromClaims(claimsIdentity.Claims)}";
                switch (activity.Type)
                {
                case ActivityTypes.EndOfConversation:
                    await _conversationIdFactory.DeleteConversationReferenceAsync(conversationId, cancellationToken).ConfigureAwait(false);
                    ApplyEoCToTurnContextActivity(turnContext, activity);
                    await _bot.OnTurnAsync(turnContext, ct).ConfigureAwait(false);
                    break;

                case ActivityTypes.Event:
                    ApplyEventToTurnContextActivity(turnContext, activity);
                    await _bot.OnTurnAsync(turnContext, ct).ConfigureAwait(false);
                    break;

                default:
                    resourceResponse = await turnContext.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
                    break;
                }
            });

            await _adapter.ContinueConversationAsync(claimsIdentity, skillConversationReference.ConversationReference, skillConversationReference.OAuthScope, callback, cancellationToken).ConfigureAwait(false);

            return(resourceResponse ?? new ResourceResponse(Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)));
        }
        public async Task ProcessActivty(string authHeader, Activity activity, Func <IBotContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);
            await JwtTokenValidation.AssertValidActivity(activity, authHeader, _credentialProvider, _httpClient);

            await base.ProcessActivityInternal(activity, callback).ConfigureAwait(false);
        }
        public async Task <IActionResult> Post([FromBody] Activity activity)
        {
            // Validate Authorization Header. Should be a jwt token.
            var authHeader = this.Request.Headers["Authorization"].SingleOrDefault();

            try
            {
                await JwtTokenValidation.AssertValidActivity(activity, authHeader, this.credentials);
            }
            catch (UnauthorizedAccessException)
            {
                return(this.Unauthorized());
            }

            // On message activity, reply with the same text
            if (activity.Type == ActivityTypes.Message)
            {
                var reply = activity.CreateReply($"You said: {activity.Text}");

                // Reply to Activity using Connector
                var connector = new ConnectorClient(
                    new Uri(activity.ServiceUrl, UriKind.Absolute),
                    new MicrosoftAppCredentials(this.credentials.AppId, this.credentials.Password));

                await connector.Conversations.ReplyToActivityAsync(reply);
            }

            return(this.Ok());
        }
 public async void Emulator_MsaHeader_BotAppIdDiffers_ShouldNotValidate()
 {
     string header      = $"Bearer {await new MicrosoftAppCredentials("2cd87869-38a0-4182-9251-d056e8f0ac24", "2.30Vs3VQLKt974F").GetTokenAsync()}";
     var    credentials = new SimpleCredentialProvider("00000000-0000-0000-0000-000000000000", "");
     await Assert.ThrowsAsync <UnauthorizedAccessException>(
         async() => await JwtTokenValidation.ValidateAuthHeader(header, credentials, "", null, emptyClient));
 }
        public async void EmptyHeader_BotWithNoCredentials_ShouldValidate()
        {
            var header      = "";
            var credentials = new SimpleCredentialProvider("", "");
            var result      = await JwtTokenValidation.ValidateAuthHeader(header, credentials, "");

            Assert.True(result.IsAuthenticated);
        }
        public async void EmptyHeader_BotWithNoCredentials_ShouldThrow()
        {
            var header      = string.Empty;
            var credentials = new SimpleCredentialProvider(string.Empty, string.Empty);

            await Assert.ThrowsAsync <ArgumentNullException>(
                async() => await JwtTokenValidation.ValidateAuthHeader(header, credentials, new SimpleChannelProvider(), string.Empty, null, emptyClient));
        }
        private async Task JwtTokenValidation_ValidateAuthHeader_WithChannelService_Succeeds(string header, string appId, string pwd, string channelService)
        {
            var credentials = new SimpleCredentialProvider(appId, pwd);
            var channel     = new SimpleChannelProvider(channelService);
            var result      = await JwtTokenValidation.ValidateAuthHeader(header, credentials, channel, string.Empty, "https://webchat.botframework.com/", client);

            Assert.True(result.IsAuthenticated);
        }
        public async void Emulator_MsaHeader_BotAppIdDiffers_ShouldNotValidate()
        {
            var header      = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlNTUWRoSTFjS3ZoUUVEU0p4RTJnR1lzNDBRMCIsImtpZCI6IlNTUWRoSTFjS3ZoUUVEU0p4RTJnR1lzNDBRMCJ9.eyJhdWQiOiIzOTYxOWE1OS01YTBjLTRmOWItODdjNS04MTZjNjQ4ZmYzNTciLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9kNmQ0OTQyMC1mMzliLTRkZjctYTFkYy1kNTlhOTM1ODcxZGIvIiwiaWF0IjoxNTE4MTIzMTQxLCJuYmYiOjE1MTgxMjMxNDEsImV4cCI6MTUxODEyNzA0MSwiYWlvIjoiWTJOZ1lQZ1djOSsrenJvaW9QM28rZmw2OWR1c0FBPT0iLCJhcHBpZCI6IjM5NjE5YTU5LTVhMGMtNGY5Yi04N2M1LTgxNmM2NDhmZjM1NyIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2Q2ZDQ5NDIwLWYzOWItNGRmNy1hMWRjLWQ1OWE5MzU4NzFkYi8iLCJ0aWQiOiJkNmQ0OTQyMC1mMzliLTRkZjctYTFkYy1kNTlhOTM1ODcxZGIiLCJ1dGkiOiJPVXE3M1lSbGtFcVoxQ3p2U3FZQkFBIiwidmVyIjoiMS4wIn0.B0t4sSsqIQ3IT2rfpZXqAdAGJSr3aihwk-jJd8as2pAoeQVcQNir_Anvvnjbo5MsB0DCyWFa9xnEmBRiTW_Ww97Z9bZhnCXq4D4vN8dmgEMV_Aci1tI4agy3coCX4fBRc76SHjqJ_ucl850aqR3d_0sfl0TPoDclE4jWssX2YTNzUAMEgisbYe9xv8FfK7AUR8ABS1teTfnWGVYyVFgC7vptSjw-de8sgz7pv8vVtLEKBrrb1FBSzHbbnZ-cQaLLHeIM4agamXf4w45o7_1uHorrp1Tg5oPrsbiayC-dt4lpC9smU5agpyUWCorKZI0Fp3aryG4519cYuLyXuUVh0A";
            var credentials = new SimpleCredentialProvider("00000000-0000-0000-0000-000000000000", "");

            await Assert.ThrowsAsync <UnauthorizedAccessException>(
                async() => await JwtTokenValidation.ValidateAuthHeader(header, credentials, ""));
        }
        public async void Connector_AuthHeader_BotAppIdDiffers_ShouldNotValidate()
        {
            var header      = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkdDeEFyWG9OOFNxbzdQd2VBNy16NjVkZW5KUSIsIng1dCI6IkdDeEFyWG9OOFNxbzdQd2VBNy16NjVkZW5KUSJ9.eyJzZXJ2aWNldXJsIjoiaHR0cHM6Ly93ZWJjaGF0LmJvdGZyYW1ld29yay5jb20vIiwiaXNzIjoiaHR0cHM6Ly9hcGkuYm90ZnJhbWV3b3JrLmNvbSIsImF1ZCI6IjM5NjE5YTU5LTVhMGMtNGY5Yi04N2M1LTgxNmM2NDhmZjM1NyIsImV4cCI6MTUxNjczNzUyMCwibmJmIjoxNTE2NzM2OTIwfQ.TBgpxbDS-gx1wm7ldvl7To-igfskccNhp-rU1mxUMtGaDjnsU--usH4OXZfzRsZqMlnXWXug_Hgd_qOr5RH8wVlnXnMWewoZTSGZrfp8GOd7jHF13Gz3F1GCl8akc3jeK0Ppc8R_uInpuUKa0SopY0lwpDclCmvDlz4PN6yahHkt_666k-9UGmRt0DDkxuYjbuYG8EDZxyyAhr7J6sFh3yE2UGRpJjRDB4wXWqv08Cp0Gn9PAW2NxOyN8irFzZH5_YZqE3DXDAYZ_IOLpygXQR0O-bFIhLDVxSz6uCeTBRjh8GU7XJ_yNiRDoaby7Rd2IfRrSnvMkBRsB8MsWN8oXg";
            var credentials = new SimpleCredentialProvider("00000000-0000-0000-0000-000000000000", "");

            await Assert.ThrowsAsync <UnauthorizedAccessException>(
                async() => await JwtTokenValidation.ValidateAuthHeader(header, credentials, "https://webchat.botframework.com/"));
        }
        public async void Emulator_MsaHeader_CorrectAppIdAndServiceUrl_ShouldValidate()
        {
            string header      = $"Bearer {await new MicrosoftAppCredentials("2cd87869-38a0-4182-9251-d056e8f0ac24", "2.30Vs3VQLKt974F").GetTokenAsync()}";
            var    credentials = new SimpleCredentialProvider("2cd87869-38a0-4182-9251-d056e8f0ac24", "");
            var    result      = await JwtTokenValidation.ValidateAuthHeader(header, credentials, "", "https://webchat.botframework.com/", emptyClient);

            Assert.True(result.IsAuthenticated);
        }
        /// <summary>
        /// Creates a turn context and runs the middleware pipeline for an incoming activity.
        /// </summary>
        /// <param name="authHeader">The HTTP authentication header of the request.</param>
        /// <param name="activity">The incoming activity.</param>
        /// <param name="callback">The code to run at the end of the adapter's middleware pipeline.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute. If the activity type
        /// was 'Invoke' and the corresponding key (channelId + activityId) was found
        /// then an InvokeResponse is returned, otherwise null is returned.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="activity"/> is <c>null</c>.</exception>
        /// <exception cref="UnauthorizedAccessException">authentication failed.</exception>
        /// <remarks>Call this method to reactively send a message to a conversation.
        /// If the task completes successfully, then if the activity's <see cref="Activity.Type"/>
        /// is <see cref="ActivityTypes.Invoke"/> and the corresponding key
        /// (<see cref="Activity.ChannelId"/> + <see cref="Activity.Id"/>) is found
        /// then an <see cref="InvokeResponse"/> is returned, otherwise null is returned.
        /// <para>This method registers the following services for the turn.<list type="bullet">
        /// <item><see cref="IIdentity"/> (key = "BotIdentity"), a claims identity for the bot.</item>
        /// <item><see cref="IConnectorClient"/>, the channel connector client to use this turn.</item>
        /// </list></para>
        /// </remarks>
        /// <seealso cref="ContinueConversationAsync(string, ConversationReference, BotCallbackHandler, CancellationToken)"/>
        /// <seealso cref="BotAdapter.RunPipelineAsync(ITurnContext, BotCallbackHandler, CancellationToken)"/>
        public async Task <InvokeResponse> ProcessActivityAsync(string authHeader, Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken)
        {
            BotAssert.ActivityNotNull(activity);

            var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _channelProvider, _httpClient).ConfigureAwait(false);

            return(await ProcessActivityAsync(claimsIdentity, activity, callback, cancellationToken).ConfigureAwait(false));
        }
        public async void Connector_AuthHeader_CorrectAppIdAndServiceUrl_ShouldValidate()
        {
            var header      = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkdDeEFyWG9OOFNxbzdQd2VBNy16NjVkZW5KUSIsIng1dCI6IkdDeEFyWG9OOFNxbzdQd2VBNy16NjVkZW5KUSJ9.eyJzZXJ2aWNldXJsIjoiaHR0cHM6Ly93ZWJjaGF0LmJvdGZyYW1ld29yay5jb20vIiwiaXNzIjoiaHR0cHM6Ly9hcGkuYm90ZnJhbWV3b3JrLmNvbSIsImF1ZCI6IjM5NjE5YTU5LTVhMGMtNGY5Yi04N2M1LTgxNmM2NDhmZjM1NyIsImV4cCI6MTUxNjczNzUyMCwibmJmIjoxNTE2NzM2OTIwfQ.TBgpxbDS-gx1wm7ldvl7To-igfskccNhp-rU1mxUMtGaDjnsU--usH4OXZfzRsZqMlnXWXug_Hgd_qOr5RH8wVlnXnMWewoZTSGZrfp8GOd7jHF13Gz3F1GCl8akc3jeK0Ppc8R_uInpuUKa0SopY0lwpDclCmvDlz4PN6yahHkt_666k-9UGmRt0DDkxuYjbuYG8EDZxyyAhr7J6sFh3yE2UGRpJjRDB4wXWqv08Cp0Gn9PAW2NxOyN8irFzZH5_YZqE3DXDAYZ_IOLpygXQR0O-bFIhLDVxSz6uCeTBRjh8GU7XJ_yNiRDoaby7Rd2IfRrSnvMkBRsB8MsWN8oXg";
            var credentials = new SimpleCredentialProvider("39619a59-5a0c-4f9b-87c5-816c648ff357", "");
            var result      = await JwtTokenValidation.ValidateAuthHeader(header, credentials, client);

            Assert.True(result.IsAuthenticated);
        }
        /// <summary>
        /// Creates a turn context and runs the middleware pipeline for an incoming activity.
        /// </summary>
        /// <param name="authHeader">The HTTP authentication header of the request.</param>
        /// <param name="activity">The incoming activity.</param>
        /// <param name="callback">The code to run at the end of the adapter's middleware
        /// pipeline.</param>
        /// <returns>A task that represents the work queued to execute. If the activity type
        /// was 'Invoke' and the corresponding key (channelId + activityId) was found
        /// then an InvokeResponse is returned, otherwise null is returned.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="activity"/> is <c>null</c>.</exception>
        /// <exception cref="UnauthorizedAccessException">
        /// authentication failed.</exception>
        /// <remarks>Call this method to reactively send a message to a conversation.
        /// <para>This method registers the following services for the turn.<list type="bullet">
        /// <item><see cref="IIdentity"/> (key = "BotIdentity"), a claims identity for the bot.</item>
        /// <item><see cref="IConnectorClient"/>, the channel connector client to use this turn.</item>
        /// </list></para>
        /// </remarks>
        /// <seealso cref="ContinueConversation(string, ConversationReference, Func{ITurnContext, Task})"/>
        /// <seealso cref="BotAdapter.RunPipeline(ITurnContext, Func{ITurnContext, Task})"/>
        public async Task <InvokeResponse> ProcessActivity(string authHeader, Activity activity, Func <ITurnContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);

            var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient).ConfigureAwait(false);

            return(await ProcessActivity(claimsIdentity, activity, callback).ConfigureAwait(false));
        }
        public async Task AuthenticateSetsAnonymousSkillClaim()
        {
            var sut = new TestChannelServiceHandler();
            await sut.HandleReplyToActivityAsync(null, "123", "456", new Activity(), CancellationToken.None);

            Assert.Equal(AuthenticationConstants.AnonymousAuthType, sut.ClaimsIdentity.AuthenticationType);
            Assert.Equal(AuthenticationConstants.AnonymousSkillAppId, JwtTokenValidation.GetAppIdFromClaims(sut.ClaimsIdentity.Claims));
        }
        public async void Connector_AuthHeader_BotWithNoCredentials_ShouldNotValidate()
        {
            // token received and auth disabled
            string header      = $"Bearer {await new MicrosoftAppCredentials("2cd87869-38a0-4182-9251-d056e8f0ac24", "2.30Vs3VQLKt974F").GetTokenAsync()}";
            var    credentials = new SimpleCredentialProvider("", "");

            await Assert.ThrowsAsync <UnauthorizedAccessException>(
                async() => await JwtTokenValidation.ValidateAuthHeader(header, credentials, "", null, client));
        }
Example #29
0
        public async Task Receive(string authHeader, Activity activity)
        {
            BotAssert.ActivityNotNull(activity);
            await JwtTokenValidation.AssertValidActivity(activity, authHeader, _credentialProvider, _httpClient);

            if (this.OnReceive != null)
            {
                await OnReceive(activity).ConfigureAwait(false);
            }
        }
        private BotFrameworkSkill GetCallingSkill(ClaimsIdentity claimsIdentity)
        {
            var appId = JwtTokenValidation.GetAppIdFromClaims(claimsIdentity.Claims);

            if (string.IsNullOrWhiteSpace(appId))
            {
                return(null);
            }

            return(_skillsConfig.Skills.Values.FirstOrDefault(s => string.Equals(s.AppId, appId, StringComparison.InvariantCultureIgnoreCase)));
        }