параметр id_token_hint не прошел проверку подписи при использовании B2C для генерации конечных точек метаданных

#.net-core #metadata #openid-connect #azure-ad-b2c-custom-policy #self-signed-certificate

Вопрос:

Я пытаюсь настроить систему, подобную Magic link, с использованием Azure B2C. Используя следующие примеры: Первичный:
https://github.com/azure-ad-b2c/samples/tree/master/policies/sign-in-with-magic-link

Для того, чтобы sing B2C генерировал конечные точки метаданных: https://github.com/azure-ad-b2c/samples/tree/master/policies/invite#using-b2c-to-generate-the-metadata-endpoints

В качестве примечания я полагаю, что в какой-то момент он работал, но после очистки я получал ошибку:

Предоставленный параметр id_token_hint не прошел проверку подписи. Пожалуйста, укажите другой токен и повторите попытку.

Шаги, которые я предпринял для настройки, следующие:

  1. Создайте сертификат с помощью powershell и получите отпечаток пальца для использования в локальном коде
  2. Используйте certmng через MMC для экспорта сертификата
    • Все задачи / Экспорт / Следующий / Да, экспортируйте закрытый ключ
    • Обмен персональной информацией — PKCS (включить все сертификаты в путь к сертификату) (включить конфиденциальность сертификата)
  3. Безопасность (пароль) Случайно сгенерированный пароль из 25 символов.
  4. Имя: id_token_hint_cert.pfx
  5. Просмотрите Azure / B2C / Identity Experience Framework / Ключи политики
    • Добавить / Параметр: загрузить / Имя: IdTokenHintCert / Загрузка файла id_token_hint_cert.pfx / Пароль: пароль из программы установки 3

Здесь я попробовал 2 разные настройки. Первым делом нужно было настроить набор пользовательских политик, чтобы я мог обновить следующего поставщика утверждений, чтобы для issuer_secret было установлено значение B2C_1A_IdTokenHintCert

 <ClaimsProvider>
  <DisplayName>Token Issuer</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="JwtIssuer">
      <DisplayName>JWT Issuer</DisplayName>
      <Protocol Name="None" />
      <OutputTokenFormat>JWT</OutputTokenFormat>
      <Metadata>
        <Item Key="client_id">{service:te}</Item>
        <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
        <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="issuer_secret" StorageReferenceId="B2C_1A_IdTokenHintCert" />
        <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" />
      </CryptographicKeys>
      <InputClaims />
      <OutputClaims />
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>
 

Это набор политик, полученных из https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/tree/master/LocalAccounts и обновлен для моего арендатора, но оставлен в основном в покое.

Я также попытался изменить issuer_secret в своих основных пользовательских политиках с выводом той же ошибки.

Переход к моему коду: это важная часть моего запуска:

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(
            OpenIdConnectDefaults.AuthenticationScheme
        ).AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdB2C"),"OpenIdConnect", "Cookies",true);

        services.AddControllersWithViews();
        services.AddRazorPages() 
            .AddMicrosoftIdentityUI();

        

        services.AddTransient<IClaimsTransformation, AppClaimsTransformations>();
    }
 

И вот мой домашний контроллер, на котором я отправляю форму, создаю токен и ссылку, а затем просто перенаправляю на эту ссылку, используя ее в качестве конечной точки run now. (Я знаю, что это не закончится, но мне нужно проверить подпись, прежде чем я смогу двигаться дальше.)

 public class HomeController : Controller
{
    private static Lazy<X509SigningCredentials> SigningCredentials;
    private readonly AppSettingsModel _appSettings;
    private readonly IWebHostEnvironment HostingEnvironment;
    private readonly ILogger<HomeController> _logger;

    // Sample: Inject an instance of an AppSettingsModel class into the constructor of the consuming class, 
    // and let dependency injection handle the rest
    public HomeController(ILogger<HomeController> logger, IOptions<AppSettingsModel> appSettings, IWebHostEnvironment hostingEnvironment)
    {
        _appSettings = appSettings.Value;
        this.HostingEnvironment = hostingEnvironment;
        this._logger = logger;

        // Sample: Load the certificate with a private key (must be pfx file)
        SigningCredentials = new Lazy<X509SigningCredentials>(() =>
        {
            X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            certStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = certStore.Certificates.Find(
                                        X509FindType.FindByThumbprint,
                                        "***************************************",
                                        false);
            // Get the first cert with the thumb-print
            if (certCollection.Count > 0)
            {
                return new X509SigningCredentials(certCollection[0]);
            }

            throw new Exception("Certificate not found");
        });
    }

    [HttpGet]
    public ActionResult Index(string Name, string email, string phone)
    {

        if (string.IsNullOrEmpty(email))
        {
            ViewData["Message"] = "";
            return View();
        }

        string token = BuildIdToken(Name, email, phone);
        string link = BuildUrl(token);

        
        return Redirect(link);
    }


    private string BuildIdToken(string Name, string email, string phone)
    {
        string issuer = $"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase.Value}/";

        // All parameters send to Azure AD B2C needs to be sent as claims
        IList<System.Security.Claims.Claim> claims = new List<System.Security.Claims.Claim>();
        claims.Add(new System.Security.Claims.Claim("name", Name, System.Security.Claims.ClaimValueTypes.String, issuer));
        claims.Add(new System.Security.Claims.Claim("email", email, System.Security.Claims.ClaimValueTypes.String, issuer));

        if (!string.IsNullOrEmpty(phone))
        {
            claims.Add(new System.Security.Claims.Claim("phone", phone, System.Security.Claims.ClaimValueTypes.String, issuer));
        }

        // Create the token
        JwtSecurityToken token = new JwtSecurityToken(
                issuer,
                "******************************************",
                claims,
                DateTime.Now,
                DateTime.Now.AddDays(7),
                HomeController.SigningCredentials.Value);

        // Get the representation of the signed token
        JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();

        return jwtHandler.WriteToken(token);
    }

    private string BuildUrl(string token)
    {
        string nonce = Guid.NewGuid().ToString("n");

        return string.Format("https://{0}.b2clogin.com/{0}.onmicrosoft.com/{1}/oauth2/v2.0/authorize?client_id={2}amp;nonce={4}amp;redirect_uri={3}amp;scope=openidamp;response_type=id_token",
                "myTenant",
                "B2C_1A_SIGNIN_WITH_EMAIL",
                "************************************",
                Uri.EscapeDataString("https://jwt.ms"),
                nonce)
                      "amp;id_token_hint="   token;
    }

   
    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}
 

}

Ответ №1:

Местоположение Местоположение Местоположение.

Я настраивал базовый профиль, который, как я узнал, я не должен делать. Когда я применил свое изменение к файлу расширения, вместо этого все начало работать правильно.