From 85240c960601731d836d4e2e807075018aba0378 Mon Sep 17 00:00:00 2001 From: stianst Date: Mon, 8 Nov 2021 13:32:26 +0100 Subject: [PATCH] Remove deprecated kcinit from keycloak Closes #9106 --- .../adapters/installed/KcinitDriver.java | 694 ----------------- adapters/oidc/kcinit/README.md | 9 - adapters/oidc/kcinit/pom.xml | 76 -- adapters/oidc/kcinit/src/main/bin/kcinit | 26 - adapters/oidc/kcinit/src/main/bin/kcinit.bat | 8 - .../org/keycloak/adapters/KcinitMain.java | 30 - adapters/oidc/pom.xml | 1 - .../admin-cli/src/main/bin/kcadm.sh | 7 - pom.xml | 11 - .../oidc/OIDCLoginProtocolService.java | 32 - .../integration-arquillian/tests/base/pom.xml | 37 - .../keycloak/testsuite/cli/KcinitExec.java | 58 -- .../admin/FineGrainAdminUnitTest.java | 20 +- .../keycloak/testsuite/cli/KcinitTest.java | 698 ------------------ .../cli/registration/KcRegConfigTest.java | 2 +- .../registration/KcRegUpdateTokenTest.java | 2 +- 16 files changed, 12 insertions(+), 1699 deletions(-) delete mode 100644 adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KcinitDriver.java delete mode 100755 adapters/oidc/kcinit/README.md delete mode 100755 adapters/oidc/kcinit/pom.xml delete mode 100755 adapters/oidc/kcinit/src/main/bin/kcinit delete mode 100755 adapters/oidc/kcinit/src/main/bin/kcinit.bat delete mode 100644 adapters/oidc/kcinit/src/main/java/org/keycloak/adapters/KcinitMain.java delete mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/cli/KcinitExec.java delete mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/KcinitTest.java diff --git a/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KcinitDriver.java b/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KcinitDriver.java deleted file mode 100644 index d264365602..0000000000 --- a/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KcinitDriver.java +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright 2016 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.adapters.installed; - -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; -import org.keycloak.OAuth2Constants; -import org.keycloak.adapters.KeycloakDeployment; -import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.adapters.ServerRequest; -import org.keycloak.common.util.Base64; -import org.keycloak.common.util.Time; -import org.keycloak.jose.jwe.*; -import org.keycloak.representations.AccessTokenResponse; -import org.keycloak.representations.adapters.config.AdapterConfig; -import org.keycloak.representations.idm.OAuth2ErrorRepresentation; -import org.keycloak.util.JsonSerialization; - -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Form; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.util.*; - -/** - * All kcinit commands that take input ask for - *

- * 1. . kcinit - * - setup and export KC_SESSION_KEY env var if not set. - * - checks to see if master token valid, refresh is possible, exit if token valid - * - performs command line login - * - stores master token for master client - * 2. app.sh is a wrapper for app cli. - * - token=`kcinit token app` - * - checks to see if token for app client has been fetched, refresh if valid, output token to sys.out if exists - * - if no token, login. Prompts go to stderr. - * - pass token as cmd line param to app or as environment variable. - *

- * 3. kcinit password {password} - * - outputs password key that is used for encryption. - * - can be used in .bashrc as export KC_SESSSION_KEY=`kcinit password {password}` or just set it in .bat file - *

- * - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class KcinitDriver { - - public static final String KC_SESSION_KEY = "KC_SESSION_KEY"; - public static final String KC_LOGIN_CONFIG_PATH = "KC_LOGIN_CONFIG_PATH"; - protected Map config; - protected boolean debug = true; - - protected static byte[] salt = new byte[]{-4, 88, 66, -101, 78, -94, 21, 105}; - - String[] args = null; - - protected boolean forceLogin; - protected boolean browserLogin; - - public void mainCmd(String[] args) throws Exception { - - this.args = args; - - - if (args.length == 0) { - printHelp(); - return; - } - - if (args[0].equalsIgnoreCase("token")) { - //System.err.println("executing token"); - token(); - } else if (args[0].equalsIgnoreCase("login")) { - login(); - } else if (args[0].equalsIgnoreCase("logout")) { - logout(); - } else if (args[0].equalsIgnoreCase("env")) { - System.out.println(System.getenv().toString()); - } else if (args[0].equalsIgnoreCase("install")) { - install(); - } else if (args[0].equalsIgnoreCase("uninstall")) { - uninstall(); - } else if (args[0].equalsIgnoreCase("password")) { - passwordKey(); - } else { - KeycloakInstalled.console().writer().println("Unknown command: " + args[0]); - KeycloakInstalled.console().writer().println(); - printHelp(); - } - } - - public String getHome() { - String home = System.getenv("HOME"); - if (home == null) { - home = System.getProperty("HOME"); - if (home == null) { - home = Paths.get("").toAbsolutePath().normalize().toString(); - } - } - return home; - } - - public void passwordKey() { - if (args.length < 2) { - printHelp(); - System.exit(1); - } - String password = args[1]; - try { - String encodedKey = generateEncryptionKey(password); - System.out.printf(encodedKey); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - - protected String generateEncryptionKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { - SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); - KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 100, 128); - SecretKey tmp = factory.generateSecret(spec); - byte[] aeskey = tmp.getEncoded(); - return Base64.encodeBytes(aeskey); - } - - public JWE createJWE() { - String key = getEncryptionKey(); - if (key == null) { - throw new RuntimeException(KC_SESSION_KEY + " env var not set"); - } - byte[] aesKey = null; - try { - aesKey = Base64.decode(key.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new RuntimeException("invalid " + KC_SESSION_KEY + "env var"); - } - - JWE jwe = new JWE(); - final SecretKey aesSecret = new SecretKeySpec(aesKey, "AES"); - jwe.getKeyStorage() - .setDecryptionKey(aesSecret); - return jwe; - } - - protected String encryptionKey; - - protected String getEncryptionKey() { - if (encryptionKey != null) return encryptionKey; - return System.getenv(KC_SESSION_KEY); - } - - public String encrypt(String payload) { - JWE jwe = createJWE(); - JWEHeader jweHeader = new JWEHeader(JWEConstants.A128KW, JWEConstants.A128CBC_HS256, null); - jwe.header(jweHeader).content(payload.getBytes(StandardCharsets.UTF_8)); - try { - return jwe.encodeJwe(); - } catch (JWEException e) { - throw new RuntimeException("cannot encrypt payload", e); - } - } - - public String decrypt(String encoded) { - JWE jwe = createJWE(); - try { - jwe.verifyAndDecodeJwe(encoded); - byte[] content = jwe.getContent(); - if (content == null) return null; - return new String(content, StandardCharsets.UTF_8); - } catch (Exception ex) { - throw new RuntimeException("cannot decrypt payload", ex); - - } - - } - - public static String getenv(String name, String defaultValue) { - String val = System.getenv(name); - return val == null ? defaultValue : val; - } - - public File getConfigDirectory() { - return Paths.get(getHome(), getenv(KC_LOGIN_CONFIG_PATH, ".keycloak"), "kcinit").toFile(); - } - - - public File getConfigFile() { - return Paths.get(getHome(), getenv(KC_LOGIN_CONFIG_PATH, ".keycloak"), "kcinit", "config.json").toFile(); - } - - public File getTokenFilePath(String client) { - return Paths.get(getHome(), getenv(KC_LOGIN_CONFIG_PATH, ".keycloak"), "kcinit", "tokens", client).toFile(); - } - - public File getTokenDirectory() { - return Paths.get(getHome(), getenv(KC_LOGIN_CONFIG_PATH, ".keycloak"), "kcinit", "tokens").toFile(); - } - - protected boolean encrypted = false; - - protected void checkEnv() { - File configFile = getConfigFile(); - if (!configFile.exists()) { - KeycloakInstalled.console().writer().println("You have not configured kcinit. Please run 'kcinit install' to configure."); - System.exit(1); - } - byte[] data = new byte[0]; - try { - data = readFileRaw(configFile); - } catch (IOException e) { - - } - if (data == null) { - KeycloakInstalled.console().writer().println("Config file unreadable. Please run 'kcinit install' to configure."); - System.exit(1); - - } - String encodedJwe = new String(data, StandardCharsets.UTF_8); - - if (encodedJwe.contains("realm")) { - encrypted = false; - return; - } else { - encrypted = true; - } - - if (System.getenv(KC_SESSION_KEY) == null) { - promptLocalPassword(); - } - } - - protected void promptLocalPassword() { - String password = KeycloakInstalled.console().passwordPrompt("Enter password to unlock kcinit config files: "); - try { - encryptionKey = generateEncryptionKey(password); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - - protected String readFile(File fp) { - try { - byte[] data = readFileRaw(fp); - if (data == null) return null; - String file = new String(data, StandardCharsets.UTF_8); - if (!encrypted) { - return file; - } - String decrypted = decrypt(file); - if (decrypted == null) - throw new RuntimeException("Unable to decrypt file. Did you set your local password correctly?"); - return decrypted; - } catch (IOException e) { - throw new RuntimeException("failed to decrypt file: " + fp.getAbsolutePath() + " Did you set your local password correctly?", e); - } - - - } - - protected byte[] readFileRaw(File fp) throws IOException { - if (!fp.exists()) return null; - try (FileInputStream fis = new FileInputStream(fp)) { - byte[] data = new byte[(int) fp.length()]; - fis.read(data); - return data; - } - } - - protected void writeFile(File fp, String payload) { - try { - String data = payload; - if (encrypted) data = encrypt(payload); - FileOutputStream fos = new FileOutputStream(fp); - fos.write(data.getBytes(StandardCharsets.UTF_8)); - fos.flush(); - fos.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - - public void install() { - if (getEncryptionKey() == null) { - if (KeycloakInstalled.console().confirm("Do you want to protect tokens stored locally with a password? (y/n): ")) { - String password = "p"; - String confirm = "c"; - do { - password = KeycloakInstalled.console().passwordPrompt("Enter local password: "); - confirm = KeycloakInstalled.console().passwordPrompt("Confirm local password: "); - if (!password.equals(confirm)) { - KeycloakInstalled.console().writer().println(); - KeycloakInstalled.console().writer().println("Confirmation does not match. Try again."); - KeycloakInstalled.console().writer().println(); - } - } while (!password.equals(confirm)); - try { - this.encrypted = true; - this.encryptionKey = generateEncryptionKey(password); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - } else { - if (!KeycloakInstalled.console().confirm("KC_SESSION_KEY env var already set. Do you want to use this as your local encryption key? (y/n): ")) { - KeycloakInstalled.console().writer().println("Unset KC_SESSION_KEY env var and run again"); - System.exit(1); - } - this.encrypted = true; - this.encryptionKey = getEncryptionKey(); - } - String server = KeycloakInstalled.console().readLine("Authentication server URL [http://localhost:8080/auth]: ").trim(); - String realm = KeycloakInstalled.console().readLine("Name of realm [master]: ").trim(); - String client = KeycloakInstalled.console().readLine("CLI client id [kcinit]: ").trim(); - String secret = KeycloakInstalled.console().readLine("CLI client secret [none]: ").trim(); - if (server.equals("")) { - server = "http://localhost:8080/auth"; - } - if (realm.equals("")) { - realm = "master"; - } - if (client.equals("")) { - client = "kcinit"; - } - File configDir = getTokenDirectory(); - configDir.mkdirs(); - - File configFile = getConfigFile(); - Map props = new HashMap<>(); - props.put("server", server); - props.put("realm", realm); - props.put("client", client); - props.put("secret", secret); - - try { - String json = JsonSerialization.writeValueAsString(props); - writeFile(configFile, json); - } catch (Exception e) { - e.printStackTrace(); - } - - KeycloakInstalled.console().writer().println(); - KeycloakInstalled.console().writer().println("Installation complete!"); - KeycloakInstalled.console().writer().println(); - } - - - public void printHelp() { - KeycloakInstalled.console().writer().println("Commands:"); - KeycloakInstalled.console().writer().println(" login [-f] -f forces login"); - KeycloakInstalled.console().writer().println(" logout"); - KeycloakInstalled.console().writer().println(" token [client] - print access token of desired client. Defaults to default master client. Will print either 'error', 'not-allowed', or 'login-required' on error."); - KeycloakInstalled.console().writer().println(" install - Install this utility. Will store in $HOME/.keycloak/kcinit unless " + KC_LOGIN_CONFIG_PATH + " env var is set"); - System.exit(1); - } - - - public AdapterConfig getConfig() { - File configFile = getConfigFile(); - if (!configFile.exists()) { - KeycloakInstalled.console().writer().println("You have not configured kcinit. Please run 'kcinit install' to configure."); - System.exit(1); - return null; - } - - AdapterConfig config = new AdapterConfig(); - config.setAuthServerUrl(getConfigProperties().get("server")); - config.setRealm(getConfigProperties().get("realm")); - config.setResource(getConfigProperties().get("client")); - config.setSslRequired("external"); - String secret = getConfigProperties().get("secret"); - if (secret != null && !secret.trim().equals("")) { - Map creds = new HashMap<>(); - creds.put("secret", secret); - config.setCredentials(creds); - } else { - config.setPublicClient(true); - } - return config; - } - - private Map getConfigProperties() { - if (this.config != null) return this.config; - if (!getConfigFile().exists()) { - KeycloakInstalled.console().writer().println(); - KeycloakInstalled.console().writer().println(("Config file does not exist. Run kcinit install to set it up.")); - System.exit(1); - } - String json = readFile(getConfigFile()); - try { - Map map = JsonSerialization.readValue(json, Map.class); - config = (Map) map; - } catch (IOException e) { - throw new RuntimeException(e); - } - return this.config; - } - - public String readToken(String client) throws Exception { - String json = getTokenResponse(client); - if (json == null) return null; - - - if (json != null) { - try { - AccessTokenResponse tokenResponse = JsonSerialization.readValue(json, AccessTokenResponse.class); - if (Time.currentTime() < tokenResponse.getExpiresIn()) { - return tokenResponse.getToken(); - } - AdapterConfig config = getConfig(); - KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config)); - installed.refreshToken(tokenResponse.getRefreshToken()); - processResponse(installed, client); - return tokenResponse.getToken(); - } catch (Exception e) { - File tokenFile = getTokenFilePath(client); - if (tokenFile.exists()) { - tokenFile.delete(); - } - - return null; - } - } - return null; - - } - - public String readRefreshToken(String client) throws Exception { - String json = getTokenResponse(client); - if (json == null) return null; - - - if (json != null) { - try { - AccessTokenResponse tokenResponse = JsonSerialization.readValue(json, AccessTokenResponse.class); - return tokenResponse.getRefreshToken(); - } catch (Exception e) { - if (debug) { - e.printStackTrace(); - } - File tokenFile = getTokenFilePath(client); - if (tokenFile.exists()) { - tokenFile.delete(); - } - - return null; - } - } - return null; - - } - - - private String getTokenResponse(String client) { - File tokenFile = getTokenFilePath(client); - try { - return readFile(tokenFile); - } catch (Exception e) { - if (debug) { - System.err.println("Failed to read encrypted file"); - e.printStackTrace(); - } - if (tokenFile.exists()) tokenFile.delete(); - return null; - } - } - - - public void token() throws Exception { - KeycloakInstalled.console().stderrOutput(); - - checkEnv(); - String masterClient = getMasterClient(); - String client = masterClient; - if (args.length > 1) { - client = args[1]; - } - //System.err.println("readToken: " + client); - String token = readToken(client); - if (token != null) { - System.out.print(token); - return; - } - if (token == null && client.equals(masterClient)) { - //System.err.println("not logged in, logging in."); - doConsoleLogin(); - token = readToken(client); - if (token != null) { - System.out.print(token); - return; - } - - } - String masterToken = readToken(masterClient); - if (masterToken == null) { - //System.err.println("not logged in, logging in."); - doConsoleLogin(); - masterToken = readToken(masterClient); - if (masterToken == null) { - System.err.println("Login failed. Cannot retrieve token"); - System.exit(1); - } - } - - //System.err.println("exchange: " + client); - Client httpClient = getHttpClient(); - - WebTarget exchangeUrl = httpClient.target(getServer()) - .path("/realms") - .path(getRealm()) - .path("protocol/openid-connect/token"); - - Form form = new Form() - .param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE) - .param(OAuth2Constants.CLIENT_ID, masterClient) - .param(OAuth2Constants.SUBJECT_TOKEN, masterToken) - .param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE) - .param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.REFRESH_TOKEN_TYPE) - .param(OAuth2Constants.AUDIENCE, client); - if (getMasterClientSecret() != null) { - form.param(OAuth2Constants.CLIENT_SECRET, getMasterClientSecret()); - } - Response response = exchangeUrl.request().post(Entity.form( - form - )); - - if (response.getStatus() == 401 || response.getStatus() == 403) { - response.close(); - System.err.println("Not allowed to exchange for client token"); - System.exit(1); - } - - if (response.getStatus() != 200) { - if (response.getMediaType() != null && response.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) { - try { - String json = response.readEntity(String.class); - OAuth2ErrorRepresentation error = JsonSerialization.readValue(json, OAuth2ErrorRepresentation.class); - System.err.println("Failed to exchange token: " + error.getError() + ". " + error.getErrorDescription()); - System.exit(1); - } catch (Exception ignore) { - ignore.printStackTrace(); - - } - } - - response.close(); - System.err.println("Unknown error exchanging for client token: " + response.getStatus()); - System.exit(1); - } - - String json = response.readEntity(String.class); - response.close(); - AccessTokenResponse tokenResponse = JsonSerialization.readValue(json, AccessTokenResponse.class); - if (tokenResponse.getToken() != null) { - getTokenDirectory().mkdirs(); - tokenResponse.setExpiresIn(Time.currentTime() + tokenResponse.getExpiresIn()); - tokenResponse.setIdToken(null); - json = JsonSerialization.writeValueAsString(tokenResponse); - writeFile(getTokenFilePath(client), json); - System.out.printf(tokenResponse.getToken()); - } else { - System.err.println("Error processing token"); - System.exit(1); - } - } - - protected String getMasterClientSecret() { - return getProperty("secret"); - } - - protected String getServer() { - return getProperty("server"); - } - - protected String getRealm() { - return getProperty("realm"); - } - - public String getProperty(String name) { - return getConfigProperties().get(name); - } - - protected boolean forceLogin() { - return args.length > 0 && args[0].equals("-f"); - - } - - public Client getHttpClient() { - return new ResteasyClientBuilder().disableTrustManager().build(); - } - - public void login() throws Exception { - checkEnv(); - this.args = Arrays.copyOfRange(this.args, 1, this.args.length); - for (String arg : args) { - if (arg.equals("-f") || arg.equals("-force")) { - forceLogin = true; - this.args = Arrays.copyOfRange(this.args, 1, this.args.length); - } else if (arg.equals("-browser") || arg.equals("-b")) { - browserLogin = true; - this.args = Arrays.copyOfRange(this.args, 1, this.args.length); - } else { - System.err.println("Illegal argument: " + arg); - printHelp(); - System.exit(1); - } - } - - String masterClient = getMasterClient(); - if (!forceLogin && readToken(masterClient) != null) { - KeycloakInstalled.console().writer().println("Already logged in. `kcinit -f` to force relogin"); - return; - } - doConsoleLogin(); - KeycloakInstalled.console().writer().println("Login successful!"); - } - - public void doConsoleLogin() throws Exception { - String masterClient = getMasterClient(); - AdapterConfig config = getConfig(); - KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config)); - //System.err.println("calling loginCommandLine"); - if (!installed.loginCommandLine()) { - System.exit(1); - } - processResponse(installed, masterClient); - } - - private String getMasterClient() { - return getProperty("client"); - } - - private void processResponse(KeycloakInstalled installed, String client) throws IOException { - AccessTokenResponse tokenResponse = installed.getTokenResponse(); - tokenResponse.setExpiresIn(Time.currentTime() + tokenResponse.getExpiresIn()); - tokenResponse.setIdToken(null); - String json = JsonSerialization.writeValueAsString(tokenResponse); - getTokenDirectory().mkdirs(); - writeFile(getTokenFilePath(client), json); - } - - public void logout() throws Exception { - String token = readRefreshToken(getMasterClient()); - if (token != null) { - try { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getConfig()); - ServerRequest.invokeLogout(deployment, token); - } catch (Exception e) { - if (debug) { - e.printStackTrace(); - } - } - - } - if (getTokenDirectory().exists()) { - for (File fp : getTokenDirectory().listFiles()) fp.delete(); - } - } - public void uninstall() throws Exception { - File configFile = getConfigFile(); - if (configFile.exists()) configFile.delete(); - if (getTokenDirectory().exists()) { - for (File fp : getTokenDirectory().listFiles()) fp.delete(); - } - } -} diff --git a/adapters/oidc/kcinit/README.md b/adapters/oidc/kcinit/README.md deleted file mode 100755 index fb0fdbecc5..0000000000 --- a/adapters/oidc/kcinit/README.md +++ /dev/null @@ -1,9 +0,0 @@ -CLI Single Sign On -=================================== - -This java-based utility is meant for providing Keycloak integration to -command line applications that are either written in Java or another language. The -idea is that the Java app provided by this utility performs a login for a specific -client, parses responses, and exports an access token as an environment variable -that can be used by the command line utility you are accessing. - diff --git a/adapters/oidc/kcinit/pom.xml b/adapters/oidc/kcinit/pom.xml deleted file mode 100755 index c48f4365df..0000000000 --- a/adapters/oidc/kcinit/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - keycloak-parent - org.keycloak - 16.0.0-SNAPSHOT - ../../../pom.xml - - 4.0.0 - - kcinit - Keycloak CLI SSO Framework - - - - - org.keycloak - keycloak-installed-adapter - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.0.0 - - - - org.keycloak.adapters.KcinitMain - - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - package - - shade - - - - - - - - diff --git a/adapters/oidc/kcinit/src/main/bin/kcinit b/adapters/oidc/kcinit/src/main/bin/kcinit deleted file mode 100755 index 4f5c2c6a72..0000000000 --- a/adapters/oidc/kcinit/src/main/bin/kcinit +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -case "`uname`" in - CYGWIN*) - CFILE = `cygpath "$0"` - RESOLVED_NAME=`readlink -f "$CFILE"` - ;; - Darwin*) - RESOLVED_NAME=`readlink "$0"` - ;; - FreeBSD) - RESOLVED_NAME=`readlink -f "$0"` - ;; - Linux) - RESOLVED_NAME=`readlink -f "$0"` - ;; -esac - -if [ "x$RESOLVED_NAME" = "x" ]; then - RESOLVED_NAME="$0" -fi - -SCRIPTPATH=`dirname "$RESOLVED_NAME"` -JAR=$SCRIPTPATH/kcinit-${project.version}.jar - -java -jar $JAR $@ diff --git a/adapters/oidc/kcinit/src/main/bin/kcinit.bat b/adapters/oidc/kcinit/src/main/bin/kcinit.bat deleted file mode 100755 index 90553091cc..0000000000 --- a/adapters/oidc/kcinit/src/main/bin/kcinit.bat +++ /dev/null @@ -1,8 +0,0 @@ -@echo off - -if "%OS%" == "Windows_NT" ( - set "DIRNAME=%~dp0%" -) else ( - set DIRNAME=.\ -) -java -jar %DIRNAME%\kcinit-${project.version}.jar %* diff --git a/adapters/oidc/kcinit/src/main/java/org/keycloak/adapters/KcinitMain.java b/adapters/oidc/kcinit/src/main/java/org/keycloak/adapters/KcinitMain.java deleted file mode 100644 index 275956f01f..0000000000 --- a/adapters/oidc/kcinit/src/main/java/org/keycloak/adapters/KcinitMain.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016 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.adapters; - -import org.keycloak.adapters.installed.KcinitDriver; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class KcinitMain extends KcinitDriver { - - public static void main(String[] args) throws Exception { - new KcinitMain().mainCmd(args); - } -} diff --git a/adapters/oidc/pom.xml b/adapters/oidc/pom.xml index e031a80f73..66cc0d999f 100755 --- a/adapters/oidc/pom.xml +++ b/adapters/oidc/pom.xml @@ -34,7 +34,6 @@ adapter-core installed fuse7 - kcinit jaxrs-oauth-client jetty js diff --git a/integration/client-cli/admin-cli/src/main/bin/kcadm.sh b/integration/client-cli/admin-cli/src/main/bin/kcadm.sh index 0c905b8514..a7bfc6a48a 100755 --- a/integration/client-cli/admin-cli/src/main/bin/kcadm.sh +++ b/integration/client-cli/admin-cli/src/main/bin/kcadm.sh @@ -22,12 +22,5 @@ fi DIRNAME=`dirname "$RESOLVED_NAME"` -# Uncomment out these lines if you are integrating with `kcinit` -#if [ "$1" = "config" ]; then -# java $KC_OPTS -cp $DIRNAME/client/keycloak-admin-cli-${project.version}.jar org.keycloak.client.admin.cli.KcAdmMain "$@" -#else -# java $KC_OPTS -cp $DIRNAME/client/keycloak-admin-cli-${project.version}.jar org.keycloak.client.admin.cli.KcAdmMain "$@" --noconfig --token $(kcinit token admin-cli) --server $(kcinit show server) -#fi -# Remove the next line if you have enabled kcinit java $KC_OPTS -cp $DIRNAME/client/keycloak-admin-cli-${project.version}.jar org.keycloak.client.admin.cli.KcAdmMain "$@" diff --git a/pom.xml b/pom.xml index eb278e2b19..53c45eedcc 100644 --- a/pom.xml +++ b/pom.xml @@ -1646,17 +1646,6 @@ ${project.version} zip - - org.keycloak - kcinit - ${project.version} - - - org.keycloak - kcinit-dist - ${project.version} - zip - com.webauthn4j diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java index 3ea1a2c49a..b404eeb9a7 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java @@ -124,11 +124,6 @@ public class OIDCLoginProtocolService { return uriBuilder.path(OIDCLoginProtocolService.class, "registrations"); } - public static UriBuilder delegatedUrl(UriInfo uriInfo) { - UriBuilder uriBuilder = tokenServiceBaseUrl(uriInfo); - return uriBuilder.path(OIDCLoginProtocolService.class, "kcinitBrowserLoginComplete"); - } - public static UriBuilder tokenUrl(UriBuilder baseUriBuilder) { UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder); return uriBuilder.path(OIDCLoginProtocolService.class, "token"); @@ -289,33 +284,6 @@ public class OIDCLoginProtocolService { } } - /** - * For KeycloakInstalled and kcinit login where command line login is delegated to a browser. - * This clears login cookies and outputs login success or failure messages. - * - * @param error - * @return - */ - @GET - @Path("delegated") - public Response kcinitBrowserLoginComplete(@QueryParam("error") boolean error) { - AuthenticationManager.expireIdentityCookie(realm, session.getContext().getUri(), clientConnection); - AuthenticationManager.expireRememberMeCookie(realm, session.getContext().getUri(), clientConnection); - if (error) { - LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class); - return forms - .setAttribute("messageHeader", forms.getMessage(Messages.DELEGATION_FAILED_HEADER)) - .setAttribute(Constants.SKIP_LINK, true).setError(Messages.DELEGATION_FAILED).createInfoPage(); - - } else { - LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class); - return forms - .setAttribute("messageHeader", forms.getMessage(Messages.DELEGATION_COMPLETE_HEADER)) - .setAttribute(Constants.SKIP_LINK, true) - .setSuccess(Messages.DELEGATION_COMPLETE).createInfoPage(); - } - } - @Path("ext/{extension}") public Object resolveExtension(@PathParam("extension") String extension) { OIDCExtProvider provider = session.getProvider(OIDCExtProvider.class, extension); diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml index 9e12c34a20..264e1dc232 100644 --- a/testsuite/integration-arquillian/tests/base/pom.xml +++ b/testsuite/integration-arquillian/tests/base/pom.xml @@ -288,43 +288,6 @@ - - com.igormaznitsa - mvn-golang-wrapper - 2.3.4 - true - - 1.9.2 - true - - - - get-mousetrap - - get - - - - github.com/inconshreveable/mousetrap - - ${project.build.directory}/gopath - - - - get-kcinit - - get - - - - github.com/keycloak/kcinit - - ${project.build.directory}/gopath - 0.5 - - - - io.fabric8 docker-maven-plugin diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/cli/KcinitExec.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/cli/KcinitExec.java deleted file mode 100644 index 513eb54d27..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/cli/KcinitExec.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.keycloak.testsuite.cli; - -import org.keycloak.testsuite.cli.exec.AbstractExec; -import org.keycloak.testsuite.cli.exec.AbstractExecBuilder; - -import java.io.InputStream; - -/** - * @author Marko Strukelj - */ -public class KcinitExec extends AbstractExec { - - public static final String WORK_DIR = System.getProperty("user.dir") + "/target"; - - public static final String CMD = OS_ARCH.isWindows() ? "kcinit" : "kcinit"; - - private KcinitExec(String workDir, String argsLine, InputStream stdin) { - this(workDir, argsLine, null, stdin); - } - - private KcinitExec(String workDir, String argsLine, String env, InputStream stdin) { - super(workDir, argsLine, env, stdin); - } - - @Override - public String getCmd() { - return "./" + CMD; - } - - public static KcinitExec.Builder newBuilder() { - return (KcinitExec.Builder) new KcinitExec.Builder().workDir(WORK_DIR); - } - - public static KcinitExec execute(String args) { - return newBuilder() - .argsLine(args) - .execute(); - } - - public static class Builder extends AbstractExecBuilder { - - @Override - public KcinitExec execute() { - KcinitExec exe = new KcinitExec(workDir, argsLine, env, stdin); - exe.dumpStreams = dumpStreams; - exe.execute(); - return exe; - } - - @Override - public KcinitExec executeAsync() { - KcinitExec exe = new KcinitExec(workDir, argsLine, env, stdin); - exe.dumpStreams = dumpStreams; - exe.executeAsync(); - return exe; - } - } -} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java index 4f05f4ebf0..51d6e318b3 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminUnitTest.java @@ -1298,12 +1298,12 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest { private String checkTokenExchange(boolean shouldPass) throws Exception { testingClient.server().run(FineGrainAdminUnitTest::setupTokenExchange); oauth.realm("master"); - oauth.clientId("kcinit"); + oauth.clientId("tokenexclient"); String exchanged = null; String token = oauth.doGrantAccessTokenRequest("password", "admin", "admin").getAccessToken(); Assert.assertNotNull(token); try { - exchanged = oauth.doTokenExchange("master", token, "admin-cli", "kcinit", "password").getAccessToken(); + exchanged = oauth.doTokenExchange("master", token, "admin-cli", "tokenexclient", "password").getAccessToken(); } catch (AssertionError e) { log.info("Error message is expected from oauth: " + e.getMessage()); } @@ -1316,17 +1316,17 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest { private static void setupTokenExchange(KeycloakSession session) { RealmModel realm = session.realms().getRealmByName("master"); - ClientModel client = session.clients().getClientByClientId(realm, "kcinit"); + ClientModel client = session.clients().getClientByClientId(realm, "tokenexclient"); if (client != null) { return; } - ClientModel kcinit = realm.addClient("kcinit"); - kcinit.setEnabled(true); - kcinit.addRedirectUri("http://localhost:*"); - kcinit.setPublicClient(false); - kcinit.setSecret("password"); - kcinit.setDirectAccessGrantsEnabled(true); + ClientModel tokenexclient = realm.addClient("tokenexclient"); + tokenexclient.setEnabled(true); + tokenexclient.addRedirectUri("http://localhost:*"); + tokenexclient.setPublicClient(false); + tokenexclient.setSecret("password"); + tokenexclient.setDirectAccessGrantsEnabled(true); // permission for client to client exchange to "target" client ClientModel adminCli = realm.getClientByClientId(ConfigUtil.DEFAULT_CLIENT); @@ -1334,7 +1334,7 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest { management.clients().setPermissionsEnabled(adminCli, true); ClientPolicyRepresentation clientRep = new ClientPolicyRepresentation(); clientRep.setName("to"); - clientRep.addClient(kcinit.getId()); + clientRep.addClient(tokenexclient.getId()); ResourceServer server = management.realmResourceServer(); Policy clientPolicy = management.authz().getStoreFactory().getPolicyStore().create(clientRep, server); management.clients().exchangeToPermission(adminCli).addAssociatedPolicy(clientPolicy); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/KcinitTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/KcinitTest.java deleted file mode 100644 index bd6d171c43..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/KcinitTest.java +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Copyright 2017 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.testsuite.cli; - -import java.io.File; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.OAuth2Constants; -import org.keycloak.authentication.requiredactions.TermsAndConditions; -import org.keycloak.authorization.model.Policy; -import org.keycloak.authorization.model.ResourceServer; -import org.keycloak.common.Profile; -import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticationFlowBindings; -import org.keycloak.models.AuthenticationFlowModel; -import org.keycloak.models.ClientModel; -import org.keycloak.models.PasswordPolicy; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RequiredActionProviderModel; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.credential.OTPCredentialModel; -import org.keycloak.models.utils.DefaultAuthenticationFlows; -import org.keycloak.models.utils.TimeBasedOTP; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.RequiredActionProviderRepresentation; -import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation; -import org.keycloak.services.resources.admin.AuthenticationManagementResource; -import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement; -import org.keycloak.services.resources.admin.permissions.AdminPermissions; -import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.ProfileAssume; -import org.keycloak.testsuite.actions.DummyRequiredActionFactory; -import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; -import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; -import org.keycloak.testsuite.authentication.PushButtonAuthenticatorFactory; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.util.GreenMailRule; -import org.keycloak.testsuite.util.MailUtils; -import org.keycloak.utils.TotpUtils; -import org.openqa.selenium.By; - -import javax.mail.internet.MimeMessage; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.junit.Assume; -import org.junit.BeforeClass; - -import static org.keycloak.common.Profile.Feature.AUTHORIZATION; - -/** - * Test that clients can override auth flows - * - * @author Bill Burke - */ -@AuthServerContainerExclude(AuthServer.REMOTE) -public class KcinitTest extends AbstractTestRealmKeycloakTest { - - public static final String KCINIT_CLIENT = "kcinit"; - public static final String APP = "app"; - public static final String UNAUTHORIZED_APP = "unauthorized_app"; - @Rule - public AssertEvents events = new AssertEvents(this); - - @Page - protected LoginPage loginPage; - - @BeforeClass - public static void enabled() { - ProfileAssume.assumeFeatureEnabled(AUTHORIZATION); - } - - @Override - public void configureTestRealm(RealmRepresentation testRealm) { - } - - @BeforeClass - public static void kcinitAvailable() { - Assume.assumeTrue(new File(KcinitExec.WORK_DIR + File.separator + KcinitExec.CMD).exists()); - } - - @Before - public void setupFlows() { - RequiredActionProviderRepresentation rep = adminClient.realm("test").flows().getRequiredAction("terms_and_conditions"); - rep.setEnabled(true); - adminClient.realm("test").flows().updateRequiredAction("terms_and_conditions", rep); - - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - - ClientModel client = session.clients().getClientByClientId(realm, "kcinit"); - if (client != null) { - return; - } - - ClientModel kcinit = realm.addClient(KCINIT_CLIENT); - kcinit.setEnabled(true); - kcinit.addRedirectUri("*"); - kcinit.setPublicClient(true); - kcinit.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); - kcinit.removeRole(realm.getRole(OAuth2Constants.OFFLINE_ACCESS)); - - ClientModel app = realm.addClient(APP); - app.setSecret("password"); - app.setEnabled(true); - app.setPublicClient(false); - - ClientModel unauthorizedApp = realm.addClient(UNAUTHORIZED_APP); - unauthorizedApp.setSecret("password"); - unauthorizedApp.setEnabled(true); - unauthorizedApp.setPublicClient(false); - - // permission for client to client exchange to "target" client - AdminPermissionManagement management = AdminPermissions.management(session, realm); - management.clients().setPermissionsEnabled(app, true); - ClientPolicyRepresentation clientRep = new ClientPolicyRepresentation(); - clientRep.setName("to"); - clientRep.addClient(kcinit.getId()); - ResourceServer server = management.realmResourceServer(); - Policy clientPolicy = management.authz().getStoreFactory().getPolicyStore().create(clientRep, server); - management.clients().exchangeToPermission(app).addAssociatedPolicy(clientPolicy); - PasswordPolicy policy = realm.getPasswordPolicy(); - policy = PasswordPolicy.parse(session, "hashIterations(1)"); - realm.setPasswordPolicy(policy); - - UserModel user = session.users().addUser(realm, "bburke"); - session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password")); - user.setEnabled(true); - user.setEmail("p@p.com"); - user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); - user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP); - user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); - user.addRequiredAction(TermsAndConditions.PROVIDER_ID); - user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE); - - user = session.users().addUser(realm, "wburke"); - session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password")); - user.setEnabled(true); - user = session.users().addUser(realm, "tbrady"); - session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password")); - user.setEnabled(true); - user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); - - // Parent flow - AuthenticationFlowModel browser = new AuthenticationFlowModel(); - browser.setAlias("no-console-flow"); - browser.setDescription("browser based authentication"); - browser.setProviderId("basic-flow"); - browser.setTopLevel(true); - browser.setBuiltIn(true); - browser = realm.addAuthenticationFlow(browser); - - AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); - execution.setParentFlow(browser.getId()); - execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); - execution.setPriority(20); - execution.setAuthenticator(PushButtonAuthenticatorFactory.PROVIDER_ID); - realm.addAuthenticatorExecution(execution); - - AuthenticationFlowModel browserBuiltin = realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW); - AuthenticationFlowModel copy = AuthenticationManagementResource.copyFlow(realm, browserBuiltin, "copy-browser"); - copy.setTopLevel(false); - realm.updateAuthenticationFlow(copy); - execution = new AuthenticationExecutionModel(); - execution.setParentFlow(browser.getId()); - execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); - execution.setFlowId(copy.getId()); - execution.setPriority(30); - execution.setAuthenticatorFlow(true); - realm.addAuthenticatorExecution(execution); - - RequiredActionProviderModel action = new RequiredActionProviderModel(); - action.setAlias("dummy"); - action.setEnabled(true); - action.setProviderId(DummyRequiredActionFactory.PROVIDER_ID); - action.setName("dummy"); - action = realm.addRequiredActionProvider(action); - - - }); - } - - //@Test - public void testDemo() throws Exception { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - Map smtp = new HashMap<>(); - smtp.put("host", "smtp.gmail.com"); - smtp.put("port", "465"); - smtp.put("fromDisplayName", "Keycloak SSO"); - smtp.put("from", "****"); - smtp.put("replyToDisplayName", "Keycloak no-reply"); - smtp.put("replyTo", "reply-to@keycloak.org"); - smtp.put("ssl", "true"); - smtp.put("auth", "true"); - smtp.put("user", "*****"); - smtp.put("password", "****"); - realm.setSmtpConfig(smtp); - - }); - - Thread.sleep(100000000); - } - - @Test - public void testBrowserContinueAuthenticator() throws Exception { - // test that we can continue in the middle of a console login that doesn't support console display mode - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - ClientModel kcinit = realm.getClientByClientId(KCINIT_CLIENT); - AuthenticationFlowModel flow = realm.getFlowByAlias("no-console-flow"); - kcinit.setAuthenticationFlowBindingOverride(AuthenticationFlowBindings.BROWSER_BINDING, flow.getId()); - - - }); - //Thread.sleep(100000000); - - try { - - testInstall(); - - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login -f --fake-browser") // --fake-browser is a hidden command so that this test can execute - .executeAsync(); - exe.waitForStderr("Open browser and continue login? [y/n]"); - exe.sendLine("y"); - exe.waitForStdout("http"); - - // the --fake-browser skips launching a browser and outputs url to stdout - String redirect = exe.stdoutString().trim(); - - //System.out.println("********************************"); - //System.out.println("Redirect: " + redirect); - - //redirect.replace("Browser required to complete login", ""); - - driver.navigate().to(redirect.trim()); - - Assert.assertEquals("PushTheButton", driver.getTitle()); - - // Push the button. I am redirected to username+password form - driver.findElement(By.name("submit1")).click(); - //System.out.println("-----"); - //System.out.println(driver.getPageSource()); - - //System.out.println(driver.getTitle()); - - - - loginPage.assertCurrent(); - - // Fill username+password. I am successfully authenticated - try { - oauth.fillLoginForm("wburke", "password"); - } catch (Throwable e) { - e.printStackTrace(); - } - - - String current = driver.getCurrentUrl(); - - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertTrue(driver.getPageSource().contains("Login Successful")); - } finally { - - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - ClientModel kcinit = realm.getClientByClientId(KCINIT_CLIENT); - kcinit.removeAuthenticationFlowBindingOverride(AuthenticationFlowBindings.BROWSER_BINDING); - - - }); - } - } - - @Test - public void testBrowserContinueRequiredAction() throws Exception { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - user.addRequiredAction("dummy"); - }); - testInstall(); - // login - //System.out.println("login...."); - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login -f --fake-browser") - .executeAsync(); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - - exe.waitForStderr("Open browser and continue login? [y/n]"); - exe.sendLine("y"); - exe.waitForStdout("http"); - - // the --fake-browser skips launching a browser and outputs url to stdout - String redirect = exe.stdoutString().trim(); - - driver.navigate().to(redirect.trim()); - - - //System.out.println(exe.stderrString()); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertTrue(driver.getPageSource().contains("Login Successful")); - } - - - - @Test - public void testBadCommand() throws Exception { - KcinitExec exe = KcinitExec.execute("covfefe"); - Assert.assertEquals(1, exe.exitCode()); - Assert.assertEquals("stderr first line", "Error: unknown command \"covfefe\" for \"kcinit\"", exe.stderrLines().get(0)); - } - - //@Test - public void testInstall() throws Exception { - KcinitExec exe = KcinitExec.execute("uninstall"); - Assert.assertEquals(0, exe.exitCode()); - - exe = KcinitExec.newBuilder() - .argsLine("install") - .executeAsync(); - //System.out.println(exe.stderrString()); - //exe.waitForStderr("(y/n):"); - //exe.sendLine("n"); - exe.waitForStderr("Authentication server URL [http://localhost:8080/auth]:"); - exe.sendLine(oauth.AUTH_SERVER_ROOT); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Name of realm [master]:"); - exe.sendLine("test"); - //System.out.println(exe.stderrString()); - exe.waitForStderr("client id [kcinit]:"); - exe.sendLine(""); - //System.out.println(exe.stderrString()); - exe.waitForStderr("secret [none]:"); - exe.sendLine(""); - //System.out.println(exe.stderrString()); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - } - - @Test - public void testOffline() throws Exception { - testInstall(); - // login - //System.out.println("login...."); - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login --offline") - .executeAsync(); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Offline tokens not allowed for the user or client"); - exe.waitCompletion(); - Assert.assertEquals(1, exe.exitCode()); - } - - - - @Test - public void testBasic() throws Exception { - testInstall(); - // login - //System.out.println("login...."); - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - //System.out.println(exe.stderrString()); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - - if (Profile.isFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE)) { - exe = KcinitExec.execute("token"); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(1, exe.stdoutLines().size()); - String token = exe.stdoutLines().get(0).trim(); - //System.out.println("token: " + token); - - exe = KcinitExec.execute("token app"); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(1, exe.stdoutLines().size()); - String appToken = exe.stdoutLines().get(0).trim(); - Assert.assertFalse(appToken.equals(token)); - //System.out.println("token: " + token); - - - exe = KcinitExec.execute("token badapp"); - Assert.assertEquals(1, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - Assert.assertEquals(1, exe.stderrLines().size()); - Assert.assertTrue(exe.stderrLines().get(0), exe.stderrLines().get(0).contains("failed to exchange token: invalid_client Audience not found")); - } - - exe = KcinitExec.execute("logout"); - Assert.assertEquals(0, exe.exitCode()); - - - - - } - - @Test - public void testTerms() throws Exception { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - user.addRequiredAction(TermsAndConditions.PROVIDER_ID); - }); - - testInstall(); - - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - exe.waitForStderr("Accept Terms? [y/n]:"); - exe.sendLine("y"); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - } - - - @Test - public void testUpdateProfile() throws Exception { - // expects that updateProfile is a passthrough - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE); - }); - - try { - testInstall(); - - //Thread.sleep(100000000); - - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - try { - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - } catch (Exception ex) { - System.out.println(exe.stderrString()); - throw ex; - } - } finally { - - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - user.removeRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE); - }); - } - } - - - @Test - public void testUpdatePassword() throws Exception { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); - }); - - try { - testInstall(); - - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - exe.waitForStderr("New Password:"); - exe.sendLine("pw"); - exe.waitForStderr("Confirm Password:"); - exe.sendLine("pw"); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - - exe = KcinitExec.newBuilder() - .argsLine("login -f") - .executeAsync(); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - exe.waitForStderr("Password:"); - exe.sendLine("pw"); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - - exe = KcinitExec.execute("logout"); - Assert.assertEquals(0, exe.exitCode()); - } finally { - - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password")); - }); - } - - } - - protected TimeBasedOTP totp = new TimeBasedOTP(); - - - @Test - public void testConfigureTOTP() throws Exception { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP); - }); - - try { - - testInstall(); - - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - exe.waitForStderr("One Time Password:"); - - Pattern p = Pattern.compile("Open the application and enter the key:\\s+(.+)\\s+Use the following configuration values"); - //Pattern p = Pattern.compile("Open the application and enter the key:"); - - String stderr = exe.stderrString(); - //System.out.println("***************"); - //System.out.println(stderr); - //System.out.println("***************"); - Matcher m = p.matcher(stderr); - Assert.assertTrue(m.find()); - String otpSecret = m.group(1).trim(); - - //System.out.println("***************"); - //System.out.println(otpSecret); - //System.out.println("***************"); - - otpSecret = TotpUtils.decode(otpSecret); - String code = totp.generateTOTP(otpSecret); - //System.out.println("***************"); - //System.out.println("code: " + code); - //System.out.println("***************"); - exe.sendLine(code); - Thread.sleep(100); - //stderr = exe.stderrString(); - //System.out.println("***************"); - //System.out.println(stderr); - //System.out.println("***************"); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - - - exe = KcinitExec.execute("logout"); - Assert.assertEquals(0, exe.exitCode()); - - exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - exe.waitForStderr("Username:"); - exe.sendLine("wburke"); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - exe.waitForStderr("One Time Password:"); - exe.sendLine(totp.generateTOTP(otpSecret)); - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - - exe = KcinitExec.execute("logout"); - Assert.assertEquals(0, exe.exitCode()); - } finally { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "wburke"); - session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE) - .collect(Collectors.toList()) - .forEach(model -> session.userCredentialManager().removeStoredCredential(realm, user, model.getId())); - }); - } - - - } - - @Rule - public GreenMailRule greenMail = new GreenMailRule(); - - @Test - public void testVerifyEmail() throws Exception { - testingClient.server().run(session -> { - RealmModel realm = session.realms().getRealmByName("test"); - UserModel user = session.users().getUserByUsername(realm, "test-user@localhost"); - user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); - }); - - testInstall(); - - KcinitExec exe = KcinitExec.newBuilder() - .argsLine("login") - .executeAsync(); - exe.waitForStderr("Username:"); - exe.sendLine("test-user@localhost"); - exe.waitForStderr("Password:"); - exe.sendLine("password"); - exe.waitForStderr("Email Code:"); - - Assert.assertEquals(1, greenMail.getReceivedMessages().length); - - MimeMessage message = greenMail.getReceivedMessages()[0]; - - String text = MailUtils.getBody(message).getText(); - Assert.assertTrue(text.contains("Please verify your email address by entering in the following code.")); - String code = text.substring("Please verify your email address by entering in the following code.".length()).trim(); - - exe.sendLine(code); - - exe.waitForStderr("Login successful"); - exe.waitCompletion(); - Assert.assertEquals(0, exe.exitCode()); - Assert.assertEquals(0, exe.stdoutLines().size()); - - - exe = KcinitExec.execute("logout"); - Assert.assertEquals(0, exe.exitCode()); - } - - - - -} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java index 8917f210b2..e189a292d3 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegConfigTest.java @@ -85,4 +85,4 @@ public class KcRegConfigTest extends AbstractRegCliTest { Assert.assertEquals("try help", "Try '" + CMD + " help config initial-token' for more information", exe.stderrLines().get(1)); } -} \ No newline at end of file +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTokenTest.java index 40e52fde4e..415fe9d83d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTokenTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/registration/KcRegUpdateTokenTest.java @@ -68,4 +68,4 @@ public class KcRegUpdateTokenTest extends AbstractRegCliTest { Assert.assertEquals("client representation returned", "reg-cli-secret-direct", client.getClientId()); } } -} \ No newline at end of file +}