Add query to redirection to provide more context in the frontend (#1973)

Co-authored-by: Sebastian Stenzel <sebastian.stenzel@gmail.com>
This commit is contained in:
Armin Schrenk
2021-12-10 13:42:37 +01:00
committed by GitHub
parent fb580ff79d
commit 921dd8fe67
8 changed files with 46 additions and 33 deletions

View File

@@ -60,8 +60,8 @@ class AuthFlow implements AutoCloseable {
* @return An authorization flow
* @throws Exception In case of any problems starting the server
*/
public static AuthFlow init(HubConfig hubConfig) throws Exception {
var receiver = AuthFlowReceiver.start(hubConfig);
public static AuthFlow init(HubConfig hubConfig, AuthFlowContext authFlowContext) throws Exception {
var receiver = AuthFlowReceiver.start(hubConfig, authFlowContext);
return new AuthFlow(receiver, hubConfig);
}

View File

@@ -0,0 +1,5 @@
package org.cryptomator.ui.keyloading.hub;
record AuthFlowContext(String deviceId) {
}

View File

@@ -35,6 +35,7 @@ public class AuthFlowController implements FxController {
private final Application application;
private final Stage window;
private final ExecutorService executor;
private final String deviceId;
private final HubConfig hubConfig;
private final AtomicReference<String> tokenRef;
private final UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result;
@@ -45,10 +46,11 @@ public class AuthFlowController implements FxController {
private AuthFlowTask task;
@Inject
public AuthFlowController(Application application, @KeyLoading Stage window, ExecutorService executor, HubConfig hubConfig, @Named("bearerToken") AtomicReference<String> tokenRef, UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result, @FxmlScene(FxmlFile.HUB_RECEIVE_KEY) Lazy<Scene> receiveKeyScene, ErrorComponent.Builder errorComponent) {
public AuthFlowController(Application application, @KeyLoading Stage window, ExecutorService executor, @Named("deviceId") String deviceId, HubConfig hubConfig, @Named("bearerToken") AtomicReference<String> tokenRef, UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result, @FxmlScene(FxmlFile.HUB_RECEIVE_KEY) Lazy<Scene> receiveKeyScene, ErrorComponent.Builder errorComponent) {
this.application = application;
this.window = window;
this.executor = executor;
this.deviceId = deviceId;
this.hubConfig = hubConfig;
this.tokenRef = tokenRef;
this.result = result;
@@ -62,7 +64,7 @@ public class AuthFlowController implements FxController {
@FXML
public void initialize() {
assert task == null;
task = new AuthFlowTask(hubConfig, this::setAuthUri);;
task = new AuthFlowTask(hubConfig, new AuthFlowContext(deviceId), this::setAuthUri);;
task.setOnFailed(this::authFailed);
task.setOnSucceeded(this::authSucceeded);
executor.submit(task);

View File

@@ -30,20 +30,18 @@ class AuthFlowReceiver implements AutoCloseable {
private final Server server;
private final ServerConnector connector;
private final CallbackServlet servlet;
private final HubConfig hubConfig;
private AuthFlowReceiver(Server server, ServerConnector connector, CallbackServlet servlet, HubConfig hubConfig) {
private AuthFlowReceiver(Server server, ServerConnector connector, CallbackServlet servlet) {
this.server = server;
this.connector = connector;
this.servlet = servlet;
this.hubConfig = hubConfig;
}
public static AuthFlowReceiver start(HubConfig hubConfig) throws Exception {
public static AuthFlowReceiver start(HubConfig hubConfig, AuthFlowContext authFlowContext) throws Exception {
var server = new Server();
var context = new ServletContextHandler();
var servlet = new CallbackServlet(hubConfig);
var servlet = new CallbackServlet(hubConfig, authFlowContext);
context.addServlet(new ServletHolder(servlet), CALLBACK_PATH);
var connector = new ServerConnector(server);
@@ -52,7 +50,7 @@ class AuthFlowReceiver implements AutoCloseable {
server.setConnectors(new Connector[]{connector});
server.setHandler(context);
server.start();
return new AuthFlowReceiver(server, connector, servlet, hubConfig);
return new AuthFlowReceiver(server, connector, servlet);
}
public String getRedirectUri() {
@@ -68,15 +66,19 @@ class AuthFlowReceiver implements AutoCloseable {
server.stop();
}
public static record Callback(String error, String code, String state){}
public static record Callback(String error, String code, String state) {
}
private static class CallbackServlet extends HttpServlet {
private final BlockingQueue<Callback> callback = new LinkedBlockingQueue<>();
private final HubConfig hubConfig;
private final AuthFlowContext authFlowContext;
public CallbackServlet(HubConfig hubConfig) {
public CallbackServlet(HubConfig hubConfig, AuthFlowContext authFlowContext) {
this.hubConfig = hubConfig;
this.authFlowContext = authFlowContext;
}
@Override
@@ -87,9 +89,9 @@ class AuthFlowReceiver implements AutoCloseable {
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
if (error == null && code != null) {
res.setHeader("Location", hubConfig.authSuccessUrl);
res.setHeader("Location", hubConfig.authSuccessUrl + "&device=" + authFlowContext.deviceId());
} else {
res.setHeader("Location", hubConfig.authErrorUrl);
res.setHeader("Location", hubConfig.authErrorUrl + "&device=" + authFlowContext.deviceId());
}
callback.add(new Callback(error, code, state));

View File

@@ -7,6 +7,7 @@ import java.util.function.Consumer;
class AuthFlowTask extends Task<String> {
private final AuthFlowContext authFlowContext;
private final Consumer<URI> redirectUriConsumer;
/**
@@ -15,14 +16,15 @@ class AuthFlowTask extends Task<String> {
* @param hubConfig Configuration object holding parameters required by {@link AuthFlow}
* @param redirectUriConsumer A callback invoked with the redirectUri, as soon as the server has started
*/
public AuthFlowTask(HubConfig hubConfig, Consumer<URI> redirectUriConsumer) {
public AuthFlowTask(HubConfig hubConfig, AuthFlowContext authFlowContext, Consumer<URI> redirectUriConsumer) {
this.hubConfig = hubConfig;
this.authFlowContext = authFlowContext;
this.redirectUriConsumer = redirectUriConsumer;
}
@Override
protected String call() throws Exception {
try (var authFlow = AuthFlow.init(hubConfig)) {
try (var authFlow = AuthFlow.init(hubConfig, authFlowContext)) {
return authFlow.run(uri -> Platform.runLater(() -> redirectUriConsumer.accept(uri)));
}
}

View File

@@ -1,12 +1,15 @@
package org.cryptomator.ui.keyloading.hub;
import com.google.common.io.BaseEncoding;
import com.nimbusds.jose.JWEObject;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import org.cryptomator.common.settings.DeviceKey;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptolib.common.MessageDigestSupplier;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
@@ -23,8 +26,7 @@ import javax.inject.Named;
import javafx.scene.Scene;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
import java.security.KeyPair;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicReference;
@@ -47,6 +49,15 @@ public abstract class HubKeyLoadingModule {
}
}
@Provides
@KeyLoadingScoped
@Named("deviceId")
static String provideDeviceId(DeviceKey deviceKey) {
var publicKey = Objects.requireNonNull(deviceKey.get()).getPublic().getEncoded();
var hashedKey = MessageDigestSupplier.SHA256.get().digest(publicKey);
return BaseEncoding.base16().encode(hashedKey);
}
@Provides
@Named("bearerToken")
@KeyLoadingScoped

View File

@@ -1,12 +1,8 @@
package org.cryptomator.ui.keyloading.hub;
import com.google.common.io.BaseEncoding;
import com.nimbusds.jose.JWEObject;
import dagger.Lazy;
import org.cryptomator.common.settings.DeviceKey;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptolib.common.MessageDigestSupplier;
import org.cryptomator.cryptolib.common.P384KeyPair;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
@@ -44,7 +40,7 @@ public class ReceiveKeyController implements FxController {
private static final String SCHEME_PREFIX = "hub+";
private final Stage window;
private final P384KeyPair keyPair;
private final String deviceId;
private final String bearerToken;
private final AtomicReference<JWEObject> jweRef;
private final UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result;
@@ -55,9 +51,9 @@ public class ReceiveKeyController implements FxController {
private final HttpClient httpClient;
@Inject
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, DeviceKey deviceKey, @Named("bearerToken") AtomicReference<String> tokenRef, AtomicReference<JWEObject> jweRef, UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, ErrorComponent.Builder errorComponent) {
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference<String> tokenRef, AtomicReference<JWEObject> jweRef, UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, ErrorComponent.Builder errorComponent) {
this.window = window;
this.keyPair = Objects.requireNonNull(deviceKey.get());
this.deviceId = deviceId;
this.bearerToken = Objects.requireNonNull(tokenRef.get());
this.jweRef = jweRef;
this.result = result;
@@ -71,9 +67,6 @@ public class ReceiveKeyController implements FxController {
@FXML
public void initialize() {
var deviceKey = keyPair.getPublic().getEncoded();
var hashedKey = MessageDigestSupplier.SHA256.get().digest(deviceKey);
var deviceId = BaseEncoding.base16().encode(hashedKey);
var keyUri = appendPath(vaultBaseUri, "/keys/" + deviceId);
var request = HttpRequest.newBuilder(keyUri) //
.header("Authorization", "Bearer " + bearerToken) //