KEYCLOAK-15849 : auth-remote-server exclude -> removed duplicated annotation, fixed @Test(timeout) bug -> replaced by lambda expression.
This commit is contained in:
parent
63b19389c1
commit
4a2830bc2e
5 changed files with 167 additions and 133 deletions
|
@ -27,6 +27,7 @@ import org.jboss.logging.Logger;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.model.TestTimedOutException;
|
||||||
import org.keycloak.admin.client.Keycloak;
|
import org.keycloak.admin.client.Keycloak;
|
||||||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||||
import org.keycloak.admin.client.resource.RealmsResource;
|
import org.keycloak.admin.client.resource.RealmsResource;
|
||||||
|
@ -78,6 +79,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
import java.util.concurrent.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -403,6 +405,34 @@ public abstract class AbstractKeycloakTest {
|
||||||
.replace("8180", "8543");
|
.replace("8180", "8543");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected interface ExecutableTestMethod {
|
||||||
|
void execute() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void runTestWithTimeout(long timeout, ExecutableTestMethod executableTestMethod) throws Exception {
|
||||||
|
ExecutorService service = Executors.newSingleThreadExecutor();
|
||||||
|
Callable<Object> callable = new Callable<Object>() {
|
||||||
|
public Object call() throws Exception {
|
||||||
|
executableTestMethod.execute();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Future<Object> result = service.submit(callable);
|
||||||
|
service.shutdown();
|
||||||
|
try {
|
||||||
|
boolean terminated = service.awaitTermination(timeout,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
if (!terminated) {
|
||||||
|
service.shutdownNow();
|
||||||
|
}
|
||||||
|
result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
throw new TestTimedOutException(timeout, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Return <code>true</code> if you wish to automatically post-process realm and replace
|
* @return Return <code>true</code> if you wish to automatically post-process realm and replace
|
||||||
* all http values with https (and correct ports).
|
* all http values with https (and correct ports).
|
||||||
|
|
|
@ -132,41 +132,42 @@ public class ClientStorageTest extends AbstractTestRealmKeycloakTest {
|
||||||
oauth.clientId("hardcoded-client");
|
oauth.clientId("hardcoded-client");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 4000)
|
@Test
|
||||||
@AuthServerContainerExclude(AuthServer.REMOTE) // testingClient doesn't work with remote
|
public void testSearchTimeout() throws Exception{
|
||||||
public void testSearchTimeout() {
|
runTestWithTimeout(4000, () -> {
|
||||||
String hardcodedClient = HardcodedClientStorageProviderFactory.PROVIDER_ID;
|
String hardcodedClient = HardcodedClientStorageProviderFactory.PROVIDER_ID;
|
||||||
String delayedSearch = HardcodedClientStorageProviderFactory.DELAYED_SEARCH;
|
String delayedSearch = HardcodedClientStorageProviderFactory.DELAYED_SEARCH;
|
||||||
String providerId = this.providerId;
|
String providerId = this.providerId;
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
assertThat(session.clientStorageManager()
|
|
||||||
.searchClientsByClientIdStream(realm, "client", null, null)
|
|
||||||
.map(ClientModel::getClientId)
|
|
||||||
.collect(Collectors.toList()),
|
|
||||||
allOf(
|
|
||||||
hasItem(hardcodedClient),
|
|
||||||
hasItem("root-url-client"))
|
|
||||||
);
|
|
||||||
|
|
||||||
//update the provider to simulate delay during the search
|
|
||||||
ComponentModel memoryProvider = realm.getComponent(providerId);
|
|
||||||
memoryProvider.getConfig().putSingle(delayedSearch, Boolean.toString(true));
|
|
||||||
realm.updateComponent(memoryProvider);
|
|
||||||
|
|
||||||
});
|
assertThat(session.clientStorageManager()
|
||||||
|
.searchClientsByClientIdStream(realm, "client", null, null)
|
||||||
testingClient.server().run(session -> {
|
.map(ClientModel::getClientId)
|
||||||
// search for clients and check hardcoded-client is not present
|
.collect(Collectors.toList()),
|
||||||
assertThat(session.clientStorageManager()
|
allOf(
|
||||||
.searchClientsByClientIdStream(session.realms().getRealmByName(AuthRealm.TEST), "client", null, null)
|
hasItem(hardcodedClient),
|
||||||
.map(ClientModel::getClientId)
|
hasItem("root-url-client"))
|
||||||
.collect(Collectors.toList()),
|
);
|
||||||
allOf(
|
|
||||||
not(hasItem(hardcodedClient)),
|
//update the provider to simulate delay during the search
|
||||||
hasItem("root-url-client")
|
ComponentModel memoryProvider = realm.getComponent(providerId);
|
||||||
));
|
memoryProvider.getConfig().putSingle(delayedSearch, Boolean.toString(true));
|
||||||
|
realm.updateComponent(memoryProvider);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
// search for clients and check hardcoded-client is not present
|
||||||
|
assertThat(session.clientStorageManager()
|
||||||
|
.searchClientsByClientIdStream(session.realms().getRealmByName(AuthRealm.TEST), "client", null, null)
|
||||||
|
.map(ClientModel::getClientId)
|
||||||
|
.collect(Collectors.toList()),
|
||||||
|
allOf(
|
||||||
|
not(hasItem(hardcodedClient)),
|
||||||
|
hasItem("root-url-client")
|
||||||
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,41 +86,42 @@ public class GroupStorageTest extends AbstractTestRealmKeycloakTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 4000)
|
@Test
|
||||||
@AuthServerContainerExclude(AuthServer.REMOTE) // testingClient doesn't work with remote
|
public void testSearchTimeout() throws Exception{
|
||||||
public void testSearchTimeout() {
|
runTestWithTimeout(4000, () -> {
|
||||||
String hardcodedGroup = HardcodedGroupStorageProviderFactory.PROVIDER_ID;
|
String hardcodedGroup = HardcodedGroupStorageProviderFactory.PROVIDER_ID;
|
||||||
String delayedSearch = HardcodedGroupStorageProviderFactory.DELAYED_SEARCH;
|
String delayedSearch = HardcodedGroupStorageProviderFactory.DELAYED_SEARCH;
|
||||||
String providerId = this.providerId;
|
String providerId = this.providerId;
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
assertThat(session.groupStorageManager()
|
assertThat(session.groupStorageManager()
|
||||||
.searchForGroupByName(realm, "group", null, null).stream()
|
.searchForGroupByName(realm, "group", null, null).stream()
|
||||||
.map(GroupModel::getName)
|
.map(GroupModel::getName)
|
||||||
.collect(Collectors.toList()),
|
.collect(Collectors.toList()),
|
||||||
allOf(
|
allOf(
|
||||||
hasItem(hardcodedGroup),
|
hasItem(hardcodedGroup),
|
||||||
hasItem("sample-realm-group"))
|
hasItem("sample-realm-group"))
|
||||||
);
|
);
|
||||||
|
|
||||||
//update the provider to simulate delay during the search
|
//update the provider to simulate delay during the search
|
||||||
ComponentModel memoryProvider = realm.getComponent(providerId);
|
ComponentModel memoryProvider = realm.getComponent(providerId);
|
||||||
memoryProvider.getConfig().putSingle(delayedSearch, Boolean.toString(true));
|
memoryProvider.getConfig().putSingle(delayedSearch, Boolean.toString(true));
|
||||||
realm.updateComponent(memoryProvider);
|
realm.updateComponent(memoryProvider);
|
||||||
});
|
});
|
||||||
|
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
// search for groups and check hardcoded-group is not present
|
// search for groups and check hardcoded-group is not present
|
||||||
assertThat(session.groupStorageManager()
|
assertThat(session.groupStorageManager()
|
||||||
.searchForGroupByName(realm, "group", null, null).stream()
|
.searchForGroupByName(realm, "group", null, null).stream()
|
||||||
.map(GroupModel::getName)
|
.map(GroupModel::getName)
|
||||||
.collect(Collectors.toList()),
|
.collect(Collectors.toList()),
|
||||||
allOf(
|
allOf(
|
||||||
not(hasItem(hardcodedGroup)),
|
not(hasItem(hardcodedGroup)),
|
||||||
hasItem("sample-realm-group")
|
hasItem("sample-realm-group")
|
||||||
));
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,41 +93,42 @@ public class RoleStorageTest extends AbstractTestRealmKeycloakTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 4000)
|
@Test
|
||||||
@AuthServerContainerExclude(AuthServer.REMOTE) // testingClient doesn't work with remote
|
public void testSearchTimeout() throws Exception{
|
||||||
public void testSearchTimeout() {
|
runTestWithTimeout(4000, () -> {
|
||||||
String hardcodedRole = HardcodedRoleStorageProviderFactory.PROVIDER_ID;
|
String hardcodedRole = HardcodedRoleStorageProviderFactory.PROVIDER_ID;
|
||||||
String delayedSearch = HardcodedRoleStorageProviderFactory.DELAYED_SEARCH;
|
String delayedSearch = HardcodedRoleStorageProviderFactory.DELAYED_SEARCH;
|
||||||
String providerId = this.providerId;
|
String providerId = this.providerId;
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
assertThat(session.roleStorageManager()
|
assertThat(session.roleStorageManager()
|
||||||
.searchForRolesStream(realm, "role", null, null)
|
.searchForRolesStream(realm, "role", null, null)
|
||||||
.map(RoleModel::getName)
|
.map(RoleModel::getName)
|
||||||
.collect(Collectors.toList()),
|
.collect(Collectors.toList()),
|
||||||
allOf(
|
allOf(
|
||||||
hasItem(hardcodedRole),
|
hasItem(hardcodedRole),
|
||||||
hasItem("sample-realm-role"))
|
hasItem("sample-realm-role"))
|
||||||
);
|
);
|
||||||
|
|
||||||
//update the provider to simulate delay during the search
|
//update the provider to simulate delay during the search
|
||||||
ComponentModel memoryProvider = realm.getComponent(providerId);
|
ComponentModel memoryProvider = realm.getComponent(providerId);
|
||||||
memoryProvider.getConfig().putSingle(delayedSearch, Boolean.toString(true));
|
memoryProvider.getConfig().putSingle(delayedSearch, Boolean.toString(true));
|
||||||
realm.updateComponent(memoryProvider);
|
realm.updateComponent(memoryProvider);
|
||||||
});
|
});
|
||||||
|
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
// search for roles and check hardcoded-role is not present
|
// search for roles and check hardcoded-role is not present
|
||||||
assertThat(session.roleStorageManager()
|
assertThat(session.roleStorageManager()
|
||||||
.searchForRolesStream(realm, "role", null, null)
|
.searchForRolesStream(realm, "role", null, null)
|
||||||
.map(RoleModel::getName)
|
.map(RoleModel::getName)
|
||||||
.collect(Collectors.toList()),
|
.collect(Collectors.toList()),
|
||||||
allOf(
|
allOf(
|
||||||
not(hasItem(hardcodedRole)),
|
not(hasItem(hardcodedRole)),
|
||||||
hasItem("sample-realm-role")
|
hasItem("sample-realm-role")
|
||||||
));
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,47 +43,48 @@ import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
|
||||||
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT9)
|
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT9)
|
||||||
public class SamlXMLAttacksTest extends AbstractSamlTest {
|
public class SamlXMLAttacksTest extends AbstractSamlTest {
|
||||||
|
|
||||||
@Test(timeout = 4000)
|
@Test
|
||||||
public void testXMLBombAttackResistance() throws Exception {
|
public void testXMLBombAttackResistance() throws Exception {
|
||||||
|
runTestWithTimeout(4000, () -> {
|
||||||
|
String bombDoctype = "<!DOCTYPE AuthnRequest [" +
|
||||||
|
" <!ENTITY lol \"lol\">" +
|
||||||
|
"<!ELEMENT AuthnRequest (#PCDATA)>" +
|
||||||
|
"<!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" +
|
||||||
|
"<!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" +
|
||||||
|
"<!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" +
|
||||||
|
"<!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" +
|
||||||
|
"<!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" +
|
||||||
|
"<!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" +
|
||||||
|
"<!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" +
|
||||||
|
"<!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" +
|
||||||
|
"<!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" +
|
||||||
|
"]>";
|
||||||
|
|
||||||
String bombDoctype = "<!DOCTYPE AuthnRequest [" +
|
String samlAuthnRequest = "<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"a123\" Version=\"2.0\" IssueInstant=\"2014-07-16T23:52:45Z\" >" +
|
||||||
" <!ENTITY lol \"lol\">" +
|
"<saml:Issuer>" + SAML_CLIENT_ID_SALES_POST + "&lol9;</saml:Issuer>" +
|
||||||
"<!ELEMENT AuthnRequest (#PCDATA)>" +
|
"</samlp:AuthnRequest>";
|
||||||
"<!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" +
|
|
||||||
"<!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" +
|
|
||||||
"<!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" +
|
|
||||||
"<!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" +
|
|
||||||
"<!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" +
|
|
||||||
"<!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" +
|
|
||||||
"<!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" +
|
|
||||||
"<!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" +
|
|
||||||
"<!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" +
|
|
||||||
"]>";
|
|
||||||
|
|
||||||
String samlAuthnRequest = "<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"a123\" Version=\"2.0\" IssueInstant=\"2014-07-16T23:52:45Z\" >" +
|
|
||||||
"<saml:Issuer>" + SAML_CLIENT_ID_SALES_POST + "&lol9;</saml:Issuer>" +
|
|
||||||
"</samlp:AuthnRequest>";
|
|
||||||
|
|
||||||
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
|
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
|
||||||
HttpPost post = new HttpPost(getAuthServerSamlEndpoint(REALM_NAME));
|
HttpPost post = new HttpPost(getAuthServerSamlEndpoint(REALM_NAME));
|
||||||
|
|
||||||
List<NameValuePair> parameters = new LinkedList<>();
|
List<NameValuePair> parameters = new LinkedList<>();
|
||||||
String encoded = PostBindingUtil.base64Encode(bombDoctype + samlAuthnRequest);
|
String encoded = PostBindingUtil.base64Encode(bombDoctype + samlAuthnRequest);
|
||||||
parameters.add(new BasicNameValuePair(GeneralConstants.SAML_REQUEST_KEY, encoded));
|
parameters.add(new BasicNameValuePair(GeneralConstants.SAML_REQUEST_KEY, encoded));
|
||||||
|
|
||||||
UrlEncodedFormEntity formEntity;
|
UrlEncodedFormEntity formEntity;
|
||||||
try {
|
try {
|
||||||
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
post.setEntity(formEntity);
|
||||||
|
|
||||||
|
try (CloseableHttpResponse response = client.execute(post)) {
|
||||||
|
assertThat(response, bodyHC(containsString("Invalid Request")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
post.setEntity(formEntity);
|
|
||||||
|
|
||||||
try (CloseableHttpResponse response = client.execute(post)) {
|
|
||||||
assertThat(response, bodyHC(containsString("Invalid Request")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deployment(name = "DTD")
|
@Deployment(name = "DTD")
|
||||||
|
|
Loading…
Reference in a new issue