KEYCLOAK-5354 (#4440)
This commit is contained in:
1 parent
801205a5bc
commit
433a8dd2e3
20 files changed
+307
-57
No files matched your search
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* 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.testsuite;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.Undertow.Builder;
|
||||
import io.undertow.servlet.Servlets;
|
||||
import io.undertow.servlet.api.DefaultServletConfig;
|
||||
import io.undertow.servlet.api.DeploymentInfo;
|
||||
import io.undertow.servlet.api.FilterInfo;
|
||||
import io.undertow.servlet.api.ServletInfo;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher;
|
||||
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
import org.keycloak.common.Version;
|
||||
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.testsuite.util.cli.TestsuiteCLI;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class KeycloakServer {
|
||||
|
||||
private static final Logger log = Logger.getLogger(KeycloakServer.class);
|
||||
|
||||
private boolean sysout = false;
|
||||
|
||||
public static class KeycloakServerConfig {
|
||||
private String host = "localhost";
|
||||
private int port = 8081;
|
||||
private int portHttps = -1;
|
||||
private int workerThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2) * 8;
|
||||
private String resourcesHome;
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public int getPortHttps() {
|
||||
return portHttps;
|
||||
}
|
||||
|
||||
public String getResourcesHome() {
|
||||
return resourcesHome;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setPortHttps(int portHttps) {
|
||||
this.portHttps = portHttps;
|
||||
}
|
||||
|
||||
public void setResourcesHome(String resourcesHome) {
|
||||
this.resourcesHome = resourcesHome;
|
||||
}
|
||||
|
||||
public int getWorkerThreads() {
|
||||
return workerThreads;
|
||||
}
|
||||
|
||||
public void setWorkerThreads(int workerThreads) {
|
||||
this.workerThreads = workerThreads;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T loadJson(InputStream is, Class<T> type) {
|
||||
try {
|
||||
return JsonSerialization.readValue(is, type);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to parse json", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (!System.getenv().containsKey("MAVEN_CMD_LINE_ARGS")) {
|
||||
Version.BUILD_TIME = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date());
|
||||
}
|
||||
|
||||
bootstrapKeycloakServer(args);
|
||||
}
|
||||
|
||||
public static KeycloakServer bootstrapKeycloakServer(String[] args) throws Throwable {
|
||||
File f = new File(System.getProperty("user.home"), ".keycloak-server.properties");
|
||||
if (f.isFile()) {
|
||||
Properties p = new Properties();
|
||||
p.load(new FileInputStream(f));
|
||||
System.getProperties().putAll(p);
|
||||
}
|
||||
|
||||
KeycloakServerConfig config = new KeycloakServerConfig();
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].equals("-b")) {
|
||||
config.setHost(args[++i]);
|
||||
}
|
||||
|
||||
if (args[i].equals("-p")) {
|
||||
config.setPort(Integer.valueOf(args[++i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (System.getProperty("keycloak.port") != null) {
|
||||
config.setPort(Integer.valueOf(System.getProperty("keycloak.port")));
|
||||
}
|
||||
|
||||
if (System.getProperty("keycloak.port.https") != null) {
|
||||
config.setPortHttps(Integer.valueOf(System.getProperty("keycloak.port.https")));
|
||||
}
|
||||
|
||||
if (System.getProperty("keycloak.bind.address") != null) {
|
||||
config.setHost(System.getProperty("keycloak.bind.address"));
|
||||
}
|
||||
|
||||
if (System.getenv("KEYCLOAK_DEV_PORT") != null) {
|
||||
config.setPort(Integer.valueOf(System.getenv("KEYCLOAK_DEV_PORT")));
|
||||
}
|
||||
|
||||
if (System.getProperties().containsKey("resources")) {
|
||||
String resources = System.getProperty("resources");
|
||||
if (resources == null || resources.equals("") || resources.equals("true")) {
|
||||
if (System.getProperties().containsKey("maven.home")) {
|
||||
resources = System.getProperty("user.dir").replaceFirst("testsuite.utils.*", "");
|
||||
} else {
|
||||
for (String c : System.getProperty("java.class.path").split(File.pathSeparator)) {
|
||||
if (c.contains(File.separator + "testsuite" + File.separator + "utils")) {
|
||||
resources = c.replaceFirst("testsuite.utils.*", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File dir = new File(resources).getAbsoluteFile();
|
||||
if (!dir.isDirectory()) {
|
||||
throw new RuntimeException("Invalid base resources directory");
|
||||
|
||||
}
|
||||
if (!new File(dir, "themes").isDirectory()) {
|
||||
throw new RuntimeException("Invalid resources forms directory");
|
||||
}
|
||||
|
||||
if (!System.getProperties().containsKey("keycloak.theme.dir")) {
|
||||
System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "themes", "src", "main", "resources", "theme").getAbsolutePath());
|
||||
} else {
|
||||
String foo = System.getProperty("keycloak.theme.dir");
|
||||
System.out.println(foo);
|
||||
}
|
||||
|
||||
if (!System.getProperties().containsKey("keycloak.theme.cacheTemplates")) {
|
||||
System.setProperty("keycloak.theme.cacheTemplates", "false");
|
||||
}
|
||||
|
||||
if (!System.getProperties().containsKey("keycloak.theme.cacheThemes")) {
|
||||
System.setProperty("keycloak.theme.cacheThemes", "false");
|
||||
}
|
||||
|
||||
if (!System.getProperties().containsKey("keycloak.theme.staticMaxAge")) {
|
||||
System.setProperty("keycloak.theme.staticMaxAge", "-1");
|
||||
}
|
||||
|
||||
config.setResourcesHome(dir.getAbsolutePath());
|
||||
}
|
||||
|
||||
if (System.getProperties().containsKey("undertowWorkerThreads")) {
|
||||
int undertowWorkerThreads = Integer.parseInt(System.getProperty("undertowWorkerThreads"));
|
||||
config.setWorkerThreads(undertowWorkerThreads);
|
||||
}
|
||||
|
||||
detectNodeName(config);
|
||||
|
||||
final KeycloakServer keycloak = new KeycloakServer(config);
|
||||
keycloak.sysout = true;
|
||||
keycloak.start();
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].equals("-import")) {
|
||||
keycloak.importRealm(new FileInputStream(args[++i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (System.getProperties().containsKey("import")) {
|
||||
keycloak.importRealm(new FileInputStream(System.getProperty("import")));
|
||||
}
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
keycloak.stop();
|
||||
}
|
||||
});
|
||||
|
||||
if (System.getProperties().containsKey("startTestsuiteCLI")) {
|
||||
new TestsuiteCLI(keycloak).start();
|
||||
}
|
||||
|
||||
return keycloak;
|
||||
}
|
||||
|
||||
private KeycloakServerConfig config;
|
||||
|
||||
private KeycloakSessionFactory sessionFactory;
|
||||
|
||||
private UndertowJaxrsServer server;
|
||||
|
||||
public KeycloakServer() {
|
||||
this(new KeycloakServerConfig());
|
||||
}
|
||||
|
||||
public KeycloakServer(KeycloakServerConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public KeycloakSessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
public UndertowJaxrsServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public KeycloakServerConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void importRealm(InputStream realm) {
|
||||
RealmRepresentation rep = loadJson(realm, RealmRepresentation.class);
|
||||
importRealm(rep);
|
||||
}
|
||||
|
||||
public void importRealm(RealmRepresentation rep) {
|
||||
KeycloakSession session = sessionFactory.create();;
|
||||
session.getTransactionManager().begin();
|
||||
|
||||
try {
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
||||
if (rep.getId() != null && manager.getRealm(rep.getId()) != null) {
|
||||
info("Not importing realm " + rep.getRealm() + " realm already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager.getRealmByName(rep.getRealm()) != null) {
|
||||
info("Not importing realm " + rep.getRealm() + " realm already exists");
|
||||
return;
|
||||
}
|
||||
manager.setContextPath("/auth");
|
||||
RealmModel realm = manager.importRealm(rep);
|
||||
|
||||
info("Imported realm " + realm.getName());
|
||||
|
||||
session.getTransactionManager().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupDevConfig() {
|
||||
if (System.getProperty("keycloak.createAdminUser", "true").equals("true")) {
|
||||
KeycloakSession session = sessionFactory.create();
|
||||
try {
|
||||
session.getTransactionManager().begin();
|
||||
if (new ApplianceBootstrap(session).isNoMasterUser()) {
|
||||
new ApplianceBootstrap(session).createMasterRealmUser("admin", "admin");
|
||||
}
|
||||
session.getTransactionManager().commit();
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start() throws Throwable {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
ResteasyDeployment deployment = new ResteasyDeployment();
|
||||
deployment.setApplicationClass(KeycloakApplication.class.getName());
|
||||
|
||||
Builder builder = Undertow.builder()
|
||||
.addHttpListener(config.getPort(), config.getHost())
|
||||
.setWorkerThreads(config.getWorkerThreads())
|
||||
.setIoThreads(config.getWorkerThreads() / 8);
|
||||
|
||||
if (config.getPortHttps() != -1) {
|
||||
builder = builder.addHttpsListener(config.getPortHttps(), config.getHost(), SSLContext.getDefault());
|
||||
}
|
||||
|
||||
server = new UndertowJaxrsServer();
|
||||
try {
|
||||
server.start(builder);
|
||||
|
||||
DeploymentInfo di = server.undertowDeployment(deployment, "");
|
||||
di.setClassLoader(getClass().getClassLoader());
|
||||
di.setContextPath("/auth");
|
||||
di.setDeploymentName("Keycloak");
|
||||
di.setDefaultEncoding("UTF-8");
|
||||
|
||||
di.addInitParameter(KeycloakApplication.KEYCLOAK_EMBEDDED, "true");
|
||||
|
||||
di.setDefaultServletConfig(new DefaultServletConfig(true));
|
||||
|
||||
ServletInfo restEasyDispatcher = Servlets.servlet("Keycloak REST Interface", HttpServlet30Dispatcher.class);
|
||||
|
||||
restEasyDispatcher.addInitParam("resteasy.servlet.mapping.prefix", "/");
|
||||
restEasyDispatcher.setAsyncSupported(true);
|
||||
|
||||
di.addServlet(restEasyDispatcher);
|
||||
|
||||
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
|
||||
|
||||
filter.setAsyncSupported(true);
|
||||
|
||||
di.addFilter(filter);
|
||||
di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
|
||||
|
||||
server.deploy(di);
|
||||
|
||||
sessionFactory = ((KeycloakApplication) deployment.getApplication()).getSessionFactory();
|
||||
|
||||
setupDevConfig();
|
||||
|
||||
if (config.getResourcesHome() != null) {
|
||||
info("Loading resources from " + config.getResourcesHome());
|
||||
}
|
||||
|
||||
info("Started Keycloak (http://" + config.getHost() + ":" + config.getPort() + "/auth"
|
||||
+ (config.getPortHttps() > 0 ? ", https://" + config.getHost() + ":" + config.getPortHttps()+ "/auth" : "")
|
||||
+ ") in "
|
||||
+ (System.currentTimeMillis() - start) + " ms\n");
|
||||
} catch (RuntimeException e) {
|
||||
server.stop();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void info(String message) {
|
||||
if (sysout) {
|
||||
System.out.println(message);
|
||||
} else {
|
||||
log.info(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
sessionFactory.close();
|
||||
server.stop();
|
||||
|
||||
info("Stopped Keycloak");
|
||||
}
|
||||
|
||||
private static File file(String... path) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (String p : path) {
|
||||
s.append(File.separator);
|
||||
s.append(p);
|
||||
}
|
||||
return new File(s.toString());
|
||||
}
|
||||
|
||||
|
||||
private static void detectNodeName(KeycloakServerConfig config) {
|
||||
String nodeName = System.getProperty(InfinispanConnectionProvider.JBOSS_NODE_NAME);
|
||||
if (nodeName == null) {
|
||||
// Try to autodetect "jboss.node.name" from the port
|
||||
Map<Integer, String> nodesCfg = new HashMap<>();
|
||||
nodesCfg.put(8181, "node1");
|
||||
nodesCfg.put(8182, "node2");
|
||||
|
||||
nodeName = nodesCfg.get(config.getPort());
|
||||
if (nodeName != null) {
|
||||
System.setProperty(InfinispanConnectionProvider.JBOSS_NODE_NAME, nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeName != null) {
|
||||
log.infof("Node name: %s", nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.testsuite;
|
||||
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.ServerSetup;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMessage.RecipientType;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
|
||||
public class MailServer {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ServerSetup setup = new ServerSetup(3025, "localhost", "smtp");
|
||||
|
||||
GreenMail greenMail = new GreenMail(setup);
|
||||
greenMail.start();
|
||||
|
||||
System.out.println("Started mail server (localhost:3025)");
|
||||
System.out.println();
|
||||
|
||||
while (true) {
|
||||
int c = greenMail.getReceivedMessages().length;
|
||||
|
||||
if (greenMail.waitForIncomingEmail(Long.MAX_VALUE, c + 1)) {
|
||||
MimeMessage message = greenMail.getReceivedMessages()[c++];
|
||||
System.out.println("-------------------------------------------------------");
|
||||
System.out.println("Received mail to " + message.getRecipients(RecipientType.TO)[0]);
|
||||
if (message.getContent() instanceof MimeMultipart) {
|
||||
MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
|
||||
for (int i = 0; i < mimeMultipart.getCount(); i++) {
|
||||
System.out.println("----");
|
||||
System.out.println(mimeMultipart.getBodyPart(i).getContentType() + ":");
|
||||
System.out.println();
|
||||
System.out.println(mimeMultipart.getBodyPart(i).getContent());
|
||||
}
|
||||
} else {
|
||||
System.out.println();
|
||||
System.out.println(message.getContent());
|
||||
}
|
||||
System.out.println("-------------------------------------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.testsuite;
|
||||
|
||||
import org.keycloak.models.utils.Base32;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
public class TotpGenerator {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
Timer timer = new Timer();
|
||||
TotpTask task = null;
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
||||
|
||||
System.out.print("Insert secret: ");
|
||||
for (String l = br.readLine(); true; l = br.readLine()) {
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
System.out.println("Secret: " + l);
|
||||
task = new TotpTask(l);
|
||||
timer.schedule(task, 0, TimeUnit.SECONDS.toMillis(TimeBasedOTP.DEFAULT_INTERVAL_SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
private static class TotpTask extends TimerTask {
|
||||
private String secret;
|
||||
|
||||
private TotpTask(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String google = new String(Base32.decode(secret));
|
||||
TimeBasedOTP otp = new TimeBasedOTP();
|
||||
System.out.println(otp.generateTOTP(google));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractCommand {
|
||||
|
||||
protected final Logger log = Logger.getLogger(this.getClass().getName());
|
||||
|
||||
protected List<String> args;
|
||||
protected KeycloakSessionFactory sessionFactory;
|
||||
|
||||
public void injectProperties(List<String> args, TestsuiteCLI cli, KeycloakSessionFactory sessionFactory) {
|
||||
this.args = args;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
public void runCommand() {
|
||||
try {
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
public void run(KeycloakSession session) {
|
||||
doRunCommand(session);
|
||||
}
|
||||
|
||||
});
|
||||
} catch (HandledException handled) {
|
||||
// Fine to ignore. Was handled already
|
||||
} catch (RuntimeException e) {
|
||||
log.error("Error occured during command. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
protected abstract void doRunCommand(KeycloakSession session);
|
||||
|
||||
protected String getArg(int index) {
|
||||
try {
|
||||
return args.get(index);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
log.errorf("Usage: %s", printUsage());
|
||||
throw new HandledException();
|
||||
}
|
||||
}
|
||||
|
||||
protected Integer getIntArg(int index) {
|
||||
String str = getArg(index);
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
} catch (NumberFormatException nex) {
|
||||
log.errorf("Usage: %s", printUsage());
|
||||
throw new HandledException();
|
||||
}
|
||||
}
|
||||
|
||||
public String printUsage() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
public static class HandledException extends RuntimeException {
|
||||
}
|
||||
|
||||
}
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.infinispan.AdvancedCache;
|
||||
import org.infinispan.Cache;
|
||||
import org.infinispan.context.Flag;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
|
||||
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractSessionCacheCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
String cacheName = getArg(0);
|
||||
if (!cacheName.equals(InfinispanConnectionProvider.SESSION_CACHE_NAME) && !cacheName.equals(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME)) {
|
||||
log.errorf("Invalid cache name: '%s', Only cache names '%s' or '%s' are supported", cacheName, InfinispanConnectionProvider.SESSION_CACHE_NAME,
|
||||
InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
Cache<String, SessionEntityWrapper> ispnCache = provider.getCache(cacheName);
|
||||
doRunCacheCommand(session, ispnCache);
|
||||
|
||||
ispnCache.entrySet().stream().skip(0).limit(10).collect(java.util.stream.Collectors.toMap(new java.util.function.Function() {
|
||||
|
||||
public Object apply(Object entry) {
|
||||
return ((java.util.Map.Entry) entry).getKey();
|
||||
}
|
||||
}, new java.util.function.Function() {
|
||||
|
||||
public Object apply(Object entry) {
|
||||
return ((java.util.Map.Entry) entry).getValue();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected void printSession(String id, UserSessionEntity userSession) {
|
||||
if (userSession == null) {
|
||||
log.info("Not found session with Id: " + id);
|
||||
} else {
|
||||
log.info("Found session. ID: " + toString(userSession));
|
||||
}
|
||||
}
|
||||
|
||||
protected String toString(UserSessionEntity userSession) {
|
||||
int clientSessionsSize = userSession.getAuthenticatedClientSessions()==null ? 0 : userSession.getAuthenticatedClientSessions().size();
|
||||
return "ID: " + userSession.getId() + ", realm: " + userSession.getRealm() + ", lastAccessTime: " + Time.toDate(userSession.getLastSessionRefresh()) +
|
||||
", authenticatedClientSessions: " + clientSessionsSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name>";
|
||||
}
|
||||
|
||||
protected abstract void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache);
|
||||
|
||||
|
||||
// IMPLS
|
||||
|
||||
public static class PutCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "put";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
UserSessionEntity userSession = new UserSessionEntity();
|
||||
String id = getArg(1);
|
||||
|
||||
userSession.setId(id);
|
||||
userSession.setRealm(getArg(2));
|
||||
|
||||
userSession.setLastSessionRefresh(Time.currentTime());
|
||||
cache.put(id, new SessionEntityWrapper(userSession));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <user-session-id> <realm-name>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class GetCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "get";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
String id = getArg(1);
|
||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id).getEntity();
|
||||
printSession(id, userSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <user-session-id>";
|
||||
}
|
||||
}
|
||||
|
||||
// Just to check performance of multiple get calls. And comparing what's the change between the case when item is available locally or not.
|
||||
public static class GetMultipleCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "getMulti";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
String id = getArg(1);
|
||||
int count = getIntArg(2);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i=0 ; i<count ; i++) {
|
||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id).getEntity();
|
||||
//printSession(id, userSession);
|
||||
}
|
||||
long took = System.currentTimeMillis() - start;
|
||||
log.infof("Took %d milliseconds", took);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <user-session-id> <count-of-gets>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class RemoveCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "remove";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
String id = getArg(1);
|
||||
cache.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <user-session-id>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ClearCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "clear";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SizeCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "size";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
log.info("Size: " + cache.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ListCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "list";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
for (String id : cache.keySet()) {
|
||||
SessionEntity entity = cache.get(id).getEntity();
|
||||
if (!(entity instanceof UserSessionEntity)) {
|
||||
continue;
|
||||
}
|
||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id).getEntity();
|
||||
log.info("list: key=" + id + ", value=" + toString(userSession));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class GetLocalCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "getLocal";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
String id = getArg(1);
|
||||
cache = ((AdvancedCache) cache).withFlags(Flag.CACHE_MODE_LOCAL);
|
||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id).getEntity();
|
||||
printSession(id, userSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <user-session-id>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SizeLocalCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "sizeLocal";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
log.info("Size local: " + cache.getAdvancedCache().withFlags(Flag.CACHE_MODE_LOCAL).size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class CreateManySessionsCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "createManySessions";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
String realmName = getArg(1);
|
||||
int count = getIntArg(2);
|
||||
int batchCount = getIntArg(3);
|
||||
|
||||
BatchTaskRunner.runInBatches(0, count, batchCount, session.getKeycloakSessionFactory(), (KeycloakSession batchSession, int firstInIteration, int countInIteration) -> {
|
||||
for (int i=0 ; i<countInIteration ; i++) {
|
||||
UserSessionEntity userSession = new UserSessionEntity();
|
||||
String id = KeycloakModelUtils.generateId();
|
||||
|
||||
userSession.setId(id);
|
||||
userSession.setRealm(realmName);
|
||||
|
||||
userSession.setLastSessionRefresh(Time.currentTime());
|
||||
cache.put(id, new SessionEntityWrapper(userSession));
|
||||
}
|
||||
|
||||
log.infof("Created '%d' sessions started from offset '%d'", countInIteration, firstInIteration);
|
||||
});
|
||||
|
||||
log.infof("Created all '%d' sessions", count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <realm-name> <count> <count-in-batch>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// This will propagate creating sessions to remoteCache too
|
||||
public static class CreateManySessionsProviderCommand extends AbstractSessionCacheCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "createManySessionsProvider";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
|
||||
String realmName = getArg(1);
|
||||
String clientId = getArg(2);
|
||||
String username = getArg(3);
|
||||
int count = getIntArg(4);
|
||||
int batchCount = getIntArg(5);
|
||||
|
||||
BatchTaskRunner.runInBatches(0, count, batchCount, session.getKeycloakSessionFactory(), (KeycloakSession batchSession, int firstInIteration, int countInIteration) -> {
|
||||
RealmModel realm = batchSession.realms().getRealmByName(realmName);
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
UserModel user = batchSession.users().getUserByUsername(username, realm);
|
||||
|
||||
for (int i=0 ; i<countInIteration ; i++) {
|
||||
UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, user, username, "127.0.0.1", "form", false, null, null);
|
||||
|
||||
session.sessions().createClientSession(userSession.getRealm(), client, userSession);
|
||||
}
|
||||
|
||||
log.infof("Created '%d' sessions started from offset '%d'", countInIteration, firstInIteration);
|
||||
});
|
||||
|
||||
log.infof("Created all '%d' sessions", count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName() + " <cache-name> <realm-name> <client-id> <user-name> <count> <count-in-batch>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
class BatchTaskRunner {
|
||||
|
||||
static void runInBatches(int first, int count, int batchCount, KeycloakSessionFactory sessionFactory, BatchTask batchTask) {
|
||||
|
||||
final StateHolder state = new StateHolder();
|
||||
state.firstInThisBatch = first;
|
||||
state.remaining = count;
|
||||
state.countInThisBatch = Math.min(batchCount, state.remaining);
|
||||
while (state.remaining > 0) {
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
public void run(KeycloakSession session) {
|
||||
batchTask.run(session, state.firstInThisBatch, state.countInThisBatch);
|
||||
}
|
||||
});
|
||||
|
||||
// update state
|
||||
state.firstInThisBatch = state.firstInThisBatch + state.countInThisBatch;
|
||||
state.remaining = state.remaining - state.countInThisBatch;
|
||||
state.countInThisBatch = Math.min(batchCount, state.remaining);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StateHolder {
|
||||
int firstInThisBatch;
|
||||
int countInThisBatch;
|
||||
int remaining;
|
||||
};
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BatchTask {
|
||||
|
||||
void run(KeycloakSession session, int firstInThisIteration, int countInThisIteration);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.infinispan.Cache;
|
||||
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class CacheCommands {
|
||||
|
||||
public static class ListCachesCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "listCaches";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
InfinispanConnectionProvider ispnProvider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
Set<String> cacheNames = ispnProvider.getCache("realms").getCacheManager().getCacheNames();
|
||||
log.infof("Available caches: %s", cacheNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class GetCacheCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "getCache";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
String cacheName = getArg(0);
|
||||
InfinispanConnectionProvider ispnProvider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
Cache<Object, Object> cache = ispnProvider.getCache(cacheName);
|
||||
if (cache == null) {
|
||||
log.errorf("Cache '%s' doesn't exist", cacheName);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
printCache(cache);
|
||||
}
|
||||
|
||||
private void printCache(Cache<Object, Object> cache) {
|
||||
int size = cache.size();
|
||||
log.infof("Cache %s, size: %d", cache.getName(), size);
|
||||
|
||||
if (size > 50) {
|
||||
log.info("Skip printing cache records due to big size");
|
||||
} else {
|
||||
for (Map.Entry<Object, Object> entry : cache.entrySet()) {
|
||||
log.infof("%s=%s", entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <cache-name> . cache-name is name of the infinispan cache provided by InfinispanConnectionProvider";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class CacheRealmObjectsCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "cacheRealmObjects";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
String realmName = getArg(0);
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
log.errorf("Realm not found: %s", realmName);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
TestCacheUtils.cacheRealmWithEverything(session, realmName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <realm-name>";
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.keycloak.cluster.ClusterProvider;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClusterProviderTaskCommand extends AbstractCommand {
|
||||
|
||||
private static final ExecutorService executors = Executors.newCachedThreadPool();
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
String taskName = getArg(0);
|
||||
int taskTimeout = getIntArg(1);
|
||||
int sleepTime = getIntArg(2);
|
||||
|
||||
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
|
||||
Future future = cluster.executeIfNotExecutedAsync(taskName, taskTimeout, () -> {
|
||||
log.infof("Started sleeping for " + sleepTime + " seconds");
|
||||
Thread.sleep(sleepTime * 1000);
|
||||
log.infof("Stopped sleeping");
|
||||
return null;
|
||||
});
|
||||
|
||||
log.info("I've retrieved future successfully");
|
||||
|
||||
executors.execute(() -> {
|
||||
try {
|
||||
future.get();
|
||||
log.info("Successfully finished future!");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateConfig(MultivaluedHashMap<String, String> cfg, int waitTime) {
|
||||
cfg.putSingle("wait-time", String.valueOf(waitTime));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "clusterProviderTask";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <task-name> <task-wait-time-in-seconds> <sleep-time-in-seconds>";
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.UserSessionProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class LoadPersistentSessionsCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "loadPersistentSessions";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
int sessionsPerSegment = getIntArg(0);
|
||||
UserSessionProviderFactory sessionProviderFactory = (UserSessionProviderFactory) sessionFactory.getProviderFactory(UserSessionProvider.class);
|
||||
sessionProviderFactory.loadPersistentSessions(sessionFactory, 10, sessionsPerSegment);
|
||||
|
||||
log.info("All persistent sessions loaded successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <sessions-count-per-segment>";
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class PersistSessionsCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "persistSessions";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRunCommand(KeycloakSession sess) {
|
||||
final int count = getIntArg(0);
|
||||
final int batchCount = getIntArg(1);
|
||||
|
||||
int remaining = count;
|
||||
|
||||
while (remaining > 0) {
|
||||
int createInThisBatch = Math.min(batchCount, remaining);
|
||||
createSessionsBatch(createInThisBatch);
|
||||
remaining = remaining - createInThisBatch;
|
||||
}
|
||||
|
||||
// Write some summary
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
public void run(KeycloakSession session) {
|
||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||
log.info("Command finished. Total number of sessions in persister: " + persister.getUserSessionsCount(true));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void createSessionsBatch(final int countInThisBatch) {
|
||||
final List<String> userSessionIds = new LinkedList<>();
|
||||
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
public void run(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName("master");
|
||||
UserModel john = session.users().getUserByUsername("admin", realm);
|
||||
ClientModel testApp = realm.getClientByClientId("security-admin-console");
|
||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||
|
||||
for (int i = 0; i < countInThisBatch; i++) {
|
||||
UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, john, "john-doh@localhost", "127.0.0.2", "form", true, null, null);
|
||||
AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, testApp, userSession);
|
||||
clientSession.setRedirectUri("http://redirect");
|
||||
clientSession.setNote("foo", "bar-" + i);
|
||||
userSessionIds.add(userSession.getId());
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
log.infof("%d sessions created in infinispan storage", countInThisBatch);
|
||||
|
||||
// Persist them now
|
||||
|
||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||
|
||||
@Override
|
||||
public void run(KeycloakSession session) {
|
||||
RealmModel realm = session.realms().getRealmByName("master");
|
||||
ClientModel testApp = realm.getClientByClientId("security-admin-console");
|
||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||
|
||||
int counter = 0;
|
||||
for (String userSessionId : userSessionIds) {
|
||||
counter++;
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, userSessionId);
|
||||
persister.createUserSession(userSession, true);
|
||||
|
||||
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(testApp.getId());
|
||||
persister.createClientSession(clientSession, true);
|
||||
}
|
||||
|
||||
log.infof("%d user sessions persisted. Continue", counter);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <sessions-count> <sessions-count-per-each-transaction>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class RoleCommands {
|
||||
|
||||
public static class CreateRoles extends AbstractCommand {
|
||||
|
||||
private String rolePrefix;
|
||||
private String roleContainer;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "createRoles";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
rolePrefix = getArg(0);
|
||||
roleContainer = getArg(1);
|
||||
int first = getIntArg(2);
|
||||
int count = getIntArg(3);
|
||||
int batchCount = getIntArg(4);
|
||||
|
||||
BatchTaskRunner.runInBatches(first, count, batchCount, session.getKeycloakSessionFactory(), (KeycloakSession bathcSession, int firstInThisIteration, int countInThisIteration) -> {
|
||||
createRolesInBatch(session, roleContainer, rolePrefix, firstInThisIteration, countInThisIteration);
|
||||
});
|
||||
|
||||
log.infof("Command finished. All roles from %s to %s created", rolePrefix + first, rolePrefix + (first + count - 1));
|
||||
}
|
||||
|
||||
private void createRolesInBatch(KeycloakSession session, String roleContainer, String rolePrefix, int first, int count) {
|
||||
RoleContainerModel container = getRoleContainer(session, roleContainer);
|
||||
|
||||
int last = first + count;
|
||||
for (int counter = first; counter < last; counter++) {
|
||||
String roleName = rolePrefix + counter;
|
||||
RoleModel role = container.addRole(roleName);
|
||||
}
|
||||
log.infof("Roles from %s to %s created", rolePrefix + first, rolePrefix + (last - 1));
|
||||
}
|
||||
|
||||
private RoleContainerModel getRoleContainer(KeycloakSession session, String roleContainer) {
|
||||
String[] parts = roleContainer.split("/");
|
||||
String realmName = parts[0];
|
||||
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
log.errorf("Unknown realm: %s", realmName);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
if (parts.length == 1) {
|
||||
return realm;
|
||||
} else {
|
||||
String clientId = parts[1];
|
||||
ClientModel client = session.realms().getClientByClientId(clientId, realm);
|
||||
if (client == null) {
|
||||
log.errorf("Unknown client: %s", clientId);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <role-prefix> <role-container> <starting-role-offset> <total-count> <batch-size> . " +
|
||||
"\n'total-count' refers to total count of newly created roles. 'batch-size' refers to number of created roles in each transaction. 'starting-role-offset' refers to starting role offset." +
|
||||
"\nFor example if 'starting-role-offset' is 15 and total-count is 10 and role-prefix is 'test', it will create roles test15, test16, test17, ... , test24" +
|
||||
"\n'role-container' is either realm (then use just realmName like 'demo' or client (then use realm/clientId like 'demo/my-client' .\n" +
|
||||
"Example usage: " + super.printUsage() + " test demo 0 500 100";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SyncDummyFederationProviderCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
int waitTime = getIntArg(0);
|
||||
int changedSyncPeriod = getIntArg(1);
|
||||
|
||||
RealmModel realm = session.realms().getRealmByName("master");
|
||||
UserStorageProviderModel fedProviderModel = KeycloakModelUtils.findUserStorageProviderByName("cluster-dummy", realm);
|
||||
if (fedProviderModel == null) {
|
||||
MultivaluedHashMap<String, String> cfg = fedProviderModel.getConfig();
|
||||
updateConfig(cfg, waitTime);
|
||||
|
||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||
model.setProviderId("sync-dummy");
|
||||
model.setPriority(1);
|
||||
model.setName("cluster-dummy");
|
||||
model.setFullSyncPeriod(-1);
|
||||
model.setChangedSyncPeriod(changedSyncPeriod);
|
||||
model.setLastSync(-1);
|
||||
fedProviderModel = new UserStorageProviderModel(realm.addComponentModel(model));
|
||||
} else {
|
||||
MultivaluedHashMap<String, String> cfg = fedProviderModel.getConfig();
|
||||
updateConfig(cfg, waitTime);
|
||||
fedProviderModel.setChangedSyncPeriod(changedSyncPeriod);
|
||||
realm.updateComponent(fedProviderModel);
|
||||
}
|
||||
|
||||
new UserStorageSyncManager().notifyToRefreshPeriodicSync(session, realm, fedProviderModel, false);
|
||||
|
||||
log.infof("User federation provider created and sync was started", waitTime);
|
||||
}
|
||||
|
||||
private void updateConfig(MultivaluedHashMap<String, String> cfg, int waitTime) {
|
||||
cfg.putSingle("wait-time", String.valueOf(waitTime));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "startSyncDummy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <wait-time-before-sync-commit-in-seconds> <changed-sync-period-in-seconds>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class TestCacheUtils {
|
||||
|
||||
public static void cacheRealmWithEverything(KeycloakSession session, String realmName) {
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
realm.getClientById(client.getId());
|
||||
realm.getClientByClientId(client.getClientId());
|
||||
|
||||
cacheRoles(session, realm, client);
|
||||
}
|
||||
|
||||
cacheRoles(session, realm, realm);
|
||||
|
||||
for (GroupModel group : realm.getTopLevelGroups()) {
|
||||
cacheGroupRecursive(realm, group);
|
||||
}
|
||||
|
||||
for (ClientTemplateModel clientTemplate : realm.getClientTemplates()) {
|
||||
realm.getClientTemplateById(clientTemplate.getId());
|
||||
}
|
||||
|
||||
for (UserModel user : session.users().getUsers(realm)) {
|
||||
session.users().getUserById(user.getId(), realm);
|
||||
if (user.getEmail() != null) {
|
||||
session.users().getUserByEmail(user.getEmail(), realm);
|
||||
}
|
||||
session.users().getUserByUsername(user.getUsername(), realm);
|
||||
|
||||
session.users().getConsents(realm, user.getId());
|
||||
|
||||
for (FederatedIdentityModel fedIdentity : session.users().getFederatedIdentities(user, realm)) {
|
||||
session.users().getUserByFederatedIdentity(fedIdentity, realm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cacheRoles(KeycloakSession session, RealmModel realm, RoleContainerModel roleContainer) {
|
||||
for (RoleModel role : roleContainer.getRoles()) {
|
||||
realm.getRoleById(role.getId());
|
||||
roleContainer.getRole(role.getName());
|
||||
if (roleContainer instanceof RealmModel) {
|
||||
session.realms().getRealmRole(realm, role.getName());
|
||||
} else {
|
||||
session.realms().getClientRole(realm, (ClientModel) roleContainer, role.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cacheGroupRecursive(RealmModel realm, GroupModel group) {
|
||||
realm.getGroupById(group.getId());
|
||||
for (GroupModel sub : group.getSubGroups()) {
|
||||
cacheGroupRecursive(realm, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.testsuite.KeycloakServer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* See Testsuite.md (section how to create many users and offline sessions)
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class TestsuiteCLI {
|
||||
|
||||
private static final Logger log = Logger.getLogger(TestsuiteCLI.class);
|
||||
|
||||
private static final Class<?>[] BUILTIN_COMMANDS = {
|
||||
ExitCommand.class,
|
||||
HelpCommand.class,
|
||||
AbstractSessionCacheCommand.PutCommand.class,
|
||||
AbstractSessionCacheCommand.GetCommand.class,
|
||||
AbstractSessionCacheCommand.GetMultipleCommand.class,
|
||||
AbstractSessionCacheCommand.GetLocalCommand.class,
|
||||
AbstractSessionCacheCommand.SizeLocalCommand.class,
|
||||
AbstractSessionCacheCommand.RemoveCommand.class,
|
||||
AbstractSessionCacheCommand.SizeCommand.class,
|
||||
AbstractSessionCacheCommand.ListCommand.class,
|
||||
AbstractSessionCacheCommand.ClearCommand.class,
|
||||
AbstractSessionCacheCommand.CreateManySessionsCommand.class,
|
||||
AbstractSessionCacheCommand.CreateManySessionsProviderCommand.class,
|
||||
PersistSessionsCommand.class,
|
||||
LoadPersistentSessionsCommand.class,
|
||||
UserCommands.Create.class,
|
||||
UserCommands.Remove.class,
|
||||
UserCommands.Count.class,
|
||||
UserCommands.GetUser.class,
|
||||
SyncDummyFederationProviderCommand.class,
|
||||
RoleCommands.CreateRoles.class,
|
||||
CacheCommands.ListCachesCommand.class,
|
||||
CacheCommands.GetCacheCommand.class,
|
||||
CacheCommands.CacheRealmObjectsCommand.class,
|
||||
ClusterProviderTaskCommand.class
|
||||
};
|
||||
|
||||
private final KeycloakSessionFactory sessionFactory;
|
||||
private final Map<String, Class<? extends AbstractCommand>> commands = new LinkedHashMap<>();
|
||||
|
||||
public TestsuiteCLI(KeycloakServer server) {
|
||||
this.sessionFactory = server.getSessionFactory();
|
||||
|
||||
// register builtin commands
|
||||
for (Class<?> clazz : BUILTIN_COMMANDS) {
|
||||
Class<? extends AbstractCommand> commandClazz = (Class<? extends AbstractCommand>) clazz;
|
||||
try {
|
||||
AbstractCommand command = commandClazz.newInstance();
|
||||
commands.put(command.getName(), commandClazz);
|
||||
} catch (Exception ex) {
|
||||
log.error("Error registering command of class: " + commandClazz.getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerCommand(String name, Class<? extends AbstractCommand> command) {
|
||||
commands.put(name, command);
|
||||
}
|
||||
|
||||
// WARNING: Stdin blocking operation
|
||||
public void start() throws IOException {
|
||||
log.info("Starting testsuite CLI. Exit with 'exit' . Available commands with 'help' ");
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
String line;
|
||||
System.out.print("$ ");
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] splits = line.split(" ");
|
||||
String commandName = splits[0];
|
||||
Class<? extends AbstractCommand> commandClass = commands.get(commandName);
|
||||
if (commandClass == null) {
|
||||
log.errorf("Unknown command: %s", commandName);
|
||||
} else {
|
||||
try {
|
||||
AbstractCommand command = commandClass.newInstance();
|
||||
List<String> args = new ArrayList<>(Arrays.asList(splits));
|
||||
args.remove(0);
|
||||
command.injectProperties(args, this, sessionFactory);
|
||||
command.runCommand();
|
||||
|
||||
// Just special handling of ExitCommand
|
||||
if (command instanceof ExitCommand) {
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (InstantiationException ex) {
|
||||
log.error(ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
log.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.print("$ ");
|
||||
}
|
||||
} finally {
|
||||
log.info("Exit testsuite CLI");
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExitCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "exit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCommand() {
|
||||
// no need to implement. Exit handled in parent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
// no need to implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
public static class HelpCommand extends AbstractCommand {
|
||||
|
||||
private List<String> commandNames = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void injectProperties(List<String> args, TestsuiteCLI cli, KeycloakSessionFactory sessionFactory) {
|
||||
for (String commandName : cli.commands.keySet()) {
|
||||
commandNames.add(commandName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "help";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCommand() {
|
||||
log.info("Available commands: " + commandNames.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
// no need to implement
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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.testsuite.util.cli;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionTask;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class UserCommands {
|
||||
|
||||
public static class Create extends AbstractCommand {
|
||||
|
||||
private String usernamePrefix;
|
||||
private String password;
|
||||
private String realmName;
|
||||
private String roleNames;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "createUsers";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
usernamePrefix = getArg(0);
|
||||
password = getArg(1);
|
||||
realmName = getArg(2);
|
||||
int first = getIntArg(3);
|
||||
int count = getIntArg(4);
|
||||
int batchCount = getIntArg(5);
|
||||
roleNames = getArg(6);
|
||||
|
||||
BatchTaskRunner.runInBatches(first, count, batchCount, session.getKeycloakSessionFactory(), this::createUsersInBatch);
|
||||
|
||||
log.infof("Command finished. All users from %s to %s created", usernamePrefix + first, usernamePrefix + (first + count - 1));
|
||||
}
|
||||
|
||||
private void createUsersInBatch(KeycloakSession session, int first, int count) {
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
log.errorf("Unknown realm: %s", realmName);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
Set<RoleModel> roles = findRoles(realm, roleNames);
|
||||
|
||||
int last = first + count;
|
||||
for (int counter = first; counter < last; counter++) {
|
||||
String username = usernamePrefix + counter;
|
||||
UserModel user = session.users().addUser(realm, username);
|
||||
user.setEnabled(true);
|
||||
user.setEmail(username + "@keycloak.org");
|
||||
UserCredentialModel passwordCred = UserCredentialModel.password(password);
|
||||
session.userCredentialManager().updateCredential(realm, user, passwordCred);
|
||||
|
||||
for (RoleModel role : roles) {
|
||||
user.grantRole(role);
|
||||
}
|
||||
}
|
||||
log.infof("Users from %s to %s created", usernamePrefix + first, usernamePrefix + (last - 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <username-prefix> <password> <realm-name> <starting-user-offset> <total-count> <batch-size> <realm-roles-list>. " +
|
||||
"\n'total-count' refers to total count of newly created users. 'batch-size' refers to number of created users in each transaction. 'starting-user-offset' refers to starting username offset." +
|
||||
"\nFor example if 'starting-user-offset' is 15 and total-count is 10 and username-prefix is 'test', it will create users test15, test16, test17, ... , test24" +
|
||||
"\nRoles list is divided by comma (client roles are referenced with format <client-id>/<role-name> )>\n" +
|
||||
"Example usage: " + super.printUsage() + " test test demo 0 500 100 user,admin";
|
||||
}
|
||||
|
||||
private Set<RoleModel> findRoles(RealmModel realm, String rolesList) {
|
||||
Set<RoleModel> result = new HashSet<>();
|
||||
|
||||
String[] roles = rolesList.split(",");
|
||||
for (String roleName : roles) {
|
||||
roleName = roleName.trim();
|
||||
RoleModel role;
|
||||
if (roleName.contains("/")) {
|
||||
String[] spl = roleName.split("/");
|
||||
ClientModel client = realm.getClientByClientId(spl[0]);
|
||||
if (client == null) {
|
||||
log.errorf("Client not found: %s", spl[0]);
|
||||
throw new HandledException();
|
||||
}
|
||||
role = client.getRole(spl[1]);
|
||||
} else {
|
||||
role = realm.getRole(roleName);
|
||||
}
|
||||
|
||||
if (role == null) {
|
||||
log.errorf("Role not found: %s", roleName);
|
||||
throw new HandledException();
|
||||
}
|
||||
|
||||
result.add(role);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class Remove extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "removeUsers";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
String usernamePrefix = getArg(0);
|
||||
String realmName = getArg(1);
|
||||
int first = getIntArg(2);
|
||||
int count = getIntArg(3);
|
||||
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
log.errorf("Unknown realm: %s", realmName);
|
||||
return;
|
||||
}
|
||||
|
||||
int last = first + count;
|
||||
for (int counter = first; counter < last; counter++) {
|
||||
String username = usernamePrefix + counter;
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
if (user == null) {
|
||||
log.errorf("User '%s' not found", username);
|
||||
} else {
|
||||
session.users().removeUser(realm, user);
|
||||
}
|
||||
}
|
||||
log.infof("Users from %s to %s removed", usernamePrefix + first, usernamePrefix + (last - 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <username-prefix> <realm-name> <starting-user-offset> <count> \n" +
|
||||
"Example usage: " + super.printUsage() + " test demo 0 20";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Count extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "getUsersCount";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
String realmName = getArg(0);
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
log.errorf("Unknown realm: %s", realmName);
|
||||
return;
|
||||
}
|
||||
|
||||
int usersCount = session.users().getUsersCount(realm);
|
||||
log.infof("Users count in realm %s: %d", realmName, usersCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <realm-name>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class GetUser extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "getUser";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRunCommand(KeycloakSession session) {
|
||||
String realmName = getArg(0);
|
||||
String username = getArg(1);
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
log.errorf("Unknown realm: %s", realmName);
|
||||
return;
|
||||
}
|
||||
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
if (user == null) {
|
||||
log.infof("User '%s' doesn't exist in realm '%s'", username, realmName);
|
||||
} else {
|
||||
List<String> roleMappings = getRoleMappings(session, realm, user);
|
||||
log.infof("User: ID: '%s', username: '%s', mail: '%s', roles: '%s'", user.getId(), user.getUsername(), user.getEmail(), roleMappings.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getRoleMappings(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
Set<RoleModel> roles = user.getRoleMappings();
|
||||
List<String> result = new LinkedList<>();
|
||||
for (RoleModel role : roles) {
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
result.add(role.getName());
|
||||
} else {
|
||||
ClientModel client = (ClientModel) role.getContainer();
|
||||
result.add(client.getClientId() + "/" + role.getName());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String printUsage() {
|
||||
return super.printUsage() + " <realm-name> <username>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"admin": {
|
||||
"realm": "master"
|
||||
},
|
||||
|
||||
"eventsStore": {
|
||||
"provider": "${keycloak.eventsStore.provider:jpa}"
|
||||
},
|
||||
|
||||
"eventsListener": {
|
||||
"jboss-logging" : {
|
||||
"success-level": "debug",
|
||||
"error-level": "warn"
|
||||
}
|
||||
},
|
||||
|
||||
"realm": {
|
||||
"provider": "${keycloak.realm.provider:jpa}"
|
||||
},
|
||||
|
||||
"user": {
|
||||
"provider": "${keycloak.user.provider:jpa}"
|
||||
},
|
||||
|
||||
"userFederatedStorage": {
|
||||
"provider": "${keycloak.userFederatedStorage.provider:jpa}"
|
||||
},
|
||||
|
||||
"userSessionPersister": {
|
||||
"provider": "${keycloak.userSessionPersister.provider:jpa}"
|
||||
},
|
||||
|
||||
"authorizationPersister": {
|
||||
"provider": "${keycloak.authorization.provider:jpa}"
|
||||
},
|
||||
|
||||
"userCache": {
|
||||
"default" : {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
|
||||
"timer": {
|
||||
"provider": "basic"
|
||||
},
|
||||
|
||||
"theme": {
|
||||
"staticMaxAge": "${keycloak.theme.staticMaxAge:2592000}",
|
||||
"cacheTemplates": "${keycloak.theme.cacheTemplates:true}",
|
||||
"cacheThemes": "${keycloak.theme.cacheThemes:true}",
|
||||
"folder": {
|
||||
"dir": "${keycloak.theme.dir}"
|
||||
}
|
||||
},
|
||||
|
||||
"scheduled": {
|
||||
"interval": 900
|
||||
},
|
||||
|
||||
"connectionsHttpClient": {
|
||||
"default": {}
|
||||
},
|
||||
|
||||
|
||||
"connectionsJpa": {
|
||||
"default": {
|
||||
"url": "${keycloak.connectionsJpa.url:jdbc:h2:mem:test;DB_CLOSE_DELAY=-1}",
|
||||
"driver": "${keycloak.connectionsJpa.driver:org.h2.Driver}",
|
||||
"driverDialect": "${keycloak.connectionsJpa.driverDialect:}",
|
||||
"user": "${keycloak.connectionsJpa.user:sa}",
|
||||
"password": "${keycloak.connectionsJpa.password:}",
|
||||
"initializeEmpty": true,
|
||||
"migrationStrategy": "update",
|
||||
"showSql": "${keycloak.connectionsJpa.showSql:false}",
|
||||
"formatSql": "${keycloak.connectionsJpa.formatSql:true}",
|
||||
"globalStatsInterval": "${keycloak.connectionsJpa.globalStatsInterval:-1}"
|
||||
}
|
||||
},
|
||||
|
||||
"realmCache": {
|
||||
"default" : {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
|
||||
"connectionsInfinispan": {
|
||||
"default": {
|
||||
"jgroupsUdpMcastAddr": "${keycloak.connectionsInfinispan.jgroupsUdpMcastAddr:234.56.78.90}",
|
||||
"nodeName": "${keycloak.connectionsInfinispan.nodeName,jboss.node.name:}",
|
||||
"siteName": "${keycloak.connectionsInfinispan.siteName,jboss.site.name:}",
|
||||
"clustered": "${keycloak.connectionsInfinispan.clustered:false}",
|
||||
"async": "${keycloak.connectionsInfinispan.async:false}",
|
||||
"sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:1}",
|
||||
"l1Lifespan": "${keycloak.connectionsInfinispan.l1Lifespan:600000}",
|
||||
"remoteStoreEnabled": "${keycloak.connectionsInfinispan.remoteStoreEnabled:false}",
|
||||
"remoteStoreHost": "${keycloak.connectionsjen neInfinispan.remoteStoreHost:localhost}",
|
||||
"remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}"
|
||||
}
|
||||
},
|
||||
|
||||
"scripting": {
|
||||
},
|
||||
|
||||
"jta-lookup": {
|
||||
"provider": "${keycloak.jta.lookup.provider:jboss}",
|
||||
"jboss" : {
|
||||
"enabled": true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
log4j.rootLogger=info, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %t [%c] %m%n
|
||||
|
||||
# For debug, run KeycloakServer with -Dkeycloak.logging.level=debug
|
||||
keycloak.logging.level=info
|
||||
log4j.logger.org.keycloak=${keycloak.logging.level}
|
||||
|
||||
|
||||
# Enable to view events
|
||||
# log4j.logger.org.keycloak.events=debug
|
||||
|
||||
# Enable to view loaded SPI and Providers
|
||||
# log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug
|
||||
# log4j.logger.org.keycloak.provider.ProviderManager=debug
|
||||
# log4j.logger.org.keycloak.provider.FileSystemProviderLoaderFactory=debug
|
||||
#log4j.logger.org.infinispan.transaction.impl.TransactionCoordinator=OFF
|
||||
#log4j.logger.org.infinispan.transaction.tm.DummyTransaction=OFF
|
||||
#log4j.logger.org.infinispan.container.entries.RepeatableReadEntry=OFF
|
||||
# Broker logging
|
||||
keycloak.testsuite.logging.level=info
|
||||
log4j.logger.org.keycloak.testsuite=${keycloak.testsuite.logging.level}
|
||||
|
||||
# Liquibase updates logged with "info" by default. Logging level can be changed by system property "keycloak.liquibase.logging.level"
|
||||
keycloak.liquibase.logging.level=info
|
||||
log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase.logging.level}
|
||||
|
||||
# Enable to view infinispan initialization
|
||||
# log4j.logger.org.keycloak.models.sessions.infinispan.initializer=trace
|
||||
|
||||
# Enable to view cache activity
|
||||
#log4j.logger.org.keycloak.cluster.infinispan=trace
|
||||
#log4j.logger.org.keycloak.models.cache.infinispan=debug
|
||||
|
||||
# Enable to view database updates
|
||||
log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=${keycloak.liquibase.logging.level}
|
||||
# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
|
||||
|
||||
# Enable to view hibernate statistics
|
||||
log4j.logger.org.keycloak.connections.jpa.HibernateStatsReporter=debug
|
||||
|
||||
keycloak.infinispan.logging.level=info
|
||||
log4j.logger.org.keycloak.cluster.infinispan=${keycloak.infinispan.logging.level}
|
||||
log4j.logger.org.keycloak.connections.infinispan=${keycloak.infinispan.logging.level}
|
||||
log4j.logger.org.keycloak.keys.infinispan=${keycloak.infinispan.logging.level}
|
||||
log4j.logger.org.keycloak.models.cache.infinispan=${keycloak.infinispan.logging.level}
|
||||
log4j.logger.org.keycloak.models.sessions.infinispan=${keycloak.infinispan.logging.level}
|
||||
|
||||
# Enable to view ldap logging
|
||||
# log4j.logger.org.keycloak.storage.ldap=trace
|
||||
|
||||
# Enable to view queries to LDAP
|
||||
# log4j.logger.org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore=trace
|
||||
|
||||
# Enable to view kerberos/spnego logging
|
||||
# log4j.logger.org.keycloak.federation.kerberos=trace
|
||||
|
||||
# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
|
||||
# log4j.logger.org.apache.directory.server.kerberos=debug
|
||||
#log4j.logger.org.keycloak.saml=debug
|
||||
|
||||
log4j.logger.org.xnio=off
|
||||
log4j.logger.org.hibernate=off
|
||||
log4j.logger.org.jboss.resteasy=warn
|
||||
log4j.logger.org.apache.directory.api=warn
|
||||
log4j.logger.org.apache.directory.server.core=warn
|
||||
log4j.logger.org.apache.directory.server.ldap.LdapProtocolHandler=error
|
||||
|
||||
# Enable to view HttpClient connection pool activity
|
||||
#log4j.logger.org.apache.http.impl.conn=debug
|
||||
|
||||
# Enable to view details from identity provider authenticator
|
||||
#log4j.logger.org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticator=trace
|
||||
#log4j.logger.org.keycloak.services.resources.IdentityBrokerService=trace
|
||||
#log4j.logger.org.keycloak.broker=trace
|
||||
|
||||
#log4j.logger.org.keycloak.cluster.infinispan.InfinispanNotificationsManager=trace
|
||||
|
||||
#log4j.logger.io.undertow=trace
|
||||
|
||||
#log4j.logger.org.keycloak.protocol=debug
|
||||
#log4j.logger.org.keycloak.services.resources.LoginActionsService=debug
|
||||
#log4j.logger.org.keycloak.services.managers=debug
|
||||
#log4j.logger.org.keycloak.services.resources.SessionCodeChecks=debug
|
||||
#log4j.logger.org.keycloak.authentication=debug
|
||||
Reference in new issue
Block a user