WebServer functionality restored. (Https instead of http)

TODO:
- Bump Http requests to Https
- Http server if certificate load fails
- No path automatic redirection based on permission level
  - Move to manual authentication instead of Authenticator
    - 403 Page
    - 401 Unauthorized Page
- Tutorial for Keystore creation
This commit is contained in:
Rsl1122 2017-07-29 12:40:39 +03:00
parent a2f7587b8d
commit ed555cce76
4 changed files with 63 additions and 162 deletions

View File

@ -2,12 +2,9 @@
<library name="Maven: com.djrapitops:abstract-plugin-framework:2.0.1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/abstract-plugin-framework/2.0.1/abstract-plugin-framework-2.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/../../Abstract-Plugin-Framework/AbstractPluginFramework/target/AbstractPluginFramework.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/abstract-plugin-framework/2.0.1/abstract-plugin-framework-2.0.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/djrapitops/abstract-plugin-framework/2.0.1/abstract-plugin-framework-2.0.1-sources.jar!/" />
</SOURCES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@ -31,14 +31,14 @@ public class Authenticator extends BasicAuthenticator {
private boolean isAuthorized(String user, String passwordRaw, String target) throws PassEncryptUtil.CannotPerformOperationException, PassEncryptUtil.InvalidHashException, SQLException {
SecurityTable securityTable = plugin.getDB().getSecurityTable();
if (!securityTable.userExists(user)) {
throw new IllegalArgumentException("User Doesn't exist");
return false;
}
WebUser securityInfo = securityTable.getSecurityInfo(user);
boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, securityInfo.getSaltedPassHash());
if (!correctPass) {
throw new IllegalArgumentException("User and Password do not match");
}
return false;
}
int permLevel = securityInfo.getPermLevel(); // Lower number has higher clearance.
int required = getRequiredPermLevel(target, securityInfo.getName());
return permLevel <= required;

View File

@ -1,17 +1,13 @@
package main.java.com.djrapitops.plan.ui.webserver;
import com.djrapitops.plugin.utilities.Verify;
import com.sun.net.httpserver.*;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.response.*;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;
import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;
import javax.net.ssl.*;
@ -20,11 +16,10 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.sql.SQLException;
import java.util.Base64;
import java.util.UUID;
import java.util.concurrent.Executors;
@ -124,17 +119,29 @@ public class WebServer {
}
Log.debug("Create server context");
server.createContext("/", serverResponse(null));
HttpContext analysisPage = server.createContext("/server", serverResponse(null));
HttpContext playersPage = server.createContext("/players", new PlayersPageResponse(null, plugin));
HttpContext inspectPage = server.createContext("/player", new InspectPageResponse(null, dataReqHandler, UUID.randomUUID())); // TODO
HttpContext context = server.createContext("/", new HttpHandler() {
@Override
public void handle(HttpExchange xghng) throws IOException {
HttpsExchange exchange = (HttpsExchange) xghng;
try {
URI uri = exchange.getRequestURI();
String target = uri.toString();
Response response = getResponse(target);
String content = response.getContent();
exchange.sendResponseHeaders(response.getCode(), content.length());
if (startSuccessful) {
for (HttpContext c : new HttpContext[]{analysisPage, playersPage, inspectPage}) {
c.setAuthenticator(new Authenticator(plugin, c.getPath()));
OutputStream os = exchange.getResponseBody();
os.write(content.getBytes());
os.close();
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
throw e;
}
}
});
if (startSuccessful) {
context.setAuthenticator(new Authenticator(plugin, "/"));
}
server.setExecutor(Executors.newSingleThreadExecutor());
server.start();
@ -147,55 +154,37 @@ public class WebServer {
}
}
// Used for deciding the Response appropriate for the Request.
private Response getResponse(Request request, OutputStream output) {
try {
Verify.nullCheck(request);
Verify.nullCheck(output);
// if (!request.hasAuthorization()) {
// return new PromptAuthorizationResponse(output);
// }
// try {
// if (!isAuthorized(request)) {
// ForbiddenResponse response403 = new ForbiddenResponse(output);
// String content = "<h1>403 Forbidden - Access Denied</h1>"
// + "<p>Unauthorized User.<br>"
// + "Make sure your user has the correct access level.<br>"
// + "You can use /plan web check <username> to check the permission level.</p>";
// response403.setContent(content);
// return response403;
// }
if (isFaviconRequest(request)) {
return new RedirectResponse(output, "https://puu.sh/tK0KL/6aa2ba141b.ico");
}
if (!request.hasAuthorization()) {
return new PromptAuthorizationResponse(output);
}
try {
if (!isAuthorized(request)) {
ForbiddenResponse response403 = new ForbiddenResponse(output);
String content = "<h1>403 Forbidden - Access Denied</h1>"
+ "<p>Unauthorized User.<br>"
+ "Make sure your user has the correct access level.<br>"
+ "You can use /plan web check <username> to check the permission level.</p>";
response403.setContent(content);
return response403;
}
} catch (IllegalArgumentException e) {
return new PromptAuthorizationResponse(output);
}
String req = request.getRequest();
String target = request.getTarget();
if (!req.equals("GET") || target.equals("/")) {
return responseNotFound(output);
}
String[] args = target.split("/");
if (args.length < 2) {
return responseNotFound(output);
}
String page = args[1];
switch (page) {
case "players":
return new PlayersPageResponse(output, plugin);
case "player":
return playerResponse(args, output);
case "server":
return serverResponse(output);
default:
return responseNotFound(output);
}
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
return new InternalErrorResponse(output, e, request.getTarget());
private Response getResponse(String target) {
String[] args = target.split("/");
if (args.length < 2) {
return responseNotFound(null);
}
String page = args[1];
switch (page) {
case "favicon.ico":
return new RedirectResponse(null, "https://puu.sh/tK0KL/6aa2ba141b.ico");
case "players":
return new PlayersPageResponse(null, plugin);
case "player":
return playerResponse(args, null);
case "server":
return serverResponse(null);
default:
return responseNotFound(null);
}
}
@ -255,63 +244,4 @@ public class WebServer {
public DataRequestHandler getDataReqHandler() {
return dataReqHandler;
}
private boolean isAuthorized(Request request) throws PassEncryptUtil.CannotPerformOperationException, PassEncryptUtil.InvalidHashException, SQLException {
Base64.Decoder decoder = Base64.getDecoder();
String auth = request.getAuthorization();
byte[] decoded = decoder.decode(auth);
String[] userInfo = new String(decoded).split(":");
if (userInfo.length != 2) {
throw new IllegalArgumentException("User and Password not specified");
}
String user = userInfo[0];
String passwordRaw = userInfo[1];
return isAuthorized(user, passwordRaw, request.getTarget());
}
private boolean isAuthorized(String user, String passwordRaw, String target) throws PassEncryptUtil.CannotPerformOperationException, PassEncryptUtil.InvalidHashException, SQLException {
SecurityTable securityTable = plugin.getDB().getSecurityTable();
if (!securityTable.userExists(user)) {
throw new IllegalArgumentException("User Doesn't exist");
}
WebUser securityInfo = securityTable.getSecurityInfo(user);
boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, securityInfo.getSaltedPassHash());
if (!correctPass) {
throw new IllegalArgumentException("User and Password do not match");
}
int permLevel = securityInfo.getPermLevel(); // Lower number has higher clearance.
int required = getRequiredPermLevel(target, securityInfo.getName());
return permLevel <= required;
}
private int getRequiredPermLevel(String target, String user) {
String[] t = target.split("/");
if (t.length < 3) {
return 0;
}
final String wantedUser = t[2].toLowerCase().trim();
final String theUser = user.trim().toLowerCase();
if (t[1].equals("players")) {
return 1;
}
if (t[1].equals("player")) {
if (wantedUser.equals(theUser)) {
return 2;
} else {
return 1;
}
}
return 0;
}
private boolean isFaviconRequest(Request request) {
String[] args = request.getTarget().split("/");
if (args.length < 2 || args.length > 2) {
return false;
}
String page = args[1];
return page.equals("favicon.ico");
}
}

View File

@ -1,12 +1,5 @@
package main.java.com.djrapitops.plan.ui.webserver.response;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsExchange;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.ui.webserver.Request;
import java.io.IOException;
import java.io.OutputStream;
@ -14,7 +7,7 @@ import java.io.OutputStream;
* @author Rsl1122
* @since 3.5.2
*/
public abstract class Response implements HttpHandler {
public abstract class Response {
private final OutputStream output;
@ -51,6 +44,10 @@ public abstract class Response implements HttpHandler {
+ content;
}
public String getContent() {
return content;
}
public void setHeader(String header) {
this.header = header;
}
@ -59,30 +56,7 @@ public abstract class Response implements HttpHandler {
this.content = content;
}
@Override
public void handle(HttpExchange xghng) throws IOException {
Log.debug("Recieved HTTP Exchange");
Log.debug(xghng.toString());
HttpsExchange exchange = (HttpsExchange) xghng;
try {
Headers headers = exchange.getRequestHeaders();
Request req = new Request(exchange.getRequestBody());
Log.debug(req.toString());
// headers.set("Content-Type", "text/html");
exchange.sendResponseHeaders(getCode(), content.length());
Log.debug("Content:");
Log.debug(content);
OutputStream os = exchange.getResponseBody();
os.write(content.getBytes());
os.close();
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
throw e;
}
}
private int getCode() {
public int getCode() {
if (header == null) {
return 500;
} else {