Starałem się, aby PyJWT 1.1.0 zweryfikować JWT z kluczem publicznym. Klucze te są domyślnie dostarczane z Keycloak. Najprawdopodobniej problem jest związany z tworzeniem tajnego klucza, ale nie znalazłem żadnych przykładów tworzenia klucza bez certyfikatu z kluczem prywatnym i publicznym.Jak zweryfikować JWT za pomocą python PyJWT z kluczem publicznym
Oto moje próby, aby to działało. Niektóre z poniższych testów narzekają na nieprawidłowy klucz, a niektóre z nich narzekają, że token nie został poprawnie zweryfikowany w odniesieniu do klucza.
import jwt
from cryptography.hazmat.backends import default_backend
from itsdangerous import base64_decode
from Crypto.PublicKey import RSA
secret = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIE6a1NyEFe7qCDFrvWFZiAlY1ttE5596w5dLjNSaHlKGv8AXbKg/f8yKY9fKAJ5BKoeWEkPPjpn1t9QQAZYzqH9KNOFigMU8pSaRUxjI2dDvwmu8ZH6EExY+RfrPjQGmeliK18iFzFgBtf0eH3NAW3Pf71OZZz+cuNnVtE9lrYQIDAQAB"
secretDer = base64_decode(secret)
sshrsaSecret = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCIE6a1NyEFe7qCDFrvWFZiAlY1ttE5596w5dLjNSaHlKGv8AXbKg/f8yKY9fKAJ5BKoeWEkPPjpn1t9QQAZYzqH9KNOFigMU8pSaRUxjI2dDvwmu8ZH6EExY+RfrPjQGmeliK18iFzFgBtf0eH3NAW3Pf71OZZz+cuNnVtE9lrYQ=="
secretPEM = "-----BEGIN PUBLIC KEY-----\n" + secret + "\n-----END PUBLIC KEY-----"
access_token = "eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIzM2ZhZGYzMS04MzZmLTQzYWUtODM4MS01OGJhM2RhMDMwYTciLCJleHAiOjE0MjkwNzYyNTYsIm5iZiI6MCwiaWF0IjoxNDI5MDc2MTk2LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsInN1YiI6ImMzNWJlODAyLTcyOGUtNGMyNC1iMjQ1LTQxMWIwMDRmZTc2NSIsImF6cCI6InNlY3VyaXR5LWFkbWluLWNvbnNvbGUiLCJzZXNzaW9uX3N0YXRlIjoiYmRjOGM0ZDgtYzUwNy00MDQ2LWE4NDctYmRlY2QxNDVmZTNiIiwiY2xpZW50X3Nlc3Npb24iOiI0OTI5YmRjNi0xOWFhLTQ3MDYtYTU1Mi1lOWI0MGFhMDg5ZTYiLCJhbGxvd2VkLW9yaWdpbnMiOltdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiYWRtaW4iLCJjcmVhdGUtcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJtYXN0ZXItcmVhbG0iOnsicm9sZXMiOlsibWFuYWdlLWV2ZW50cyIsIm1hbmFnZS1jbGllbnRzIiwidmlldy1yZWFsbSIsInZpZXctZXZlbnRzIiwibWFuYWdlLWlkZW50aXR5LXByb3ZpZGVycyIsInZpZXctaWRlbnRpdHktcHJvdmlkZXJzIiwidmlldy11c2VycyIsInZpZXctY2xpZW50cyIsIm1hbmFnZS11c2VycyIsIm1hbmFnZS1yZWFsbSJdfX0sIm5hbWUiOiIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.O7e8dkv0k-2HCjMdZFXIxLhypVyRPwIdrQsYTMwC1996wbsjIw1L3OjDSzJKXcx0U9YrVeRM4yMVlFg40uJDC-9IsKZ8nr5dl_da8SzgpAkempxpas3girST2U9uvY56m2Spp6-EFInvMSb6k4t1L49_Q7R2g0DOlKzxgQd87LY"
############### Test using PEM key (with ----- lines)
try:
access_token_json = jwt.decode(access_token, key=secretPEM)
except Exception as e:
print "Not working using PEM key with ----: ", e
else:
print "It worked!"
############### Test using PEM key (without ----- lines)
try:
access_token_json = jwt.decode(access_token, key=secret)
except Exception as e:
print "Not working using PEM key without ----: ", e
else:
print "It worked!"
############### Test using DER key
try:
access_token_json = jwt.decode(access_token, key=secretDer)
except Exception as e:
print "Not working using DER key: ", e
else:
print "It worked!"
############### Test using DER key #2
try:
public_key = default_backend().load_der_public_key(secretDer)
access_token_json = jwt.decode(access_token, key=public_key)
except Exception as e:
print "Not working using DER key #2: ", e
else:
print "It worked!"
############### Test using SSH style key
try:
access_token_json = jwt.decode(access_token, key=sshrsaSecret)
except Exception as e:
print "Not working using SSH style key: ", e
else:
print "It worked!"
############### Test using RSA numbers
class Numbers:
pass
numbers = Numbers()
public_key = RSA.importKey(secretDer)
numbers.e = public_key.key.e
numbers.n = public_key.key.n
# yet another way to generated valid key object
public_key = default_backend().load_rsa_public_numbers(numbers)
print public_key
try:
access_token_json = jwt.decode(access_token, key=public_key)
except Exception as e:
print "Not working using RSA numbers: ", e
else:
print "It worked!"
###############
Sprawdziłem, czy token i klucz współpracują z implementacją Java, patrz poniżej.
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
public class JWTTest {
public static final void main(String[] argv) {
String token = "eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIzM2ZhZGYzMS04MzZmLTQzYWUtODM4MS01OGJhM2RhMDMwYTciLCJleHAiOjE0MjkwNzYyNTYsIm5iZiI6MCwiaWF0IjoxNDI5MDc2MTk2LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODEvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsInN1YiI6ImMzNWJlODAyLTcyOGUtNGMyNC1iMjQ1LTQxMWIwMDRmZTc2NSIsImF6cCI6InNlY3VyaXR5LWFkbWluLWNvbnNvbGUiLCJzZXNzaW9uX3N0YXRlIjoiYmRjOGM0ZDgtYzUwNy00MDQ2LWE4NDctYmRlY2QxNDVmZTNiIiwiY2xpZW50X3Nlc3Npb24iOiI0OTI5YmRjNi0xOWFhLTQ3MDYtYTU1Mi1lOWI0MGFhMDg5ZTYiLCJhbGxvd2VkLW9yaWdpbnMiOltdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiYWRtaW4iLCJjcmVhdGUtcmVhbG0iXX0sInJlc291cmNlX2FjY2VzcyI6eyJtYXN0ZXItcmVhbG0iOnsicm9sZXMiOlsibWFuYWdlLWV2ZW50cyIsIm1hbmFnZS1jbGllbnRzIiwidmlldy1yZWFsbSIsInZpZXctZXZlbnRzIiwibWFuYWdlLWlkZW50aXR5LXByb3ZpZGVycyIsInZpZXctaWRlbnRpdHktcHJvdmlkZXJzIiwidmlldy11c2VycyIsInZpZXctY2xpZW50cyIsIm1hbmFnZS11c2VycyIsIm1hbmFnZS1yZWFsbSJdfX0sIm5hbWUiOiIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.O7e8dkv0k-2HCjMdZFXIxLhypVyRPwIdrQsYTMwC1996wbsjIw1L3OjDSzJKXcx0U9YrVeRM4yMVlFg40uJDC-9IsKZ8nr5dl_da8SzgpAkempxpas3girST2U9uvY56m2Spp6-EFInvMSb6k4t1L49_Q7R2g0DOlKzxgQd87LY";
String key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHJUdDw1bPg/tZBY+kDDZZQnAp1mVr0CMyE+VzvJ+n2v6SHBdjjuWEw+LfLd69evg8ndr1RRPWZ1ryKgWS/NKTNqH+UhHkK9NToDucJI9Bi/scCpBps+/X/S7gZtcBMdfd4IB+LPCsP8v2RT/H9VjeCP4sWuqNwAMtCMyGr1Vw9wIDAQAB";
String verifierKey = "-----BEGIN PUBLIC KEY-----\n" + key + "\n-----END PUBLIC KEY-----";
SignatureVerifier verifier = new RsaVerifier(verifierKey);
System.out.println(JwtHelper.decodeAndVerify(token, verifier));
}
}
Aktualizacja: jestem w stanie podpisać token poprawnie z HS256 (zweryfikowane z http://jwt.io/) za pomocą następującego kodu. Nie mogę jednak rozszyfrować tokena podpisanego przez PyJWT przy użyciu PyJWT. Interfejs jest naprawdę dziwny. Oto przykład (tajemnica jest taka sama, jak w powyższych przykładach):
some_token = jwt.encode(access_token_json, secret)
# verified some_token to be valid with jwt.io
# the code below does not validate the token correctly
jwt.decode(some_token, key=secret)
Aktualizacja 2: Działa
from jwt.algorithms import HMACAlgorithm, RSAAlgorithm
access_token_json = jwt.decode(access_token, verify=False)
algo = HMACAlgorithm(HMACAlgorithm.SHA256)
shakey = algo.prepare_key(secret)
testtoken = jwt.encode(access_token_json, key=shakey, algorithm='HS256')
options={'verify_exp': False, # Skipping expiration date check
'verify_aud': False } # Skipping audience check
print jwt.decode(testtoken, key=shakey, options=options)
Jednak to nie
from jwt.algorithms import HMACAlgorithm, RSAAlgorithm
algo = RSAAlgorithm(RSAAlgorithm.SHA256)
shakey = algo.prepare_key(sshrsaSecret)
options={'verify_exp': False, # Skipping expiration date check
'verify_aud': False } # Skipping audience check
print jwt.decode(access_token, key=shakey, options=options)
Doskonała praca przy rozwiązywaniu własnego problemu. W celu uzyskania dalszych informacji zachęcamy do odpowiedzi na własne pytanie zamiast edytowania pola pytania http://stackoverflow.com/help/self-answer –
W aktualizacji 2 wydaje się, że dekodowanie działa po użyciu testtoken, ale w tym, który nie działa, jest to kod dostępu próbujący zostać zdekodowany. – Efren