Skip to content

Instantly share code, notes, and snippets.

@Maarten88
Last active September 8, 2017 14:30
Show Gist options
  • Save Maarten88/9aacc25368601a2d65b417dc90945440 to your computer and use it in GitHub Desktop.
Save Maarten88/9aacc25368601a2d65b417dc90945440 to your computer and use it in GitHub Desktop.
Microsoft Bot Framework Bot Authentication migrated to dotnet core 2.0
using System;
using Microsoft.Bot.Connector;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extension methods to add BotAuthentication capabilities to an HTTP application pipeline.
/// </summary>
public static class BotAuthenticationAppBuilderExtensions
{
public static AuthenticationBuilder AddBotAuthentication(this AuthenticationBuilder builder, string authenticationScheme, string microsoftAppId, string microsoftAppPassword)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (authenticationScheme != "Bearer")
{
throw new ArgumentNullException("AuthenticationScheme must be set to \"Bearer\"");
}
if (string.IsNullOrEmpty(microsoftAppId))
{
throw new ArgumentNullException(nameof(microsoftAppId));
}
if (string.IsNullOrEmpty(microsoftAppPassword))
{
throw new ArgumentNullException(nameof(microsoftAppPassword));
}
return builder
.AddScheme<BotAuthenticationSchemeOptions, BotAuthenticationHandler>(authenticationScheme, null, options =>
{
options.MicrosoftAppId = microsoftAppId;
options.MicrosoftAppPassword = microsoftAppPassword;
});
}
}
}
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using System.Text.Encodings.Web;
namespace Microsoft.Bot.Connector
{
/// <summary>
/// Bot authentication hanlder used by <see cref="BotAuthenticationHandler"/>.
/// </summary>
public sealed class BotAuthenticationHandler : AuthenticationHandler<BotAuthenticationSchemeOptions>
{
public BotAuthenticationHandler(IOptionsMonitor<BotAuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (await Options.CredentialProvider.IsAuthenticationDisabledAsync())
{
var principal = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Role, "Bot") }));
return AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), BotAuthenticationSchemeOptions.AuthenticationScheme));
}
string token = null;
string authorization = Request.Headers["Authorization"];
token = authorization?.Substring("Bearer ".Length).Trim();
// If no token found, no further work possible
// and Authentication is not disabled fail
if (string.IsNullOrEmpty(token))
{
return AuthenticateResult.Fail("No JwtToken is present and BotAuthentication is enabled!");
}
var authenticator = new BotAuthenticator(Options.CredentialProvider, Options.OpenIdConfiguration, Options.DisableEmulatorTokens);
var identityToken = await authenticator.TryAuthenticateAsync(BotAuthenticationSchemeOptions.AuthenticationScheme, token, CancellationToken.None);
if (identityToken.Authenticated)
{
identityToken.Identity.AddClaim(new Claim(ClaimTypes.Role, "Bot"));
var principal = new ClaimsPrincipal(identityToken.Identity);
var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), BotAuthenticationSchemeOptions.AuthenticationScheme);
Context.User = principal;
if (Options.SaveToken)
{
ticket.Properties.StoreTokens(new[]
{
new AuthenticationToken { Name = "access_token", Value = token }
});
}
return AuthenticateResult.Success(ticket);
}
else
{
return AuthenticateResult.Fail($"Failed to authenticate JwtToken {token}");
}
}
}
}
using Microsoft.AspNetCore.Authentication;
using System;
namespace Microsoft.Bot.Connector
{
/// <summary>
/// Options for <see cref="BotAuthenticationSchemeOptions"/>.
/// </summary>
public sealed class BotAuthenticationSchemeOptions : AuthenticationSchemeOptions
{
Lazy<ICredentialProvider> credentialProvider;
public BotAuthenticationSchemeOptions() : base()
{
this.credentialProvider = new Lazy<ICredentialProvider>(() => new StaticCredentialProvider(this.MicrosoftAppId, this.MicrosoftAppPassword));
}
public string MicrosoftAppId { get; set; }
public string MicrosoftAppPassword { get; set; }
/// <summary>
/// The <see cref="ICredentialProvider"/> used for authentication.
/// </summary>
public ICredentialProvider CredentialProvider
{
get
{
if (string.IsNullOrEmpty(this.MicrosoftAppId) || string.IsNullOrEmpty(this.MicrosoftAppId))
{
throw new ArgumentException("BotAuthenticationOptions: MicrosoftAppId and/or MicrosoftAppId missing");
}
return this.credentialProvider.Value;
}
}
public const string AuthenticationScheme = "Bearer";
/// <summary>
/// The OpenId configuation.
/// </summary>
public string OpenIdConfiguration { set; get; } = JwtConfig.ToBotFromChannelOpenIdMetadataUrl;
/// <summary>
/// Flag indicating if emulator tokens should be disabled.
/// </summary>
public bool DisableEmulatorTokens { set; get; } = false;
/// <summary>
/// Flag indicating if <see cref="BotAuthenticationHandler"/> should be stored in
/// the returned <see cref="Microsoft.AspNetCore.Authentication.AuthenticationTicket"/>.
/// </summary>
public bool SaveToken { set; get; } = true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment