keycloak-uncached
Changes
integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java 4(+2 -2)
Details
diff --git a/core/src/main/java/org/keycloak/util/HostUtils.java b/core/src/main/java/org/keycloak/util/HostUtils.java
index fb1b29f..391964a 100644
--- a/core/src/main/java/org/keycloak/util/HostUtils.java
+++ b/core/src/main/java/org/keycloak/util/HostUtils.java
@@ -8,29 +8,67 @@ import java.net.UnknownHostException;
*/
public class HostUtils {
+ // Best effort to find the most proper hostname of this server.
public static String getHostName() {
- String jbossHostName = System.getProperty("jboss.host.name");
- if (jbossHostName != null) {
- return jbossHostName;
- } else {
- try {
- return InetAddress.getLocalHost().getHostName();
- } catch (UnknownHostException uhe) {
- throw new IllegalStateException(uhe);
- }
- }
+ return getHostNameImpl().trim().toLowerCase();
}
public static String getIpAddress() {
try {
- String jbossHostName = System.getProperty("jboss.host.name");
- if (jbossHostName != null) {
- return InetAddress.getByName(jbossHostName).getHostAddress();
- } else {
- return java.net.InetAddress.getLocalHost().getHostAddress();
- }
+ String hostname = getHostName();
+ return InetAddress.getByName(hostname).getHostAddress();
} catch (UnknownHostException uhe) {
throw new IllegalStateException(uhe);
}
}
+
+ private static String getHostNameImpl() {
+ // Return bind address if available
+ String bindAddr = System.getProperty("jboss.bind.address");
+ if (bindAddr != null && !bindAddr.trim().equals("0.0.0.0")) {
+ return bindAddr;
+ }
+
+ // Fallback to qualified name
+ String qualifiedHostName = System.getProperty("jboss.qualified.host.name");
+ if (qualifiedHostName != null) {
+ return qualifiedHostName;
+ }
+
+ // If not on jboss env, let's try other possible fallbacks
+ // POSIX-like OSes including Mac should have this set
+ qualifiedHostName = System.getenv("HOSTNAME");
+ if (qualifiedHostName != null) {
+ return qualifiedHostName;
+ }
+
+ // Certain versions of Windows
+ qualifiedHostName = System.getenv("COMPUTERNAME");
+ if (qualifiedHostName != null) {
+ return qualifiedHostName;
+ }
+
+ try {
+ return NetworkUtils.canonize(getLocalHost().getHostName());
+ } catch (UnknownHostException uhe) {
+ uhe.printStackTrace();
+ return "unknown-host.unknown-domain";
+ }
+ }
+
+ /**
+ * Methods returns InetAddress for localhost
+ *
+ * @return InetAddress of the localhost
+ * @throws UnknownHostException if localhost could not be resolved
+ */
+ private static InetAddress getLocalHost() throws UnknownHostException {
+ InetAddress addr;
+ try {
+ addr = InetAddress.getLocalHost();
+ } catch (ArrayIndexOutOfBoundsException e) { //this is workaround for mac osx bug see AS7-3223 and JGRP-1404
+ addr = InetAddress.getByName(null);
+ }
+ return addr;
+ }
}
diff --git a/core/src/main/java/org/keycloak/util/NetworkUtils.java b/core/src/main/java/org/keycloak/util/NetworkUtils.java
new file mode 100644
index 0000000..8d9bd15
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/NetworkUtils.java
@@ -0,0 +1,446 @@
+package org.keycloak.util;
+
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Utility methods related to networking.
+ *
+ * @author Brian Stansberry (c) 2011 Red Hat Inc.
+ */
+public class NetworkUtils {
+
+ private static final int MAX_GROUP_LENGTH = 4;
+ private static final int IPV6_LEN = 8;
+ private static final boolean can_bind_to_mcast_addr; // are we running on Linux ?
+
+ static {
+ can_bind_to_mcast_addr = checkForLinux() || checkForSolaris() || checkForHp();
+ }
+
+ public static String formatPossibleIpv6Address(String address) {
+ if(address == null) {
+ return null;
+ }
+ String ipv6Address;
+ if (address.startsWith("[") && address.endsWith("]")) {
+ ipv6Address = address.substring(0, address.lastIndexOf(']')).substring(1);
+ } else {
+ ipv6Address = address;
+ }
+ // Definitely not an IPv6, return untouched input.
+ if (!mayBeIPv6Address(ipv6Address)) {
+ return ipv6Address;
+ }
+ return '[' + canonize(ipv6Address) + ']';
+ }
+
+ /**
+ * <p>Convert IPv6 adress into RFC 5952 form.
+ * E.g. 2001:db8:0:1:0:0:0:1 -> 2001:db8:0:1::1</p>
+ *
+ * <p>Method is null safe, and if IPv4 address or host name is passed to the
+ * method it is returned wihout any processing.</p>
+ *
+ * <p>Method also supports IPv4 in IPv6 (e.g. 0:0:0:0:0:ffff:192.0.2.1 ->
+ * ::ffff:192.0.2.1), and zone ID (e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
+ * -> fe80::f0f0:c0c0:1919:1234%4).</p>
+ *
+ * @param ipv6Address String representing valid IPv6 address.
+ * @return String representing IPv6 in canonical form.
+ * @throws IllegalArgumentException if IPv6 format is unacceptable.
+ */
+ public static String canonize(String ipv6Address) throws IllegalArgumentException {
+
+ if (ipv6Address == null) {
+ return null;
+ }
+
+ // Definitely not an IPv6, return untouched input.
+ if (!mayBeIPv6Address(ipv6Address)) {
+ return ipv6Address;
+ }
+
+ // Length without zone ID (%zone) or IPv4 address
+ int ipv6AddressLength = ipv6Address.length();
+ if (isIPv4AddressInIPv6(ipv6Address)) {
+ // IPv4 in IPv6
+ // e.g. 0:0:0:0:0:FFFF:127.0.0.1
+ int lastColonPos = ipv6Address.lastIndexOf(":");
+ int lastColonsPos = ipv6Address.lastIndexOf("::");
+ if (lastColonsPos >= 0 && lastColonPos == lastColonsPos + 1) {
+ // IPv6 part ends with two consecutive colons, last colon is part of IPv6 format.
+ // e.g. ::127.0.0.1
+ ipv6AddressLength = lastColonPos + 1;
+ } else {
+ // IPv6 part ends with only one colon, last colon is not part of IPv6 format.
+ // e.g. ::FFFF:127.0.0.1
+ ipv6AddressLength = lastColonPos;
+ }
+ } else if (ipv6Address.contains(":") && ipv6Address.contains("%")) {
+ // Zone ID
+ // e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
+ ipv6AddressLength = ipv6Address.lastIndexOf("%");
+ }
+
+ StringBuilder result = new StringBuilder();
+ char [][] groups = new char[IPV6_LEN][MAX_GROUP_LENGTH];
+ int groupCounter = 0;
+ int charInGroupCounter = 0;
+
+ // Index of the current zeroGroup, -1 means not found.
+ int zeroGroupIndex = -1;
+ int zeroGroupLength = 0;
+
+ // maximum length zero group, if there is more then one, then first one
+ int maxZeroGroupIndex = -1;
+ int maxZeroGroupLength = 0;
+
+ boolean isZero = true;
+ boolean groupStart = true;
+
+ /*
+ * Two consecutive colons, initial expansion.
+ * e.g. 2001:db8:0:0:1::1 -> 2001:db8:0:0:1:0:0:1
+ */
+ StringBuilder expanded = new StringBuilder(ipv6Address);
+ int colonsPos = ipv6Address.indexOf("::");
+ int length = ipv6AddressLength;
+ int change = 0;
+
+ if (colonsPos >= 0 && colonsPos < ipv6AddressLength - 2) {
+ int colonCounter = 0;
+ for (int i = 0; i < ipv6AddressLength; i++) {
+ if (ipv6Address.charAt(i) == ':') {
+ colonCounter++;
+ }
+ }
+
+ if (colonsPos == 0) {
+ expanded.insert(0, "0");
+ change = change + 1;
+ }
+
+ for (int i = 0; i < IPV6_LEN - colonCounter; i++) {
+ expanded.insert(colonsPos + 1, "0:");
+ change = change + 2;
+ }
+
+
+ if (colonsPos == ipv6AddressLength - 2) {
+ expanded.setCharAt(colonsPos + change + 1, '0');
+ } else {
+ expanded.deleteCharAt(colonsPos + change + 1);
+ change = change - 1;
+ }
+ length = length + change;
+ }
+
+
+ // Processing one char at the time
+ for (int charCounter = 0; charCounter < length; charCounter++) {
+ char c = expanded.charAt(charCounter);
+ if (c >= 'A' && c <= 'F') {
+ c = (char) (c + 32);
+ }
+ if (c != ':') {
+ groups[groupCounter][charInGroupCounter] = c;
+ if (!(groupStart && c == '0')) {
+ ++charInGroupCounter;
+ groupStart = false;
+ }
+ if (c != '0') {
+ isZero = false;
+ }
+ }
+ if (c == ':' || charCounter == (length - 1)) {
+ // We reached end of current group
+ if (isZero) {
+ ++zeroGroupLength;
+ if (zeroGroupIndex == -1) {
+ zeroGroupIndex = groupCounter;
+ }
+ }
+
+ if (!isZero || charCounter == (length - 1)) {
+ // We reached end of zero group
+ if (zeroGroupLength > maxZeroGroupLength) {
+ maxZeroGroupLength = zeroGroupLength;
+ maxZeroGroupIndex = zeroGroupIndex;
+ }
+ zeroGroupLength = 0;
+ zeroGroupIndex = -1;
+ }
+ ++groupCounter;
+ charInGroupCounter = 0;
+ isZero = true;
+ groupStart = true;
+ }
+ }
+
+ int numberOfGroups = groupCounter;
+
+ // Output results
+ for (groupCounter = 0; groupCounter < numberOfGroups; groupCounter++) {
+ if (maxZeroGroupLength <= 1 || groupCounter < maxZeroGroupIndex
+ || groupCounter >= maxZeroGroupIndex + maxZeroGroupLength) {
+ for (int j = 0; j < MAX_GROUP_LENGTH; j++) {
+ if (groups[groupCounter][j] != 0) {
+ result.append(groups[groupCounter][j]);
+ }
+ }
+ if (groupCounter < (numberOfGroups - 1)
+ && (groupCounter != maxZeroGroupIndex - 1
+ || maxZeroGroupLength <= 1)) {
+ result.append(':');
+ }
+ } else if (groupCounter == maxZeroGroupIndex) {
+ result.append("::");
+ }
+ }
+
+ // Solve problem with three colons in IPv4 in IPv6 format
+ // e.g. 0:0:0:0:0:0:127.0.0.1 -> :::127.0.0.1 -> ::127.0.0.1
+ int resultLength = result.length();
+ if (result.charAt(resultLength - 1) == ':' && ipv6AddressLength < ipv6Address.length()
+ && ipv6Address.charAt(ipv6AddressLength) == ':') {
+ result.delete(resultLength - 1, resultLength);
+ }
+
+ /*
+ * Append IPv4 from IPv4-in-IPv6 format or Zone ID
+ */
+ for (int i = ipv6AddressLength; i < ipv6Address.length(); i++) {
+ result.append(ipv6Address.charAt(i));
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Heuristic check if string might be an IPv6 address.
+ *
+ * @param input Any string or null
+ * @return true, if input string contains only hex digits and at least two colons, before '.' or '%' character.
+ */
+ private static boolean mayBeIPv6Address(String input) {
+ if (input == null) {
+ return false;
+ }
+
+ boolean result = false;
+ int colonsCounter = 0;
+ int length = input.length();
+ for (int i = 0; i < length; i++) {
+ char c = input.charAt(i);
+ if (c == '.' || c == '%') {
+ // IPv4 in IPv6 or Zone ID detected, end of checking.
+ break;
+ }
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F') || c == ':')) {
+ return false;
+ } else if (c == ':') {
+ colonsCounter++;
+ }
+ }
+ if (colonsCounter >= 2) {
+ result = true;
+ }
+ return result;
+ }
+ /**
+ * Check if it is an IPv4 in IPv6 format.
+ * e.g. 0:0:0:0:0:FFFF:127.0.0.1
+ *
+ * @param ipv6Address the address
+ * @return true, if input string is an IPv4 address in IPv6 format.
+ */
+ private static boolean isIPv4AddressInIPv6(String ipv6Address) {
+ return (ipv6Address.contains(":") && ipv6Address.contains("."));
+ }
+
+ /**
+ * Formats input address. For IPV4 returns simply host address, for IPV6 formats address according to <a
+ * href="http://tools.ietf.org/html/rfc5952">RFC5952</a> rules. It does not embed IPV6 address in '[', ']', since those are part of IPV6 URI literal.
+ *
+ * @param inet
+ * @return
+ */
+ public static String formatAddress(InetAddress inet){
+ if(inet == null){
+ throw new NullPointerException();
+ }
+ if(inet instanceof Inet4Address){
+ return inet.getHostAddress();
+ } else if (inet instanceof Inet6Address){
+ byte[] byteRepresentation = inet.getAddress();
+ int[] hexRepresentation = new int[IPV6_LEN];
+
+ for(int i=0;i < hexRepresentation.length;i++){
+ hexRepresentation[i] = ( byteRepresentation[2*i] & 0xFF) << 8 | ( byteRepresentation[2*i+1] & 0xFF );
+ }
+ compactLongestZeroSequence(hexRepresentation);
+ return formatAddress6(hexRepresentation);
+ } else {
+ return inet.getHostAddress();
+ }
+ }
+
+ /**
+ * Converts socket address into string literal, which has form: 'address:port'. Example:<br>
+ * <ul>
+ * <li>127.0.0.1:8080</li>
+ * <li>dns.name.com:8080</li>
+ * <li>[0fe:1::20]:8080</li>
+ * <li>[::1]:8080</li>
+ * </ul>
+ * @param inet
+ * @return
+ */
+ public static String formatAddress(InetSocketAddress inet){
+ if(inet == null){
+ throw new NullPointerException();
+ }
+ StringBuilder result = new StringBuilder();
+ if(inet.isUnresolved()){
+ result.append(inet.getHostName());
+ }else{
+ result.append(formatPossibleIpv6Address(formatAddress(inet.getAddress())));
+ }
+ result.append(":").append(inet.getPort());
+ return result.toString();
+ }
+
+ /**
+ * Converts IPV6 int[] representation into valid IPV6 string literal. Sequence of '-1' values are converted into '::'.
+ * @param hexRepresentation
+ * @return
+ */
+ private static String formatAddress6(int[] hexRepresentation){
+ if(hexRepresentation == null){
+ throw new NullPointerException();
+ }
+ if(hexRepresentation.length != IPV6_LEN){
+ throw new IllegalArgumentException();
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ boolean inCompressedSection = false;
+ for(int i = 0;i<hexRepresentation.length;i++){
+ if(hexRepresentation[i] == -1){
+ if(!inCompressedSection){
+ inCompressedSection = true;
+ if(i == 0){
+ stringBuilder.append("::");
+ } else {
+ stringBuilder.append(':');
+ }
+ }
+ } else {
+ inCompressedSection = false;
+ stringBuilder.append(Integer.toHexString(hexRepresentation[i]));
+ if(i+1<hexRepresentation.length){
+ stringBuilder.append(":");
+ }
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ public static boolean isBindingToMulticastDressSupported() {
+ return can_bind_to_mcast_addr;
+ }
+
+ private static void compactLongestZeroSequence(int[] hexRepresentatoin){
+ int bestRunStart = -1;
+ int bestRunLen = -1;
+ boolean inRun = false;
+ int runStart = -1;
+ for(int i=0;i<hexRepresentatoin.length;i++){
+
+ if(hexRepresentatoin[i] == 0){
+ if(!inRun){
+ runStart = i;
+ inRun = true;
+ }
+ } else {
+ if(inRun){
+ inRun = false;
+ int runLen = i - runStart;
+ if(bestRunLen < 0){
+ bestRunStart = runStart;
+ bestRunLen = runLen;
+ } else {
+ if(runLen > bestRunLen){
+ bestRunStart = runStart;
+ bestRunLen = runLen;
+ }
+ }
+ }
+ }
+ }
+ if(bestRunStart >=0){
+ Arrays.fill(hexRepresentatoin, bestRunStart, bestRunStart + bestRunLen, -1);
+ }
+ }
+
+ private static boolean checkForLinux() {
+ return checkForPresence("os.name", "linux");
+ }
+
+ private static boolean checkForHp() {
+ return checkForPresence("os.name", "hp");
+ }
+
+ private static boolean checkForSolaris() {
+ return checkForPresence("os.name", "sun");
+ }
+
+ private static boolean checkForWindows() {
+ return checkForPresence("os.name", "win");
+ }
+
+ public static boolean checkForMac() {
+ return checkForPresence("os.name", "mac");
+ }
+
+ private static boolean checkForPresence(final String key, final String value) {
+ final String tmp = System.getProperty(key, value);
+ try {
+ return tmp != null && tmp.trim().toLowerCase(Locale.ENGLISH).startsWith(value);
+ } catch (Throwable t) {
+ return false;
+ }
+ }
+
+ // No instantiation
+ private NetworkUtils() {
+
+ }
+}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java
index 0e9234f..86b54fa 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/NodesRegistrationManagement.java
@@ -64,7 +64,7 @@ public class NodesRegistrationManagement {
protected void sendRegistrationEvent(KeycloakDeployment deployment) {
log.debug("Sending registration event right now");
- String host = HostUtils.getIpAddress();
+ String host = HostUtils.getHostName();
try {
ServerRequest.invokeRegisterNode(deployment, host);
NodeRegistrationContext regContext = new NodeRegistrationContext(Time.currentTime(), deployment);
@@ -84,7 +84,7 @@ public class NodesRegistrationManagement {
protected boolean sendUnregistrationEvent(KeycloakDeployment deployment) {
log.debug("Sending Unregistration event right now");
- String host = HostUtils.getIpAddress();
+ String host = HostUtils.getHostName();
try {
ServerRequest.invokeUnregisterNode(deployment, host);
log.debugf("Node '%s' successfully unregistered from Keycloak", host);
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
index 741edc7..eebac4f 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
@@ -103,7 +103,7 @@ public class ServerRequest {
formparams.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
if (sessionId != null) {
formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_SESSION_STATE, sessionId));
- formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_SESSION_HOST, HostUtils.getIpAddress()));
+ formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_SESSION_HOST, HostUtils.getHostName()));
}
HttpResponse response = null;
HttpPost post = new HttpPost(codeUrl);
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index d3fb82a..ff2069a 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -184,7 +184,12 @@ public class ResourceAdminManager {
}
}
- if (managementUrl.contains(APPLICATION_SESSION_HOST_PROPERTY) && adapterSessionIds != null) {
+ if (adapterSessionIds == null || adapterSessionIds.isEmpty()) {
+ logger.debugv("Can't logout {0}: no logged adapter sessions", resource.getName());
+ return false;
+ }
+
+ if (managementUrl.contains(APPLICATION_SESSION_HOST_PROPERTY)) {
boolean allPassed = true;
// Send logout separately to each host (needed for single-sign-out in cluster for non-distributable apps - KEYCLOAK-748)
for (Map.Entry<String, List<String>> entry : adapterSessionIds.entrySet()) {
@@ -197,13 +202,11 @@ public class ResourceAdminManager {
return allPassed;
} else {
// Send single logout request
- List<String> allSessionIds = null;
- if (adapterSessionIds != null) {
- allSessionIds = new ArrayList<String>();
- for (List<String> currentIds : adapterSessionIds.values()) {
- allSessionIds.addAll(currentIds);
- }
+ List<String> allSessionIds = new ArrayList<String>();
+ for (List<String> currentIds : adapterSessionIds.values()) {
+ allSessionIds.addAll(currentIds);
}
+
return sendLogoutRequest(realm, resource, allSessionIds, client, 0, managementUrl);
}
} else {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index cef068a..91c3974 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -79,9 +79,7 @@ public class AdapterTest {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
- RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
- RealmModel realm = manager.importRealm(representation);
-
+ RealmModel realm = AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
realmPublicKey = realm.getPublicKey();
URL url = getClass().getResource("/adapter-test/cust-app-keycloak.json");
@@ -184,4 +182,12 @@ public class AdapterTest {
}
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ testStrategy.testAdminApplicationLogout();
+ }
+
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index 6ff9df2..e55e0da 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -28,6 +28,7 @@ import org.junit.rules.ExternalResource;
import org.keycloak.Config;
import org.keycloak.OAuth2Constants;
import org.keycloak.Version;
+import org.keycloak.admin.client.Keycloak;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
@@ -38,15 +39,20 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.admin.AdminRoot;
+import org.keycloak.services.resources.admin.ApplicationsResource;
+import org.keycloak.services.resources.admin.RealmAdminResource;
+import org.keycloak.services.resources.admin.RealmsAdminResource;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
+import org.keycloak.testutils.KeycloakServer;
import org.keycloak.util.BasicAuthHelper;
import org.openqa.selenium.WebDriver;
@@ -106,6 +112,15 @@ public class AdapterTestStrategy extends ExternalResource {
if (addSlash) slash = "/";
}
+ public static RealmModel baseAdapterTestInitialization(KeycloakSession session, RealmManager manager, RealmModel adminRealm, Class<?> clazz) {
+ // Required by admin client
+ adminRealm.setPasswordCredentialGrantAllowed(true);
+
+ RealmRepresentation representation = KeycloakServer.loadJson(clazz.getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
+ RealmModel demoRealm = manager.importRealm(representation);
+ return demoRealm;
+ }
+
@Override
protected void before() throws Throwable {
super.before();
@@ -562,6 +577,25 @@ public class AdapterTestStrategy extends ExternalResource {
}, "demo");
}
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ // login as bburke
+ loginAndCheckSession(driver, loginPage);
+
+ // logout mposolda with admin client
+ Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CONSOLE_APPLICATION);
+ keycloakAdmin.realm("demo").applications().get("session-portal").logoutUser("mposolda");
+
+ // bburke should be still logged with original httpSession in our browser window
+ driver.navigate().to(APP_SERVER_BASE_URL + "/session-portal");
+ Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/session-portal" + slash);
+ String pageSource = driver.getPageSource();
+ Assert.assertTrue(pageSource.contains("Counter=3"));
+ }
+
protected void loginAndCheckSession(WebDriver driver, LoginPage loginPage) {
driver.navigate().to(APP_SERVER_BASE_URL + "/session-portal");
String currentUrl = driver.getCurrentUrl();
diff --git a/testsuite/integration/src/test/resources/adapter-test/demorealm.json b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
index ec53bd7..f4668a4 100755
--- a/testsuite/integration/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {
diff --git a/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
index ce40aec..0de8bce 100755
--- a/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {
diff --git a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index 19a8efd..22170ee 100755
--- a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -75,8 +75,7 @@ public class Jetty9Test {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
- RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
- RealmModel realm = manager.importRealm(representation);
+ AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
}
};
@@ -191,4 +190,12 @@ public class Jetty9Test {
testStrategy.testSessionInvalidatedAfterFailedRefresh();
}
+
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ testStrategy.testAdminApplicationLogout();
+ }
}
diff --git a/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
index ce40aec..0de8bce 100755
--- a/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {
diff --git a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index 4d3c439..e965ea6 100755
--- a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -75,8 +75,7 @@ public class Jetty9Test {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
- RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
- RealmModel realm = manager.importRealm(representation);
+ AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
}
};
@@ -191,4 +190,12 @@ public class Jetty9Test {
testStrategy.testSessionInvalidatedAfterFailedRefresh();
}
+
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ testStrategy.testAdminApplicationLogout();
+ }
}
diff --git a/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
index ce40aec..0de8bce 100755
--- a/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {
diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java
index d24a80d..076daaf 100755
--- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java
+++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java
@@ -63,8 +63,7 @@ public class TomcatTest {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
- RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
- RealmModel realm = manager.importRealm(representation);
+ AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
}
};
@@ -173,6 +172,14 @@ public class TomcatTest {
}
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ testStrategy.testAdminApplicationLogout();
+ }
+
static String getBaseDirectory() {
String dirPath = null;
String relativeDirPath = "testsuite" + File.separator + "tomcat6" + File.separator + "target";
diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
index ce40aec..0de8bce 100755
--- a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
index b79b085..0039f4e 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
@@ -64,8 +64,7 @@ public class Tomcat7Test {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
- RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
- RealmModel realm = manager.importRealm(representation);
+ AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
}
};
@@ -177,6 +176,14 @@ public class Tomcat7Test {
}
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ testStrategy.testAdminApplicationLogout();
+ }
+
private static String getBaseDirectory() {
String dirPath = null;
diff --git a/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
index ce40aec..0de8bce 100755
--- a/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {
diff --git a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java
index e4834b6..2b03b82 100755
--- a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java
+++ b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java
@@ -64,8 +64,7 @@ public class TomcatTest {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
- RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
- RealmModel realm = manager.importRealm(representation);
+ AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
}
};
@@ -178,6 +177,14 @@ public class TomcatTest {
}
+ /**
+ * KEYCLOAK-942
+ */
+ @Test
+ public void testAdminApplicationLogout() throws Throwable {
+ testStrategy.testAdminApplicationLogout();
+ }
+
private static String getBaseDirectory() {
String dirPath = null;
String relativeDirPath = "testsuite" + File.separator + "tomcat8" + File.separator + "target";
diff --git a/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
index ce40aec..0de8bce 100755
--- a/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
@@ -28,6 +28,21 @@
"applicationRoles": {
"account": [ "manage-account" ]
}
+ },
+ {
+ "username" : "mposolda",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
}
],
"roles" : {