Как исправить ошибку API "Недействительная подпись" при отправке запроса токена в потоке OpenID?

Я настраиваю поток OpenID для своего приложения и хочу протестировать аутентификацию сертификата клиента JWT с закрытым ключом с помощью Microsoft Active Directory. То есть я хочу использовать сертификат, а не секреты клиента для аутентификации моего приложения при запросе идентификаторов и токенов доступа. Однако при запросе токена я получаю следующую ошибку:

{
   "error":"invalid_client",
   "error_description":"AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Please visit 'https://developer.microsoft.com/en-us/graph/graph-explorer' and query for 'https://graph.microsoft.com/beta/applications/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' to see configured keys]\r\nTrace ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\nCorrelation ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\nTimestamp: 2019-09-26 22:24:19Z",
   "error_codes":[
      700027
   ],
   "timestamp":"2019-09-26 22:24:19Z",
   "trace_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
   "correlation_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
   "error_uri":"https://login.microsoftonline.com/error?code=700027"
}

Я генерирую закрытый ключ и сертификат с помощью следующей команды:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

Я загрузил cert.pem к моей регистрации приложения на лазурном портале.

В своем приложении я использую библиотеку Nimbus JOSE + JWT для создания JWT и Nimbus OAuth 2.0 SDK с расширениями OpenID Connect для управления потоком OpenID. Вот страницы документации Javadoc для каждого из этих пакетов соответственно:

Я проверил, что ключ и сертификат находятся в формате PEM, проверив, что они содержат -----BEGIN PRIVATE KEY----- а также -----BEGIN CERTIFICATE----- заголовки и соответствующие нижние колонтитулы.

В соответствии с ошибкой я посетил https://developer.microsoft.com/en-us/graph/graph-explorer, вошел в систему слева, а затем отправил запрос, используя данный неотредактированный URL-адрес. Это дало мне ошибку:

{
"error": {
    "code": "Request_ResourceNotFound",
    "message": "Resource 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' does not exist or one of its queried reference-property objects are not present.",
    "innerError": {
        "request-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "date": "2019-09-26T23:47:37"
    }
}

Моя текущая реализация выглядит следующим образом.

        val privateKeyString = File(keyFilePath).readText()
        val certificateString = File(certFilePath).readText()
        val certObject = JWK.parseFromPEMEncodedX509Cert(certificateString)
        val privateKeyJWK = JWK.parseFromPEMEncodedObjects(privateKeyString)
        val privateKey = RSAKey.parse(privateKeyJWK.toJSONObject())
        val privateKeyJWT = PrivateKeyJWT(
                ClientID(configuration.clientId), // clientId retrieved from the app reg on the azure portal
                providerMetadata.tokenEndpointURI, // login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/token
                JWSAlgorithm.RS256,
                privateKey.toRSAPrivateKey(),
                certObject.keyID,
                null)

        val tokenReq = TokenRequest(
                providerMetadata.tokenEndpointURI,
                privateKeyJWT,
                AuthorizationCodeGrant(authCode, // authCode received from previous step of the OpenID flow
                        URI(configuration.redirectURI)) // the application's login page. This has been registered in
                                                        // the app reg on the azure portal.
        )

        val tokenHTTPResponse: HTTPResponse? = tokenReq.toHTTPRequest().send()
        val tokenResponse = OIDCTokenResponse.parse(tokenHTTPResponse) // response fails with the described error

Есть несколько шагов, которые могут пойти не так, но я не смог их сузить:

  • Мое поколение ключей могло быть неправильным. Возможно, я использую ключ и сертификат не в ожидаемом формате?
  • Мой анализ ключей с помощью библиотеки Nimbus мог быть неправильным. Пошаговое выполнение кода во время запроса и проверка объектов данных, кажется, указывает на то, что он анализирует все компоненты из файла. Неясно, правильно ли он разбирает эти компоненты.
  • Моя конструкция закрытого ключа JWT может быть ошибочной.
  • Построение запроса токена может быть некорректным.
  • Конфигурация регистрации моего приложения на портале Azure может быть неправильной.

Мы будем очень благодарны за любые советы о том, как сузить круг вопросов или решить эту проблему!

2 ответа

Существует более простой способ сгенерировать JWK из библиотеки Nimbus JOSE+JWT:

https://connect2id.com/products/nimbus-jose-jwt/examples/jwk-generation

Ваш клиент OAuth 2.0 зарегистрирован для private_key_jwt аутентификация в конечной точке токена?

Простой ответ на вопрос, почему это не работает, заключается в том, что Azure Active Directory не поддерживает аутентификацию JWT с закрытым ключом. Написанный код работает, но только для служб, поддерживающих аутентификацию JWT с закрытым ключом.

Другие вопросы по тегам