Add login information to display secret.
This commit is contained in:
parent
0828d03835
commit
3012da3e87
3 changed files with 72 additions and 33 deletions
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.jdrupes.vmoperator.manager;
|
||||
|
||||
// TODO: Auto-generated Javadoc
|
||||
/**
|
||||
* Some constants.
|
||||
*/
|
||||
|
|
@ -33,6 +34,12 @@ public class Constants extends org.jdrupes.vmoperator.common.Constants {
|
|||
/** The Constant DATA_PASSWORD_EXPIRY. */
|
||||
public static final String DATA_PASSWORD_EXPIRY = "password-expiry";
|
||||
|
||||
/** The Constant DATA_DISPLAY_USER. */
|
||||
public static final String DATA_DISPLAY_USER = "display-user";
|
||||
|
||||
/** The Constant DATA_DISPLAY_LOGIN. */
|
||||
public static final String DATA_DISPLAY_LOGIN = "login-user";
|
||||
|
||||
/** The Constant STATE_RUNNING. */
|
||||
public static final String STATE_RUNNING = "Running";
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
|||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
import io.kubernetes.client.util.generic.options.ListOptions;
|
||||
import java.io.IOException;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Instant;
|
||||
|
|
@ -33,16 +34,19 @@ import java.util.Collections;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Logger;
|
||||
import static org.jdrupes.vmoperator.common.Constants.APP_NAME;
|
||||
import static org.jdrupes.vmoperator.common.Constants.COMP_DISPLAY_SECRET;
|
||||
import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP;
|
||||
import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM;
|
||||
import org.jdrupes.vmoperator.common.K8sV1SecretStub;
|
||||
import org.jdrupes.vmoperator.common.VmDefinitionStub;
|
||||
import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET;
|
||||
import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_LOGIN;
|
||||
import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_PASSWORD;
|
||||
import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_USER;
|
||||
import static org.jdrupes.vmoperator.manager.Constants.DATA_PASSWORD_EXPIRY;
|
||||
import org.jdrupes.vmoperator.manager.events.PrepareConsole;
|
||||
import org.jdrupes.vmoperator.manager.events.VmChannel;
|
||||
|
|
@ -75,6 +79,15 @@ public class DisplaySecretReconciler extends Component {
|
|||
private final List<PendingGet> pendingPrepares
|
||||
= Collections.synchronizedList(new LinkedList<>());
|
||||
|
||||
/**
|
||||
* Instantiates a new display secret reconciler.
|
||||
*
|
||||
* @param componentChannel the component channel
|
||||
*/
|
||||
public DisplaySecretReconciler(Channel componentChannel) {
|
||||
super(componentChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* On configuration update.
|
||||
*
|
||||
|
|
@ -213,39 +226,13 @@ public class DisplaySecretReconciler extends Component {
|
|||
}
|
||||
var stub = stubs.iterator().next();
|
||||
|
||||
// Check validity
|
||||
// Get secret and update
|
||||
var secret = stub.model().get();
|
||||
@SuppressWarnings("PMD.StringInstantiation")
|
||||
var expiry = Optional.ofNullable(secret.getData()
|
||||
.get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null);
|
||||
if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null
|
||||
&& stillValid(expiry)) {
|
||||
// Fixed secret, don't touch
|
||||
event.setResult(
|
||||
new String(secret.getData().get(DATA_DISPLAY_PASSWORD)));
|
||||
var updPw = updatePassword(secret, event);
|
||||
var updUsr = updateUser(secret, event);
|
||||
if (!updPw && !updUsr) {
|
||||
return;
|
||||
}
|
||||
updatePassword(stub, event);
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.StringInstantiation")
|
||||
private void updatePassword(K8sV1SecretStub stub, PrepareConsole event)
|
||||
throws ApiException {
|
||||
SecureRandom random = null;
|
||||
try {
|
||||
random = SecureRandom.getInstanceStrong();
|
||||
} catch (NoSuchAlgorithmException e) { // NOPMD
|
||||
// "Every implementation of the Java platform is required
|
||||
// to support at least one strong SecureRandom implementation."
|
||||
}
|
||||
byte[] bytes = new byte[16];
|
||||
random.nextBytes(bytes);
|
||||
var password = Base64.encode(bytes);
|
||||
var model = stub.model().get();
|
||||
model.setStringData(Map.of(DATA_DISPLAY_PASSWORD, password,
|
||||
DATA_PASSWORD_EXPIRY,
|
||||
Long.toString(Instant.now().getEpochSecond() + passwordValidity)));
|
||||
event.setResult(password);
|
||||
|
||||
// Prepare wait for confirmation (by VM status change)
|
||||
var pending = new PendingGet(event,
|
||||
|
|
@ -257,7 +244,52 @@ public class DisplaySecretReconciler extends Component {
|
|||
});
|
||||
|
||||
// Update, will (eventually) trigger confirmation
|
||||
stub.update(model).getObject();
|
||||
stub.update(secret).getObject();
|
||||
}
|
||||
|
||||
private boolean updateUser(V1Secret secret, PrepareConsole event) {
|
||||
var curUser = DataPath.<byte[]> get(secret, "data", DATA_DISPLAY_USER)
|
||||
.map(b -> new String(b, UTF_8)).orElse(null);
|
||||
var curLogin = DataPath.<byte[]> get(secret, "data", DATA_DISPLAY_LOGIN)
|
||||
.map(b -> new String(b, UTF_8)).map(Boolean::parseBoolean)
|
||||
.orElse(null);
|
||||
if (Objects.equals(curUser, event.user()) && Objects.equals(
|
||||
curLogin, event.loginUser())) {
|
||||
return false;
|
||||
}
|
||||
secret.getData().put(DATA_DISPLAY_USER, event.user().getBytes(UTF_8));
|
||||
secret.getData().put(DATA_DISPLAY_LOGIN,
|
||||
Boolean.toString(event.loginUser()).getBytes(UTF_8));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean updatePassword(V1Secret secret, PrepareConsole event) {
|
||||
var expiry = Optional.ofNullable(secret.getData()
|
||||
.get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null);
|
||||
if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null
|
||||
&& stillValid(expiry)) {
|
||||
// Fixed secret, don't touch
|
||||
event.setResult(
|
||||
new String(secret.getData().get(DATA_DISPLAY_PASSWORD)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate password and set expiry
|
||||
SecureRandom random = null;
|
||||
try {
|
||||
random = SecureRandom.getInstanceStrong();
|
||||
} catch (NoSuchAlgorithmException e) { // NOPMD
|
||||
// "Every implementation of the Java platform is required
|
||||
// to support at least one strong SecureRandom implementation."
|
||||
}
|
||||
byte[] bytes = new byte[16];
|
||||
random.nextBytes(bytes);
|
||||
var password = Base64.encode(bytes);
|
||||
secret.setStringData(Map.of(DATA_DISPLAY_PASSWORD, password,
|
||||
DATA_PASSWORD_EXPIRY,
|
||||
Long.toString(Instant.now().getEpochSecond() + passwordValidity)));
|
||||
event.setResult(password);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean stillValid(String expiry) {
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ public class Reconciler extends Component {
|
|||
fmConfig.setClassForTemplateLoading(Reconciler.class, "");
|
||||
|
||||
cmReconciler = new ConfigMapReconciler(fmConfig);
|
||||
dsReconciler = attach(new DisplaySecretReconciler());
|
||||
dsReconciler = attach(new DisplaySecretReconciler(componentChannel));
|
||||
stsReconciler = new StatefulSetReconciler(fmConfig);
|
||||
pvcReconciler = new PvcReconciler(fmConfig);
|
||||
podReconciler = new PodReconciler(fmConfig);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue