Не удалось проверить токен доступа с помощью oidc-client-js и Apereo CAS

#javascript #reactjs #cas #openid-connect #oidc-client-js

#javascript #reactjs #cas #OpenID-подключиться #oidc-client-js

Вопрос:

Я пытаюсь войти с помощью Apereo CAS 5.1.1 в моем приложении react, используя OIDC. В поисках библиотек для достижения этой цели я остановился на oidc-client-js 1.7.0, но я сталкиваюсь со следующей ошибкой:

ResponseValidator._validateAccessToken: Не удалось проверить at_hash dWr5-bD5lv8C1x3VcfFn1Q dWr5 bD5lv8C1x3VcfFn1Q ==

Следуя трассировке, я обнаружил, где генерируется исключение

 var a = s.substr(0, s.length / 2), u = this._joseUtil.hexToBase64Url(a);

return u !== e.profile.at_hash ? 
(i.Log.error("ResponseValidator._validateAccessToken: Failed to validate at_hash", u, e.profile.at_hash), Promise.reject(new Error("Failed to validate at_hash"))) : 
(i.Log.debug("ResponseValidator._validateAccessToken: success"), Promise.resolve(e));
  

Проблема в том, что this._joseUtil.hexToBase64Url(a) не добавляется заполнение ( = ) и в данном конкретном случае знак. Это потому, что эти символы не принимаются в URL. Таким образом, сравнение всегда (или почти всегда) будет ложным. Например, в этом выполнении:

 dWr5-bD5lv8C1x3VcfFn1Q != dWr5 bD5lv8C1x3VcfFn1Q==
  

С другой стороны, я думаю, что в моем приложении что-то упущено или неправильно настроено, потому что в противном случае каждый пользователь, использующий эту библиотеку, столкнется с одной и той же проблемой.

Итак, мой вопрос: как я могу успешно проверить токен доступа в этом сценарии?

Спасибо.

Ответ №1:

Я обнаружил проблему, возникающую в коде обоих фрагментов кода, взаимодействующих для выполнения проверки.

Оказалось, что версия CAS, которую я использовал (5.1.1), имеет ошибку при создании хэш- at_hash значения токена доступа.

Класс org.apereo.cas.oidc.token.OidcIdTokenGeneratorService имеет следующий метод: generateAccessTokenHash . Последние строки кода, где он фактически генерирует хэш, являются:

 final byte[] digested = DigestUtils.rawDigest(hashAlg, tokenBytes);
final byte[] hashBytesLeftHalf = Arrays.copyOf(digested, digested.length / 2);
return EncodingUtils.encodeBase64(hashBytesLeftHalf);
  

Проблема в том, что он кодируется в base64, когда at_hash должен быть закодирован в base64url в соответствии с этим:

Хэш-значение токена доступа. Его значением является кодировка base64url самой левой половины хэша октетов ASCII-представления значения access_token, где используемый алгоритм хэширования является алгоритмом хэширования, используемым в параметре заголовка alg заголовка JOSE токена ID. Например, если alg равен RS256, хэшируйте значение access_token с помощью SHA-256, затем возьмите самые левые 128 бит и закодируйте их в base64url. Значение at_hash является строкой, чувствительной к регистру.

Эта проблема была решена в следующей версии CAS, по крайней мере, я могу подтвердить, что 5.2.x решила ее, изменив (среди прочего) последнюю строку на:

 return EncodingUtils.encodeUrlSafeBase64(hashBytesLeftHalf);
  

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