Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ node
# Vite
dist

!/quarkus/dist
!/quarkus/**/src/**/dist
Comment thread
vmuzikar marked this conversation as resolved.
Outdated

# ESLint
.eslintcache

Expand All @@ -108,4 +111,4 @@ node_modules
.sdkmanrc

# JENV
.java-version
.java-version
52 changes: 52 additions & 0 deletions common/src/main/java/org/keycloak/common/util/IoUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.keycloak.common.util;

import java.io.Console;

public class IoUtils {

public static String readFromConsole(String kind, String defaultValue, boolean password) {
Console cons = System.console();
if (cons == null) {
if (defaultValue != null) {
return defaultValue;
}
throw new RuntimeException(String.format("Console is not active, but %s is required", kind));
}
String prompt = String.format("Enter %s", kind) + (defaultValue != null ? String.format(" [%s]:", defaultValue) : ":");
if (password) {
char[] passwd;
if ((passwd = cons.readPassword(prompt)) != null) {
return new String(passwd);
}
} else {
return cons.readLine(prompt);
}
throw new RuntimeException(String.format("No %s provided", kind));
}

public static String readPasswordFromConsole(String kind) {
return readFromConsole(kind, null, true);
}

public static String readLineFromConsole(String kind, String defaultValue) {
return readFromConsole(kind, defaultValue, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
import static org.keycloak.client.admin.cli.operations.UserOperations.resetUserPassword;
import static org.keycloak.client.cli.util.ConfigUtil.credentialsAvailable;
import static org.keycloak.client.cli.util.ConfigUtil.loadConfig;
import static org.keycloak.client.cli.util.IoUtil.readSecret;
import static org.keycloak.client.cli.util.OsUtil.PROMPT;
import static org.keycloak.client.admin.cli.KcAdmMain.CMD;
import static org.keycloak.common.util.IoUtils.readPasswordFromConsole;

/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
Expand Down Expand Up @@ -61,7 +61,7 @@ protected void process() {
}

if (pass == null) {
pass = readSecret("Enter password: ");
pass = readPasswordFromConsole("password");
}

ConfigData config = loadConfig();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.keycloak.client.cli.util.AuthUtil;
import org.keycloak.client.cli.util.ConfigUtil;
import org.keycloak.client.cli.util.HttpUtil;
import org.keycloak.client.cli.util.IoUtil;
import org.keycloak.common.util.IoUtils;

import java.io.File;
import java.io.PrintWriter;
Expand Down Expand Up @@ -176,8 +176,8 @@ protected void setupTruststore(ConfigData configData) {
if (pass == null) {
pass = System.getenv("KC_CLI_TRUSTSTORE_PASSWORD");
}
if (pass == null) {
pass = IoUtil.readSecret("Enter truststore password: ");
if (pass == null) {
pass = IoUtils.readPasswordFromConsole("truststore password");
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@
import static org.keycloak.client.cli.util.ConfigUtil.loadConfig;
import static org.keycloak.client.cli.util.ConfigUtil.saveTokens;
import static org.keycloak.client.cli.util.IoUtil.printErr;
import static org.keycloak.client.cli.util.IoUtil.readSecret;
import static org.keycloak.client.cli.util.OsUtil.OS_ARCH;
import static org.keycloak.client.cli.util.OsUtil.PROMPT;

import static org.keycloak.common.util.IoUtils.readPasswordFromConsole;

/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
Expand Down Expand Up @@ -107,19 +106,19 @@ public void process() {
password = System.getenv("KC_CLI_PASSWORD");
}
if (password == null) {
password = readSecret("Enter password: ");
password = readPasswordFromConsole("password");
}
// if secret was set to be read from stdin, then ask for it
if ("-".equals(secret) && keystore == null) {
secret = readSecret("Enter client secret: ");
secret = readPasswordFromConsole("client secret");
}
} else if (keystore != null || secret != null || clientSet) {
grantTypeForAuthentication = OAuth2Constants.CLIENT_CREDENTIALS;
printErr("Logging into " + server + " as " + "service-account-" + clientId + " of realm " + realm);
if (keystore == null && secret == null) {
secret = System.getenv("KC_CLI_CLIENT_SECRET");
if (secret == null) {
secret = readSecret("Enter client secret: ");
secret = readPasswordFromConsole("client secret");
}
}
}
Expand All @@ -141,9 +140,9 @@ public void process() {
}

if (storePass == null) {
storePass = readSecret("Enter keystore password: ");
storePass = readPasswordFromConsole("keystore password");
if (keyPass == null) {
keyPass = readSecret("Enter key password: ");
keyPass = readPasswordFromConsole("key password");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
import picocli.CommandLine.Parameters;

import static org.keycloak.client.cli.util.ConfigUtil.saveMergeConfig;
import static org.keycloak.client.cli.util.IoUtil.readSecret;
import static org.keycloak.client.cli.util.OsUtil.OS_ARCH;
import static org.keycloak.client.cli.util.OsUtil.PROMPT;
import static org.keycloak.common.util.IoUtils.readPasswordFromConsole;

/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
Expand Down Expand Up @@ -78,7 +78,7 @@ protected void process() {
}

if ("-".equals(trustPass)) {
trustPass = readSecret("Enter truststore password: ");
trustPass = readPasswordFromConsole("truststore password");
}

pass = trustPass;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
*/
package org.keycloak.client.cli.util;

import java.io.Console;
import org.keycloak.common.util.StreamUtil;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
Expand Down Expand Up @@ -65,31 +66,12 @@ public static String readFileOrStdin(String file) {
return content;
}

public static String readSecret(String prompt) {
Console cons = System.console();
if (cons == null) {
throw new RuntimeException("Console is not active, but a password is required");
}
char[] passwd;
if ((passwd = cons.readPassword("%s", prompt)) != null) {
return new String(passwd);
}
throw new RuntimeException("No password provided");
}

public static String readFully(InputStream is) {
StringBuilder out = new StringBuilder();
byte [] buf = new byte[8192];

int rc;
try {
while ((rc = is.read(buf)) != -1) {
out.append(new String(buf, 0, rc, StandardCharsets.UTF_8));
}
return StreamUtil.readString(is, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("Failed to read stream", e);
}
return out.toString();
}

public static void copyStream(InputStream is, OutputStream os) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.keycloak.client.registration.cli.commands;

import org.keycloak.client.cli.config.RealmConfigData;
import org.keycloak.client.cli.util.IoUtil;
import org.keycloak.client.registration.cli.CmdStdinContext;
import org.keycloak.client.registration.cli.KcRegMain;
import org.keycloak.common.util.IoUtils;

import java.io.PrintWriter;
import java.io.StringWriter;
Expand Down Expand Up @@ -64,7 +64,7 @@ protected void process() {
}

if (!delete && token == null) {
token = IoUtil.readSecret("Enter Initial Access Token: ");
token = IoUtils.readPasswordFromConsole("Initial Access Token");
}

// now update the config
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.keycloak.client.registration.cli.commands;

import org.keycloak.client.registration.cli.KcRegMain;
import org.keycloak.common.util.IoUtils;
import org.keycloak.client.cli.config.RealmConfigData;
import org.keycloak.client.cli.util.IoUtil;

import java.io.PrintWriter;
import java.io.StringWriter;
Expand Down Expand Up @@ -61,7 +61,7 @@ protected void process() {


if (!delete && token == null) {
token = IoUtil.readSecret("Enter Registration Access Token: ");
token = IoUtils.readPasswordFromConsole("Registration Access Token");
}

// now update the config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@
import static org.keycloak.client.cli.util.IoUtil.printErr;
import static org.keycloak.client.cli.util.IoUtil.printOut;
import static org.keycloak.client.cli.util.IoUtil.readFully;
import static org.keycloak.client.cli.util.IoUtil.readSecret;
import static org.keycloak.client.cli.util.OsUtil.OS_ARCH;
import static org.keycloak.client.cli.util.OsUtil.PROMPT;
import static org.keycloak.client.cli.util.ParseUtil.parseKeyVal;
import static org.keycloak.client.registration.cli.EndpointType.DEFAULT;
import static org.keycloak.client.registration.cli.EndpointType.OIDC;
import static org.keycloak.client.registration.cli.EndpointType.SAML2;
import static org.keycloak.client.registration.cli.KcRegMain.CMD;
import static org.keycloak.common.util.IoUtils.readPasswordFromConsole;

/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
Expand Down Expand Up @@ -105,7 +105,7 @@ protected void process() {

// if --token is specified read it
if ("-".equals(externalToken)) {
externalToken = readSecret("Enter Initial Access Token: ");
externalToken = readPasswordFromConsole("Initial Access Token");
}

CmdStdinContext ctx = new CmdStdinContext();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.keycloak.config;

public class BootstrapAdminOptions {

public static final Option<String> PASSWORD = new OptionBuilder<>("bootstrap-admin-password", String.class)
.category(OptionCategory.BOOTSTRAP_ADMIN)
.description("Bootstrap admin password")
.hidden()
.build();

public static final Option<String> USERNAME = new OptionBuilder<>("bootstrap-admin-username", String.class)
.category(OptionCategory.BOOTSTRAP_ADMIN)
.description("Username of the bootstrap admin")
.hidden()
.build();

public static final Option<Integer> EXPIRATION = new OptionBuilder<>("bootstrap-admin-expiration", Integer.class)
.category(OptionCategory.BOOTSTRAP_ADMIN)
.description("Time in minutes for the bootstrap admin user to expire.")
.hidden()
.build();
Comment thread
vmuzikar marked this conversation as resolved.
Outdated

public static final Option<String> CLIENT_ID = new OptionBuilder<>("bootstrap-admin-client-id", String.class)
.category(OptionCategory.BOOTSTRAP_ADMIN)
.description("Client id for the admin service")
.hidden()
.build();

public static final Option<String> CLIENT_SECRET = new OptionBuilder<>("bootstrap-admin-client-secret", String.class)
.category(OptionCategory.BOOTSTRAP_ADMIN)
.description("Client secret for the admin service")
.hidden()
.build();

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.keycloak.config;

public enum OptionCategory {
// ordered by name asc
CACHE("Cache", 10, ConfigSupportLevel.SUPPORTED),
CONFIG("Config", 15, ConfigSupportLevel.SUPPORTED),
DATABASE("Database", 20, ConfigSupportLevel.SUPPORTED),
Expand All @@ -20,6 +19,7 @@ public enum OptionCategory {
SECURITY("Security", 120, ConfigSupportLevel.SUPPORTED),
EXPORT("Export", 130, ConfigSupportLevel.SUPPORTED),
IMPORT("Import", 140, ConfigSupportLevel.SUPPORTED),
BOOTSTRAP_ADMIN("Bootstrap Admin", 998, ConfigSupportLevel.SUPPORTED),
GENERAL("General", 999, ConfigSupportLevel.SUPPORTED);

private final String heading;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@

public final class Environment {

public static final String IMPORT_EXPORT_MODE = "import_export";
public static final String NON_SERVER_MODE = "nonserver";
public static final String PROFILE ="kc.profile";
public static final String ENV_PROFILE ="KC_PROFILE";
public static final String DATA_PATH = File.separator + "data";
public static final String DEFAULT_THEMES_PATH = File.separator + "themes";
public static final String PROD_PROFILE_VALUE = "prod";
Expand Down Expand Up @@ -139,8 +141,8 @@ public static boolean isDevProfile(){
return Optional.ofNullable(org.keycloak.common.util.Environment.getProfile()).orElse("").equalsIgnoreCase(org.keycloak.common.util.Environment.DEV_PROFILE_VALUE);
}

public static boolean isImportExportMode() {
return IMPORT_EXPORT_MODE.equalsIgnoreCase(org.keycloak.common.util.Environment.getProfile());
public static boolean isNonServerMode() {
return NON_SERVER_MODE.equalsIgnoreCase(org.keycloak.common.util.Environment.getProfile());
}

public static boolean isWindows() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import static org.keycloak.quarkus.runtime.Environment.getKeycloakModeFromProfile;
import static org.keycloak.quarkus.runtime.Environment.isDevProfile;
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault;
import static org.keycloak.quarkus.runtime.Environment.isImportExportMode;
import static org.keycloak.quarkus.runtime.Environment.isNonServerMode;
import static org.keycloak.quarkus.runtime.Environment.isTestLaunchMode;
import static org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTIMIZED_BUILD_OPTION_LONG;
Expand Down Expand Up @@ -168,7 +168,7 @@ public int run(String... args) throws Exception {

int exitCode = ApplicationLifecycleManager.getExitCode();

if (isTestLaunchMode() || isImportExportMode()) {
if (isTestLaunchMode() || isNonServerMode()) {
// in test mode we exit immediately
// we should be managing this behavior more dynamically depending on the tests requirements (short/long lived)
Quarkus.asyncExit(exitCode);
Expand Down
Loading