authentication for extensions as suggested by LittleJ

This commit is contained in:
sirjonasxx 2018-10-16 17:47:00 +02:00
parent df87eb339d
commit aaf3878878
7 changed files with 142 additions and 10 deletions

View File

@ -30,6 +30,7 @@ public abstract class Extension {
private boolean isCorrupted = false;
private static final String[] PORT_FLAG = {"--port", "-p"};
private static final String[] FILE_FLAG = {"--filename", "-f"};
private static final String[] COOKIE_FLAG = {"--auth-token", "-c"}; // don't add a cookie or filename when debugging
private OutputStream out = null;
private final Map<Integer, List<MessageListener>> incomingMessageListeners = new HashMap<>();
@ -81,6 +82,7 @@ public abstract class Extension {
int port = Integer.parseInt(getArgument(args, PORT_FLAG));
String file = getArgument(args, FILE_FLAG);
String cookie = getArgument(args, COOKIE_FLAG);
Socket gEarthExtensionServer = null;
try {
@ -123,6 +125,7 @@ public abstract class Extension {
.appendBoolean(isOnClickMethodUsed())
.appendBoolean(file != null)
.appendString(file == null ? "": file)
.appendString(cookie == null ? "" : cookie)
.appendBoolean(CANLEAVE)
.appendBoolean(CANDELETE);
writeToStream(response.toBytes());

View File

@ -7,14 +7,17 @@ import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.DialogPane;
import java.util.HashSet;
import java.util.Set;
/**
* Created by Jonas on 27/09/18.
*/
public class ConfirmationDialog {
public static boolean showDialog = true;
private static Set<String> ignoreDialogs = new HashSet<>();
public static Alert createAlertWithOptOut(Alert.AlertType type, String title, String headerText,
public static Alert createAlertWithOptOut(Alert.AlertType type, String dialogKey, String title, String headerText,
String message, String optOutMessage, /*Callback<Boolean, Void> optOutAction,*/
ButtonType... buttonTypes) {
Alert alert = new Alert(type);
@ -29,7 +32,11 @@ public class ConfirmationDialog {
protected Node createDetailsButton() {
CheckBox optOut = new CheckBox();
optOut.setText(optOutMessage);
optOut.setOnAction(event -> showDialog = !optOut.isSelected());
optOut.setOnAction(event -> {
if (optOut.isSelected()) {
ignoreDialogs.add(dialogKey);
}
});
return optOut;
}
});
@ -46,5 +53,8 @@ public class ConfirmationDialog {
return alert;
}
public static boolean showDialog(String dialogKey) {
return !ignoreDialogs.contains(dialogKey);
}
}

View File

@ -101,12 +101,14 @@ public class ExtensionItemContainer extends GridPane {
Tooltip.install(deleteButton, uninstall);
deleteButton.show();
GridPane this2 = this;
final String uninstallKey = "uninstallExtension";
deleteButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
boolean delet_dis = true;
if (ConfirmationDialog.showDialog) {
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION,
"Confirmation Dialog", null,
if (ConfirmationDialog.showDialog(uninstallKey)) {
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.CONFIRMATION, uninstallKey
,"Confirmation Dialog", null,
"Are you sure want to uninstall this extension?", "Do not ask again",
ButtonType.YES, ButtonType.NO
);

View File

@ -6,6 +6,7 @@ import gearth.protocol.HPacket;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import gearth.ui.extensions.authentication.Authenticator;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
@ -26,6 +27,7 @@ public class GEarthExtension {
private boolean isInstalledExtension; // <- extension is in the extensions directory
private String fileName;
private String cookie;
private Socket connection;
@ -60,7 +62,14 @@ public class GEarthExtension {
connection,
onDisconnectedCallback
);
callback.act(gEarthExtension);
if (Authenticator.evaluate(gEarthExtension)) {
callback.act(gEarthExtension);
}
else {
gEarthExtension.closeConnection(); //you shall not pass...
}
break;
}
}
@ -79,6 +88,7 @@ public class GEarthExtension {
this.isInstalledExtension = extensionInfo.readBoolean();
this.fileName = extensionInfo.readString();
this.cookie = extensionInfo.readString();
this.leaveButtonVisible = extensionInfo.readBoolean();
this.deleteButtonVisible = extensionInfo.readBoolean();
@ -151,6 +161,9 @@ public class GEarthExtension {
public String getFileName() {
return fileName;
}
public String getCookie() {
return cookie;
}
public boolean isDeleteButtonVisible() {
return deleteButtonVisible;
}

View File

@ -0,0 +1,101 @@
package gearth.ui.extensions.authentication;
import gearth.extensions.Extension;
import gearth.misc.ConfirmationDialog;
import gearth.ui.extensions.GEarthExtension;
import gearth.ui.extensions.executer.ExtensionRunner;
import gearth.ui.extensions.executer.ExtensionRunnerFactory;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* Created by Jonas on 16/10/18.
*/
public class Authenticator {
private static Map<String, String> cookies = new HashMap<>();
public static String generateCookieForExtension(String filename) {
String cookie = getRandomCookie();
cookies.put(filename, cookie);
return cookie;
}
public static boolean evaluate(GEarthExtension extension) {
if (extension.isInstalledExtension()) {
return claimSession(extension.getFileName(), extension.getCookie());
}
else {
return askForPermission(extension);
}
}
/**
* authenticator: authenticate an extension and remove the cookie
* @param filename
* @param cookie
* @return if the extension is authenticated
*/
private static boolean claimSession(String filename, String cookie) {
if (cookies.containsKey(filename) && cookies.get(filename).equals(cookie)) {
cookies.remove(filename);
return true;
}
return false;
}
private static volatile boolean rememberOption = false;
//for not-installed extensions, popup a dialog
private static boolean askForPermission(GEarthExtension extension) {
boolean[] allowConnection = {true};
final String connectExtensionKey = "allow_extension_connection";
if (ConfirmationDialog.showDialog(connectExtensionKey)) {
boolean[] done = {false};
Platform.runLater(() -> {
Alert alert = ConfirmationDialog.createAlertWithOptOut(Alert.AlertType.WARNING, connectExtensionKey
,"Confirmation Dialog", null,
"Extension \""+extension.getTitle()+"\" tries to connect but isn't known to G-Earth, accept this connection?", "Remember my choice",
ButtonType.YES, ButtonType.NO
);
if (!(alert.showAndWait().filter(t -> t == ButtonType.YES).isPresent())) {
allowConnection[0] = false;
}
done[0] = true;
if (!ConfirmationDialog.showDialog(connectExtensionKey)) {
rememberOption = allowConnection[0];
}
});
while (!done[0]) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return allowConnection[0];
}
return rememberOption;
}
private static String getRandomCookie() {
StringBuilder builder = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 40; i++) {
builder.append(r.nextInt(40));
}
return builder.toString();
}
}

View File

@ -25,7 +25,7 @@ public class ExecutionInfo {
for(String type : extensionTypeToExecutionCommand.keySet()) {
extensionTypeToExecutionCommand.put(
type,
extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename}"
extensionTypeToExecutionCommand.get(type) + " -p {port} -f {filename} -c {cookie}"
);
}

View File

@ -1,6 +1,7 @@
package gearth.ui.extensions.executer;
import gearth.Main;
import gearth.ui.extensions.authentication.Authenticator;
import java.io.File;
import java.io.IOException;
@ -70,11 +71,13 @@ public class NormalExtensionRunner implements ExtensionRunner {
public void tryRunExtension(String path, int port) {
try {
String filename = Paths.get(path).getFileName().toString();
Runtime.getRuntime().exec(
ExecutionInfo.getExecutionCommand(getFileExtension(path))
.replace("{path}", path)
.replace("{port}", port+"")
.replace("{filename}", Paths.get(path).getFileName().toString())
.replace("{filename}", filename)
.replace("{cookie}", Authenticator.generateCookieForExtension(filename))
);
} catch (IOException e) {
e.printStackTrace();
@ -119,7 +122,7 @@ public class NormalExtensionRunner implements ExtensionRunner {
private String getRandomString() {
StringBuilder builder = new StringBuilder();
Random r = new Random();
for (int i = 0; i < 10; i++) {
for (int i = 0; i < 12; i++) {
builder.append(r.nextInt(10));
}