From 8f7b2af21beda60d6123f555a0c21d2eadfc777a Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Fri, 20 Dec 2019 16:28:41 +0300 Subject: Sign In With Apple --- src/test/java/com/juick/JWTTest.java | 94 ++++++++++++++++++++++++++++++++++++ src/test/resources/testkey.p8 | 5 ++ 2 files changed, 99 insertions(+) create mode 100644 src/test/java/com/juick/JWTTest.java create mode 100644 src/test/resources/testkey.p8 (limited to 'src/test') diff --git a/src/test/java/com/juick/JWTTest.java b/src/test/java/com/juick/JWTTest.java new file mode 100644 index 00000000..1a6eeada --- /dev/null +++ b/src/test/java/com/juick/JWTTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008-2019, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick; + +import com.github.scribejava.apis.AppleClientSecretGenerator; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; +import org.apache.commons.io.FileUtils; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.interfaces.ECPrivateKey; +import org.bouncycastle.jce.interfaces.ECPublicKey; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; + +import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; + +public class JWTTest { + @Value("classpath:testkey.p8") + Resource p8key; + @Test + public void testAppleClientSecret() throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, NoSuchProviderException { + AppleClientSecretGenerator clientSecretGenerator = + new AppleClientSecretGenerator("example", "1", "2", p8key.getFilename()); + String secret = new String(clientSecretGenerator.getClientSecret().getBytes(), StandardCharsets.UTF_8); + String p8encodedData = FileUtils.readFileToString(new File(p8key.getFilename()), StandardCharsets.UTF_8); + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter(); + pemConverter.setProvider("BC"); + //EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(p8encodedData)); + // Strips the "---- {BEGIN,END} {CERTIFICATE,PUBLIC/PRIVATE KEY} -----"-like header and footer lines, + // base64-decodes the body, + // then uses the proper key specification format to turn it into a JCA Key instance + final Reader pemReader = new StringReader(p8encodedData); + final PEMParser parser = new PEMParser(pemReader); + PrivateKey privateKey; + Object pemObj = parser.readObject(); + + privateKey = pemConverter.getPrivateKey((PrivateKeyInfo) pemObj); + + +// Generate public key from private key + KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC"); + ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1"); + + ECPoint Q = ecSpec.getG().multiply(((ECPrivateKey)privateKey).getD()); + byte[] publicDerBytes = Q.getEncoded(false); + + ECPoint point = ecSpec.getCurve().decodePoint(publicDerBytes); + ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, ecSpec); + ECPublicKey publicKeyGenerated = (ECPublicKey) keyFactory.generatePublic(pubSpec); + + Jws jwt = Jwts.parser() + .setSigningKey(publicKeyGenerated) + .parseClaimsJws(secret); + assertThat(jwt.getHeader().get("kid"), is("2")); + assertThat(jwt.getHeader().get("alg"), is("ES256")); + Claims claims = (Claims)jwt.getBody(); + assertThat(claims.get("iss"), is("1")); + assertThat(claims.get("sub"), is("example")); + assertThat(claims.get("aud"), is("https://appleid.apple.com")); + } +} diff --git a/src/test/resources/testkey.p8 b/src/test/resources/testkey.p8 new file mode 100644 index 00000000..1e5d0f98 --- /dev/null +++ b/src/test/resources/testkey.p8 @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg72/yb71r7uVirjpf +vjAPZ5aUR0si2c1yH6Lt/NlhWcWhRANCAAQydvu0D1+DTVM0/U0rbxHfkG3AswYw +hZZk58QvxSbxoBcmoLLMKAuaNBCVg+4I0xKvCfB0dkIjRATNpveON8y3 +-----END PRIVATE KEY----- -- cgit v1.2.3