public async Task AcceptAllowedCallersArray(string allowedCallerClaimId, IList <string> allowList) { var validator = new AllowedSkillsClaimsValidator(allowList); if (allowedCallerClaimId != null) { var claims = CreateCallerClaims(allowedCallerClaimId); if (allowList != null) { if (allowList.Contains(allowedCallerClaimId) || allowList.Contains("*")) { await validator.ValidateClaimsAsync(claims); } else { await ValidateUnauthorizedAccessException(allowedCallerClaimId, validator, claims); } } else { await ValidateUnauthorizedAccessException(allowedCallerClaimId, validator, claims); } } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddNewtonsoftJson(); // Register the skills configuration class services.AddSingleton <SkillsConfiguration>(); // Register AuthConfiguration to enable custom claim validation. services.AddSingleton(sp => { var allowedSkills = sp.GetService <SkillsConfiguration>().Skills.Values.Select(s => s.AppId).ToList(); var claimsValidator = new AllowedSkillsClaimsValidator(allowedSkills); // If TenantId is specified in config, add the tenant as a valid JWT token issuer for Bot to Skill conversation. // The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered. var validTokenIssuers = new List <string>(); var tenantId = sp.GetService <IConfiguration>().GetSection(MicrosoftAppCredentials.MicrosoftAppTenantIdKey)?.Value; if (!string.IsNullOrWhiteSpace(tenantId)) { // For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant. // Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests. validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, tenantId)); validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, tenantId)); validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1, tenantId)); validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2, tenantId)); } return(new AuthenticationConfiguration { ClaimsValidator = claimsValidator, ValidTokenIssuers = validTokenIssuers }); }); // Create the Bot Framework Authentication to be used with the Bot Adapter. services.AddSingleton <BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>(); // Register the Bot Framework Adapter with error handling enabled. // Note: some classes use the base BotAdapter so we add an extra registration that pulls the same instance. services.AddSingleton <CloudAdapter, AdapterWithErrorHandler>(); services.AddSingleton <IBotFrameworkHttpAdapter>(sp => sp.GetService <CloudAdapter>()); services.AddSingleton <BotAdapter>(sp => sp.GetService <CloudAdapter>()); // Register the skills client and skills request handler. services.AddSingleton <SkillConversationIdFactoryBase, SkillConversationIdFactory>(); services.AddSingleton <ChannelServiceHandlerBase, CloudSkillHandler>(); // Register the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.) services.AddSingleton <IStorage, MemoryStorage>(); // Register Conversation state (used by the Dialog system itself). services.AddSingleton <ConversationState>(); // Register the bot as a transient. In this case the ASP Controller is expecting an IBot. services.AddTransient <IBot, RootBot>(); }
private static async Task ValidateUnauthorizedAccessException(string allowedCallerClaimId, AllowedSkillsClaimsValidator validator, List <Claim> claims) { Exception ex = await Assert.ThrowsAsync <UnauthorizedAccessException>(() => validator.ValidateClaimsAsync(claims)); Assert.Contains(allowedCallerClaimId, ex.Message); }