KEYCLOAK-942 Incorrect condition in ResourceAdminManager could cause global logout

This commit is contained in:
mposolda 2015-01-07 20:25:29 +01:00
parent e62858cefd
commit fff8ae9f8a
16 changed files with 216 additions and 51 deletions

View file

@ -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; boolean allPassed = true;
// Send logout separately to each host (needed for single-sign-out in cluster for non-distributable apps - KEYCLOAK-748) // 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()) { for (Map.Entry<String, List<String>> entry : adapterSessionIds.entrySet()) {
@ -197,13 +202,11 @@ public class ResourceAdminManager {
return allPassed; return allPassed;
} else { } else {
// Send single logout request // Send single logout request
List<String> allSessionIds = null; List<String> allSessionIds = new ArrayList<String>();
if (adapterSessionIds != null) {
allSessionIds = new ArrayList<String>();
for (List<String> currentIds : adapterSessionIds.values()) { for (List<String> currentIds : adapterSessionIds.values()) {
allSessionIds.addAll(currentIds); allSessionIds.addAll(currentIds);
} }
}
return sendLogoutRequest(realm, resource, allSessionIds, client, 0, managementUrl); return sendLogoutRequest(realm, resource, allSessionIds, client, 0, managementUrl);
} }
} else { } else {

View file

@ -79,9 +79,7 @@ public class AdapterTest {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); RealmModel realm = AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
realmPublicKey = realm.getPublicKey(); realmPublicKey = realm.getPublicKey();
URL url = getClass().getResource("/adapter-test/cust-app-keycloak.json"); 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();
}
} }

View file

@ -28,6 +28,7 @@ import org.junit.rules.ExternalResource;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.Version; import org.keycloak.Version;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.constants.AdapterConstants; import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants; 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.OpenIDConnectService;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.admin.AdminRoot; 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.OAuthClient;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule; import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule; import org.keycloak.testsuite.rule.WebRule;
import org.keycloak.testutils.KeycloakServer;
import org.keycloak.util.BasicAuthHelper; import org.keycloak.util.BasicAuthHelper;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
@ -106,6 +112,15 @@ public class AdapterTestStrategy extends ExternalResource {
if (addSlash) slash = "/"; 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 @Override
protected void before() throws Throwable { protected void before() throws Throwable {
super.before(); super.before();
@ -562,6 +577,25 @@ public class AdapterTestStrategy extends ExternalResource {
}, "demo"); }, "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) { protected void loginAndCheckSession(WebDriver driver, LoginPage loginPage) {
driver.navigate().to(APP_SERVER_BASE_URL + "/session-portal"); driver.navigate().to(APP_SERVER_BASE_URL + "/session-portal");
String currentUrl = driver.getCurrentUrl(); String currentUrl = driver.getCurrentUrl();

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {

View file

@ -21,62 +21,35 @@
*/ */
package org.keycloak.testsuite; package org.keycloak.testsuite;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.jetty.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.adapter.AdapterTestStrategy; import org.keycloak.testsuite.adapter.AdapterTestStrategy;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule; import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.keycloak.testutils.KeycloakServer;
import org.openqa.selenium.WebDriver;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.UriBuilder;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL; import java.net.URL;
import java.security.Principal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class Jetty9Test { public class Jetty8Test {
@ClassRule @ClassRule
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
} }
}; };
@ -89,7 +62,7 @@ public class Jetty9Test {
List<Handler> list = new ArrayList<Handler>(); List<Handler> list = new ArrayList<Handler>();
System.setProperty("app.server.base.url", "http://localhost:8082"); System.setProperty("app.server.base.url", "http://localhost:8082");
System.setProperty("my.host.name", "localhost"); System.setProperty("my.host.name", "localhost");
URL dir = Jetty9Test.class.getResource("/adapter-test/demorealm.json"); URL dir = Jetty8Test.class.getResource("/adapter-test/demorealm.json");
File base = new File(dir.getFile()).getParentFile(); File base = new File(dir.getFile()).getParentFile();
list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal")); list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal"));
list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db")); list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
@ -190,4 +163,13 @@ public class Jetty9Test {
public void testSessionInvalidatedAfterFailedRefresh() throws Throwable { public void testSessionInvalidatedAfterFailedRefresh() throws Throwable {
testStrategy.testSessionInvalidatedAfterFailedRefresh(); testStrategy.testSessionInvalidatedAfterFailedRefresh();
}} }
/**
* KEYCLOAK-942
*/
@Test
public void testAdminApplicationLogout() throws Throwable {
testStrategy.testAdminApplicationLogout();
}
}

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {

View file

@ -75,8 +75,7 @@ public class Jetty9Test {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
} }
}; };
@ -191,4 +190,12 @@ public class Jetty9Test {
testStrategy.testSessionInvalidatedAfterFailedRefresh(); testStrategy.testSessionInvalidatedAfterFailedRefresh();
} }
/**
* KEYCLOAK-942
*/
@Test
public void testAdminApplicationLogout() throws Throwable {
testStrategy.testAdminApplicationLogout();
}
} }

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {

View file

@ -75,8 +75,7 @@ public class Jetty9Test {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
} }
}; };
@ -191,4 +190,12 @@ public class Jetty9Test {
testStrategy.testSessionInvalidatedAfterFailedRefresh(); testStrategy.testSessionInvalidatedAfterFailedRefresh();
} }
/**
* KEYCLOAK-942
*/
@Test
public void testAdminApplicationLogout() throws Throwable {
testStrategy.testAdminApplicationLogout();
}
} }

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {

View file

@ -63,8 +63,7 @@ public class TomcatTest {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
} }
}; };
@ -173,6 +172,14 @@ public class TomcatTest {
} }
/**
* KEYCLOAK-942
*/
@Test
public void testAdminApplicationLogout() throws Throwable {
testStrategy.testAdminApplicationLogout();
}
static String getBaseDirectory() { static String getBaseDirectory() {
String dirPath = null; String dirPath = null;
String relativeDirPath = "testsuite" + File.separator + "tomcat6" + File.separator + "target"; String relativeDirPath = "testsuite" + File.separator + "tomcat6" + File.separator + "target";

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {

View file

@ -64,8 +64,7 @@ public class Tomcat7Test {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
} }
}; };
@ -177,6 +176,14 @@ public class Tomcat7Test {
} }
/**
* KEYCLOAK-942
*/
@Test
public void testAdminApplicationLogout() throws Throwable {
testStrategy.testAdminApplicationLogout();
}
private static String getBaseDirectory() { private static String getBaseDirectory() {
String dirPath = null; String dirPath = null;

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {

View file

@ -64,8 +64,7 @@ public class TomcatTest {
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() { public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
@Override @Override
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class); AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
RealmModel realm = manager.importRealm(representation);
} }
}; };
@ -178,6 +177,14 @@ public class TomcatTest {
} }
/**
* KEYCLOAK-942
*/
@Test
public void testAdminApplicationLogout() throws Throwable {
testStrategy.testAdminApplicationLogout();
}
private static String getBaseDirectory() { private static String getBaseDirectory() {
String dirPath = null; String dirPath = null;
String relativeDirPath = "testsuite" + File.separator + "tomcat8" + File.separator + "target"; String relativeDirPath = "testsuite" + File.separator + "tomcat8" + File.separator + "target";

View file

@ -28,6 +28,21 @@
"applicationRoles": { "applicationRoles": {
"account": [ "manage-account" ] "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" : { "roles" : {