aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/github/scribejava/apis/AppleClientSecretGenerator.java16
-rw-r--r--src/main/java/com/juick/server/configuration/SignInWithAppleConfig.java7
-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.java94
-rw-r--r--src/test/java/com/juick/server/tests/ServerTests.java73
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"));
+ }
}