Added PKCS12 support

Affects issues:
- Close #1102
This commit is contained in:
Rsl1122 2019-08-08 10:13:43 +03:00
parent 8fe59ae83c
commit a129c24e7a
6 changed files with 178 additions and 52 deletions

View File

@ -178,8 +178,9 @@ public class WebServer implements SubSystem {
String alias = config.get(WebserverSettings.CERTIFICATE_ALIAS); String alias = config.get(WebserverSettings.CERTIFICATE_ALIAS);
boolean startSuccessful = false; boolean startSuccessful = false;
String keyStoreKind = keyStorePath.endsWith(".p12") ? "PKCS12" : "JKS";
try (FileInputStream fIn = new FileInputStream(keyStorePath)) { try (FileInputStream fIn = new FileInputStream(keyStorePath)) {
KeyStore keystore = KeyStore.getInstance("JKS"); KeyStore keystore = KeyStore.getInstance(keyStoreKind);
keystore.load(fIn, storepass); keystore.load(fIn, storepass);
Certificate cert = keystore.getCertificate(alias); Certificate cert = keystore.getCertificate(alias);

View File

@ -0,0 +1,76 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.webserver;
import com.djrapitops.plan.api.exceptions.connection.*;
import com.djrapitops.plan.utilities.Base64Util;
import org.junit.jupiter.api.Test;
import utilities.HTTPConnector;
import java.net.HttpURLConnection;
import java.net.URL;
import static org.junit.Assert.assertTrue;
interface HttpsServerTest {
HTTPConnector connector = new HTTPConnector();
WebServer getWebServer();
int testPortNumber();
@Test
default void webServerIsRunningHTTPS() {
assertTrue("WebServer is not using https", getWebServer().isUsingHTTPS());
}
/**
* Test case against "Perm level 0 required, got 0".
*/
@Test
default void userCanLogIn() throws Exception {
webServerIsRunningHTTPS();
String address = "https://localhost:" + testPortNumber();
URL url = new URL(address);
HttpURLConnection connection = connector.getConnection("GET", address);
String user = Base64Util.encode("test:testPass");
connection.setRequestProperty("Authorization", "Basic " + user);
int responseCode = connection.getResponseCode();
switch (responseCode) {
case 200:
case 302:
return;
case 400:
throw new BadRequestException("Bad Request: " + url.toString());
case 403:
throw new ForbiddenException(url.toString() + " returned 403");
case 404:
throw new NotFoundException(url.toString() + " returned a 404, ensure that your server is connected to an up to date Plan server.");
case 412:
throw new UnauthorizedServerException(url.toString() + " reported that it does not recognize this server. Make sure '/plan m setup' was successful.");
case 500:
throw new InternalErrorException();
default:
throw new WebException(url.toString() + "| Wrong response code " + responseCode);
}
}
}

View File

@ -16,53 +16,38 @@
*/ */
package com.djrapitops.plan.system.webserver; package com.djrapitops.plan.system.webserver;
import com.djrapitops.plan.api.exceptions.connection.*;
import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.data.WebUser;
import com.djrapitops.plan.db.access.transactions.commands.RegisterWebUserTransaction; import com.djrapitops.plan.db.access.transactions.commands.RegisterWebUserTransaction;
import com.djrapitops.plan.system.PlanSystem; import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.settings.config.PlanConfig; import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.WebserverSettings; import com.djrapitops.plan.system.settings.paths.WebserverSettings;
import com.djrapitops.plan.utilities.Base64Util;
import com.djrapitops.plan.utilities.PassEncryptUtil; import com.djrapitops.plan.utilities.PassEncryptUtil;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.junit.platform.runner.JUnitPlatform; import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import utilities.HTTPConnector;
import utilities.RandomData; import utilities.RandomData;
import utilities.TestResources; import utilities.TestResources;
import utilities.mocks.PluginMockComponent; import utilities.mocks.PluginMockComponent;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import static org.junit.Assert.assertTrue;
@RunWith(JUnitPlatform.class) @RunWith(JUnitPlatform.class)
class HTTPSWebServerAuthTest { class JksHttpsServerTest implements HttpsServerTest {
private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500); private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
public static PluginMockComponent component;
private static PlanSystem system; private static PlanSystem system;
private HTTPConnector connector = new HTTPConnector();
@BeforeAll @BeforeAll
static void setUpClass(@TempDir Path tempDir) throws Exception { static void setUpClass(@TempDir Path tempDir) throws Exception {
File file = tempDir.resolve("Cert.keystore").toFile(); File file = tempDir.resolve("PlanCert.jks").toFile();
TestResources.copyResourceIntoFile(file, "/Cert.keystore"); TestResources.copyResourceIntoFile(file, "/PlanCert.jks");
String absolutePath = file.getAbsolutePath(); String absolutePath = file.getAbsolutePath();
component = new PluginMockComponent(tempDir); PluginMockComponent component = new PluginMockComponent(tempDir);
system = component.getPlanSystem(); system = component.getPlanSystem();
PlanConfig config = system.getConfigSystem().getConfig(); PlanConfig config = system.getConfigSystem().getConfig();
@ -87,38 +72,13 @@ class HTTPSWebServerAuthTest {
} }
} }
/** @Override
* Test case against "Perm level 0 required, got 0". public WebServer getWebServer() {
*/ return system.getWebServerSystem().getWebServer();
@Test }
void testHTTPSAuthForPages() throws IOException, WebException, KeyManagementException, NoSuchAlgorithmException {
assertTrue("WebServer is not using https", system.getWebServerSystem().getWebServer().isUsingHTTPS());
String address = "https://localhost:" + TEST_PORT_NUMBER; @Override
URL url = new URL(address); public int testPortNumber() {
HttpURLConnection connection = connector.getConnection("GET", address); return TEST_PORT_NUMBER;
String user = Base64Util.encode("test:testPass");
connection.setRequestProperty("Authorization", "Basic " + user);
int responseCode = connection.getResponseCode();
switch (responseCode) {
case 200:
case 302:
return;
case 400:
throw new BadRequestException("Bad Request: " + url.toString());
case 403:
throw new ForbiddenException(url.toString() + " returned 403");
case 404:
throw new NotFoundException(url.toString() + " returned a 404, ensure that your server is connected to an up to date Plan server.");
case 412:
throw new UnauthorizedServerException(url.toString() + " reported that it does not recognize this server. Make sure '/plan m setup' was successful.");
case 500:
throw new InternalErrorException();
default:
throw new WebException(url.toString() + "| Wrong response code " + responseCode);
}
} }
} }

View File

@ -0,0 +1,89 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.webserver;
import com.djrapitops.plan.data.WebUser;
import com.djrapitops.plan.db.access.transactions.commands.RegisterWebUserTransaction;
import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.settings.changes.ConfigUpdater;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.WebserverSettings;
import com.djrapitops.plan.utilities.PassEncryptUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.io.TempDir;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import utilities.RandomData;
import utilities.TestResources;
import utilities.mocks.PluginMockComponent;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@RunWith(JUnitPlatform.class)
class Pkcs12HttpsServerTest implements HttpsServerTest {
private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
private static PlanSystem system;
@BeforeAll
static void setUpClass(@TempDir Path tempDir) throws Exception {
File file = tempDir.resolve("TestCert.p12").toFile();
File testCert = TestResources.getTestResourceFile("TestCert.p12", ConfigUpdater.class);
Files.copy(testCert.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
String absolutePath = file.getAbsolutePath();
PluginMockComponent component = new PluginMockComponent(tempDir);
system = component.getPlanSystem();
PlanConfig config = system.getConfigSystem().getConfig();
config.set(WebserverSettings.CERTIFICATE_PATH, absolutePath);
config.set(WebserverSettings.CERTIFICATE_KEYPASS, "test");
config.set(WebserverSettings.CERTIFICATE_STOREPASS, "test");
config.set(WebserverSettings.CERTIFICATE_ALIAS, "test");
config.set(WebserverSettings.PORT, TEST_PORT_NUMBER);
system.enable();
WebUser webUser = new WebUser("test", PassEncryptUtil.createHash("testPass"), 0);
system.getDatabaseSystem().getDatabase().executeTransaction(new RegisterWebUserTransaction(webUser));
}
@AfterAll
static void tearDownClass() {
if (system != null) {
system.disable();
}
}
@Override
public WebServer getWebServer() {
return system.getWebServerSystem().getWebServer();
}
@Override
public int testPortNumber() {
return TEST_PORT_NUMBER;
}
}

Binary file not shown.