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); }
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); }
/// <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; } } } }
/// <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)); }
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)); }
/// <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; } }
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))); }
/// <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); }
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)); }
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))); }