diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/com/github/scribejava/apis/AppleClientSecretGenerator.java | 16 | ||||
-rw-r--r-- | src/main/java/com/juick/server/configuration/SignInWithAppleConfig.java | 7 | ||||
-rw-r--r-- | src/main/resources/testkey.p8 (renamed from src/test/resources/testkey.p8) | 0 | ||||
-rw-r--r-- | src/test/java/com/juick/JWTTest.java | 94 | ||||
-rw-r--r-- | src/test/java/com/juick/server/tests/ServerTests.java | 73 |
5 files changed, 70 insertions, 120 deletions
diff --git a/src/main/java/com/github/scribejava/apis/AppleClientSecretGenerator.java b/src/main/java/com/github/scribejava/apis/AppleClientSecretGenerator.java index 3af6bc7a..f8e10d97 100644 --- a/src/main/java/com/github/scribejava/apis/AppleClientSecretGenerator.java +++ b/src/main/java/com/github/scribejava/apis/AppleClientSecretGenerator.java @@ -19,10 +19,10 @@ package com.github.scribejava.apis; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; -import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; -import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.KeyFactory; @@ -41,14 +41,16 @@ public class AppleClientSecretGenerator { private final Key signingKey; - public AppleClientSecretGenerator(final String subject, final String teamId, final String keyId, final String keyPath) + private final String pemData; + + public AppleClientSecretGenerator(final String subject, final String teamId, final String keyId, final InputStream keyData) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { this.subject = subject; this.keyId = keyId; this.teamId = teamId; - String pemData = FileUtils.readFileToString(new File(keyPath), StandardCharsets.UTF_8); - String p8encodedData = pemData + this.pemData = IOUtils.toString(keyData, StandardCharsets.UTF_8); + String p8encodedData = getPemData() .replace( "-----BEGIN PRIVATE KEY-----\n", "") .replace("\n", "") @@ -82,4 +84,8 @@ public class AppleClientSecretGenerator { public String getApplicationId() { return subject; } + + public String getPemData() { + return pemData; + } } diff --git a/src/main/java/com/juick/server/configuration/SignInWithAppleConfig.java b/src/main/java/com/juick/server/configuration/SignInWithAppleConfig.java index f736e673..b55ba391 100644 --- a/src/main/java/com/juick/server/configuration/SignInWithAppleConfig.java +++ b/src/main/java/com/juick/server/configuration/SignInWithAppleConfig.java @@ -21,6 +21,7 @@ import com.github.scribejava.apis.AppleClientSecretGenerator; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; import java.io.IOException; import java.security.NoSuchAlgorithmException; @@ -34,11 +35,11 @@ public class SignInWithAppleConfig { private String teamId; @Value("${apple_key_id:keyid}") private String keyId; - @Value("${apple_key_path:AuthKey.p8}") - private String keyPath; + @Value("${apple_key_path:classpath:testkey.p8}") + private Resource keyPath; @Bean public AppleClientSecretGenerator clientSecretGenerator() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { - return new AppleClientSecretGenerator(appId, teamId, keyId, keyPath); + return new AppleClientSecretGenerator(appId, teamId, keyId, keyPath.getInputStream()); } } diff --git a/src/test/resources/testkey.p8 b/src/main/resources/testkey.p8 index 1e5d0f98..1e5d0f98 100644 --- a/src/test/resources/testkey.p8 +++ b/src/main/resources/testkey.p8 diff --git a/src/test/java/com/juick/JWTTest.java b/src/test/java/com/juick/JWTTest.java deleted file mode 100644 index 1a6eeada..00000000 --- a/src/test/java/com/juick/JWTTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 <http://www.gnu.org/licenses/>. - */ - -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/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java index 01f9812c..30f2a025 100644 --- a/src/test/java/com/juick/server/tests/ServerTests.java +++ b/src/test/java/com/juick/server/tests/ServerTests.java @@ -27,6 +27,7 @@ import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.css.StyleElement; import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.github.scribejava.apis.AppleClientSecretGenerator; import com.jayway.jsonpath.JsonPath; import com.juick.*; import com.juick.formatters.PlainTextFormatter; @@ -48,7 +49,6 @@ import com.juick.server.util.HttpUtils; import com.juick.server.util.ImageUtils; import com.juick.server.www.WebApp; import com.juick.service.*; -import com.juick.service.activities.ActivityListener; import com.juick.service.activities.UpdateEvent; import com.juick.service.component.SystemEvent; import com.juick.test.util.MockUtils; @@ -57,12 +57,24 @@ import com.juick.util.MessageUtils; import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.error.PebbleException; import com.mitchellbosecke.pebble.template.PebbleTemplate; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.IteratorUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.text.StringEscapeUtils; +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.After; import org.junit.Assert; import org.junit.Before; @@ -115,30 +127,18 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; +import java.io.*; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.security.*; +import java.security.spec.InvalidKeySpecException; import java.sql.Timestamp; import java.time.Instant; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Scanner; -import java.util.Set; +import java.util.*; import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -164,7 +164,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @TestPropertySource(properties = { - "broken_ssl_hosts=localhost,serverstorageisfull.tld", "ios_app_id=12345678.com.juick.ExampleApp" }) @AutoConfigureMockMvc @@ -249,6 +248,8 @@ public class ServerTests { private Resource jpegNoJfifTiff; @Value("classpath:Transparent.gif") private Resource invisiblePixel; + @Inject + AppleClientSecretGenerator clientSecretGenerator; @Inject private KeystoreManager testKeystoreManager; @@ -2331,4 +2332,40 @@ public class ServerTests { MockUtils.mockMessage(1, freefd, "txt"), Collections.singletonList(freefd)); var likeStr = jsonMapper.writeValueAsString(like); } + + @Test + public void testAppleClientSecret() throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, NoSuchProviderException { + String secret = new String(clientSecretGenerator.getClientSecret().getBytes(), StandardCharsets.UTF_8); + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter(); + pemConverter.setProvider("BC"); + final Reader pemReader = new StringReader(clientSecretGenerator.getPemData()); + 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); + Assert.assertThat(jwt.getHeader().get("kid"), is("keyid")); + Assert.assertThat(jwt.getHeader().get("alg"), is("ES256")); + Claims claims = (Claims)jwt.getBody(); + Assert.assertThat(claims.get("iss"), is("teamid")); + Assert.assertThat(claims.get("sub"), is("com.example.app")); + Assert.assertThat(claims.get("aud"), is("https://appleid.apple.com")); + } } |