简体   繁体   English

Azure B2C 自定义策略 Rest API 客户端证书

[英]Azure B2C Custom Policy Rest API Client Certificate

I have a custom policy that I created to call a rest api to do some custom user verification.我创建了一个自定义策略来调用 rest api 来执行一些自定义用户验证。 I have that working, I log into my site via the B2C custom policy and my rest api is called like it should.我有这个工作,我通过 B2C 自定义策略登录到我的网站,我的 rest api 被称为应该的。 Now that I have it working, I would like to secure it so that only the B2C custom policy is able to make that call to that particular controller/method.现在我已经开始工作了,我想保护它,以便只有 B2C 自定义策略能够调用那个特定的控制器/方法。 I've read the documentation on securing the rest api ( Secure your API Connector ), I created a self-signed certificate, uploaded the certificate to the IEF policy and updated my rest api technical profile.我已阅读有关保护 rest api( 保护您的 API 连接器)的文档,我创建了一个自签名证书,将证书上传到 IEF 策略并更新了我的 rest api 技术资料。 What I can't figure out is how to add/use the certificate (.pxf) inside my Blazor server application.我想不通的是如何在我的 Blazor 服务器应用程序中添加/使用证书 (.pxf)。 All the documentation I've found so far is all Azure B2C, not how to tie all this together?到目前为止我找到的所有文档都是 Azure B2C,而不是如何将所有这些联系在一起? Any guidance would be greatly appreciated.任何指导将不胜感激。

My appsettings.json我的 appsettings.json

"AzureAdB2C": {
    "Instance": "https://my-tenant.b2clogin.com",
    "ClientId": "[guid]",
    "CallbackPath": "/signin-oidc",
    "Domain": "my-tenant.onmicrosoft.com",
    "SignedOutCallbackPath": "/signout",
    "SignUpSignInPolicyId": "B2C_1A_custom_signup_signin",
    "ResetPasswordPolicyId": "B2C_1_password_reset",
    "EditProfilePolicyId": "",
    "ClientSecret": "my-secret-key"
}

My Configure Services我的配置服务

public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddSingleton<WeatherForecastService>();

        services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdB2C"));
        
        services.AddControllersWithViews().AddMicrosoftIdentityUI();

        services.AddServerSideBlazor().AddMicrosoftIdentityConsentHandler();
    }

My custom claim provider我的自定义索赔提供者

<ClaimsProvider>
  <DisplayName>REST APIs</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="REST-GetProfile">
      <DisplayName>Get user extended profile Azure Function web hook</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <Metadata>
        <!-- Set the ServiceUrl with your own REST API endpoint -->
        <Item Key="ServiceUrl">https://my.azurewebsites.com/api/Validate</Item>
        <Item Key="SendClaimsIn">Body</Item>
        <!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
        <Item Key="AuthenticationType">ClientCertificate</Item>
        <!-- REMOVE the following line in production environments -->
        <Item Key="AllowInsecureAuthInProduction">false</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="ClientCertificate" StorageReferenceId="B2C_1A_RestApiClientCertificate" />
      </CryptographicKeys>
      <InputClaims>
        <!-- Claims sent to your REST API -->
        <InputClaim ClaimTypeReferenceId="objectId" />
        <InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email"/>
        <InputClaim ClaimTypeReferenceId="userLanguage" PartnerClaimType="lang" DefaultValue="{Culture:LCID}" AlwaysUseDefaultValue="true" />
      </InputClaims>
      <OutputClaims>
        <!-- Claims parsed from your REST API -->
        <OutputClaim ClaimTypeReferenceId="IsValid" />
      </OutputClaims>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

I've made a little bit of progress.我已经取得了一点进步。 I created a Certification Validation Service:我创建了一个认证验证服务:

public class MyCertificateValidationService
{
    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        var cert = new X509Certificate2( Path.Combine( @"..\MyCertificate.pfx" ), "[password]");
        Console.WriteLine($"cert.Thumbprint: {cert.Thumbprint}{Environment.NewLine}clientCertificate.Thumbprint");
        if (clientCertificate.Thumbprint == cert.Thumbprint)
        {
            return true;
        }

        return false;
    }
}

And updated my ConfigureServices:并更新了我的 ConfigureServices:

    public void ConfigureServices( IServiceCollection services )
    {
        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddSingleton<WeatherForecastService>();

        services.AddAuthentication( OpenIdConnectDefaults.AuthenticationScheme )
            .AddMicrosoftIdentityWebApp( Configuration.GetSection( "AzureAdB2C" ) );

        services.AddAuthentication( CertificateAuthenticationDefaults.AuthenticationScheme )
            .AddCertificate( options =>
             {
                 options.AllowedCertificateTypes = CertificateTypes.All;
                 options.Events = new CertificateAuthenticationEvents
                 {
                     OnCertificateValidated = context =>
                     {
                         var validationService = context.HttpContext.RequestServices
                             .GetRequiredService<MyCertificateValidationService>();

                         if( validationService.ValidateCertificate( context.ClientCertificate ) )
                         {
                             var claims = new[]
                             {
                                new Claim(
                                    ClaimTypes.NameIdentifier,
                                    context.ClientCertificate.Subject,
                                    ClaimValueTypes.String,
                                    context.Options.ClaimsIssuer),
                                new Claim(ClaimTypes.Name,
                                    context.ClientCertificate.Subject,
                                    ClaimValueTypes.String,
                                    context.Options.ClaimsIssuer)
                             };

                             context.Principal = new ClaimsPrincipal(
                                 new ClaimsIdentity( claims, context.Scheme.Name ) );
                             context.Success();
                         }

                         return Task.CompletedTask;
                     }
                 };
             } )
            // Adding an ICertificateValidationCache results in certificate auth caching the results.
            // The default implementation uses a memory cache.
            .AddCertificateCache();

        services.AddControllersWithViews().AddMicrosoftIdentityUI();

        services.AddServerSideBlazor().AddMicrosoftIdentityConsentHandler();
    }

Now when I try and call my rest api, I get the following error:现在,当我尝试拨打我的 rest api 时,出现以下错误:

AADB2C90028: Client certificate specified for 'REST-GetProfile' is invalid. AADB2C90028:为“REST-GetProfile”指定的客户端证书无效。 Check that the certificate is correct, contains a private key and that access has been granted by the resource.检查证书是否正确、是否包含私钥以及资源是否已授予访问权限。 Correlation ID: [guid] Timestamp: 2021-05-13 14:10:15Z相关 ID:[guid] 时间戳:2021-05-13 14:10:15Z

Any ideas of things I could check or try?我可以检查或尝试的事情有什么想法吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM