KEYCLOAK-13770 Fix Quarkus ScriptDeploymentTests, Hostnametests and tests relying on user attribute config

This commit is contained in:
Dominik 2021-09-17 15:36:02 +02:00 committed by Pedro Igor
parent 6e8cd3262d
commit 20b91c7d4f
12 changed files with 134 additions and 44 deletions

View file

@ -1051,7 +1051,7 @@ Make sure you build the project using the `quarkus` profile as follows:
Run tests using the `auth-server-quarkus` profile:
mvn -f testsuite/integration-arquillian/tests/base/pom.xml clean install -Pauth-server-quarkus
mvn -f testsuite/integration-arquillian/pom.xml clean install -Pauth-server-quarkus
### Debug the Server
@ -1091,3 +1091,20 @@ because this is not UI testing). For debugging purposes you can override the hea
-Pfirefox-strict-cookies \
-Dtest=**.adapter.** \
-Dauth.server.host=[some_host] -Dauth.server.host2=[some_other_host]
## Hostname Tests
For changing the hostname in the hostname tests (e.g. [DefaultHostnameTest](https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/url/DefaultHostnameTest.java)),
we rely on [nip.io](https://nip.io) for DNS switching, so tests will work everywhere without fiddling with `etc/hosts` locally.
### Tips & Tricks:
Although it _should_ work in general, you may experience an exception like this:
```
java.lang.RuntimeException: java.net.UnknownHostException: keycloak.127.0.0.1.nip.io: nodename nor servname provided,
or not known at org.keycloak.testsuite.util.OAuthClient.doWellKnownRequest(OAuthClient.java:1032)
at org.keycloak.testsuite.url.DefaultHostnameTest.assertBackendForcedToFrontendWithMatchingHostname(
DefaultHostnameTest.java:226)
...
```
when running these tests on your local machine. This happens when something on your machine or network is blocking DNS queries to [nip.io](https://nip.io)
One possible workaround is to add a commonly used public dns server (e.g. 8.8.8.8 for google dns server) to your local
networks dns configuration and run the tests.

View file

@ -23,5 +23,9 @@ spi.hostname.default.frontend-url = ${keycloak.frontendUrl:}
spi.truststore.file.file=${kc.home.dir}/conf/keycloak.truststore
spi.truststore.file.password=secret
# Declarative User Profile
spi.user-profile.declarative-user-profile.read-only-attributes=deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing
spi.user-profile.declarative-user-profile.admin-read-only-attributes=deniedSomeAdmin
# http client connection reuse settings
spi.connections-http-client.default.reuse-connections=false

View file

@ -9,9 +9,12 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
@ -32,6 +35,7 @@ import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.logging.Logger;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.descriptor.api.Descriptor;
import org.keycloak.testsuite.arquillian.SuiteContext;
@ -51,6 +55,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
private boolean forceReaugmentation;
private List<String> additionalArgs = Collections.emptyList();
private List<String> runtimeProperties = Collections.emptyList();
@Override
public Class<KeycloakQuarkusConfiguration> getConfigurationClass() {
@ -89,12 +94,27 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
@Override
public ProtocolMetaData deploy(Archive<?> archive) throws DeploymentException {
return null;
log.infof("Trying to deploy: " + archive.getName());
try {
deployArchiveToServer(archive);
restartServer();
} catch (Exception e) {
throw new DeploymentException(e.getMessage(),e);
}
return new ProtocolMetaData();
}
@Override
public void undeploy(Archive<?> archive) throws DeploymentException {
File wrkDir = configuration.getProvidersPath().resolve("providers").toFile();
try {
Files.deleteIfExists(wrkDir.toPath().resolve(archive.getName()));
restartServer();
} catch (Exception e) {
throw new DeploymentException(e.getMessage(),e);
}
}
@Override
@ -171,9 +191,9 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
commands.add("--cluster=" + System.getProperty("auth.server.quarkus.cluster.config", "local"));
commands.addAll(getRuntimeProperties());
addAdditionalCommands(commands);
return commands.toArray(new String[commands.size()]);
return commands.toArray(new String[0]);
}
private void addAdditionalCommands(List<String> commands) {
@ -277,8 +297,31 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
additionalArgs = Arrays.asList(args);
}
public void resetConfiguration() {
public void resetConfiguration(boolean isReAugmentationNeeded) {
additionalArgs = Collections.emptyList();
runtimeProperties = Collections.emptyList();
if (isReAugmentationNeeded) {
forceReAugmentation();
}
}
private void deployArchiveToServer(Archive<?> archive) throws IOException {
File providersDir = configuration.getProvidersPath().resolve("providers").toFile();
InputStream zipStream = archive.as(ZipExporter.class).exportAsInputStream();
Files.copy(zipStream, providersDir.toPath().resolve(archive.getName()), StandardCopyOption.REPLACE_EXISTING);
}
private void restartServer() throws Exception {
forceReaugmentation = true;
stop();
start();
}
public List<String> getRuntimeProperties() {
return runtimeProperties;
}
public void setRuntimeProperties(List<String> runtimeProperties) {
this.runtimeProperties = runtimeProperties;
}
}

View file

@ -39,7 +39,7 @@ public class SpiProvidersSwitchingUtils {
System.clearProperty("keycloak." + annotation.spi() + ".provider");
} else if (authServerInfo.isQuarkus()) {
KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer) authServerInfo.getArquillianContainer().getDeployableContainer();
container.resetConfiguration();
container.resetConfiguration(true);
} else {
OnlineManagementClient client = AuthServerTestEnricher.getManagementClient();
if (annotation.onlyUpdateDefault()) {

View file

@ -36,15 +36,13 @@ import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.QUARKUS;
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@AuthServerContainerExclude({REMOTE, QUARKUS}) // TODO: Enable this for quarkus and hopefully for remote as well...
@AuthServerContainerExclude({REMOTE}) // TODO: Enable this for quarkus and hopefully for remote as well...
public class AccountRestServiceReadOnlyAttributesTest extends AbstractRestServiceTest {
private static final Logger logger = Logger.getLogger(AccountRestServiceReadOnlyAttributesTest.class);

View file

@ -47,7 +47,6 @@ import org.keycloak.models.credential.OTPCredentialModel;
import org.keycloak.models.credential.PasswordCredentialModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
@ -102,6 +101,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
@ -110,11 +111,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.keycloak.testsuite.Assert.assertNames;
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.QUARKUS;
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
@ -1104,7 +1103,7 @@ public class UserTest extends AbstractAdminTest {
}
@Test
@AuthServerContainerExclude({REMOTE, QUARKUS}) // TODO: Enable for quarkus and remote
@AuthServerContainerExclude({REMOTE}) // TODO: Enable for remote
public void updateUserWithReadOnlyAttributes() {
// Admin is able to update "usercertificate" attribute
UserRepresentation user1 = new UserRepresentation();

View file

@ -85,7 +85,6 @@ public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
@BeforeClass
public static void verifyEnvironment() {
ContainerAssume.assumeNotAuthServerUndertow();
ContainerAssume.assumeNotAuthServerQuarkus();
}
@Rule
@ -122,9 +121,9 @@ public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
.user(okayUser);
}
public void configureFlows() {
public void configureFlows() throws Exception {
deployer.deploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
if (testContext.isInitialized()) {
return;
}
@ -139,10 +138,10 @@ public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
.builtIn(false)
.build();
Response createFlowResponse = testRealm().flows().createFlow(scriptBrowserFlow);
Response createFlowResponse = adminClient.realm(TEST_REALM_NAME).flows().createFlow(scriptBrowserFlow);
Assert.assertEquals(201, createFlowResponse.getStatus());
RealmRepresentation realm = testRealm().toRepresentation();
RealmRepresentation realm = adminClient.realm(TEST_REALM_NAME).toRepresentation();
realm.setBrowserFlow(scriptFlow);
realm.setDirectGrantFlow(scriptFlow);
testRealm().update(realm);
@ -175,15 +174,16 @@ public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
}
@After
public void onAfter() {
public void onAfter() throws Exception {
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
}
/**
* KEYCLOAK-3491
*/
@Test
public void loginShouldWorkWithScriptAuthenticator() {
public void loginShouldWorkWithScriptAuthenticator() throws Exception {
configureFlows();
loginPage.open();
@ -197,7 +197,7 @@ public class DeployedScriptAuthenticatorTest extends AbstractFlowTest {
* KEYCLOAK-3491
*/
@Test
public void loginShouldFailWithScriptAuthenticator() {
public void loginShouldFailWithScriptAuthenticator() throws Exception {
configureFlows();
loginPage.open();

View file

@ -37,7 +37,6 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.common.Profile;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.mappers.ScriptBasedOIDCProtocolMapper;
import org.keycloak.representations.AccessToken;
@ -45,7 +44,6 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.provider.ScriptProviderDescriptor;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.util.ContainerAssume;
import org.keycloak.testsuite.util.OAuthClient;
@ -74,20 +72,21 @@ public class DeployedScriptMapperTest extends AbstractTestRealmKeycloakTest {
@BeforeClass
public static void verifyEnvironment() {
ContainerAssume.assumeNotAuthServerUndertow();
ContainerAssume.assumeNotAuthServerQuarkus();
}
@ArquillianResource
private Deployer deployer;
@Before
public void configureFlows() {
public void configureFlows() throws Exception {
deployer.deploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
}
@After
public void onAfter() {
public void onAfter() throws Exception {
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
}
@Override

View file

@ -51,7 +51,6 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.provider.ScriptProviderDescriptor;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
import org.keycloak.testsuite.authz.AbstractAuthzTest;
@ -88,8 +87,8 @@ public class DeployedScriptPolicyTest extends AbstractAuthzTest {
@BeforeClass
public static void verifyEnvironment() {
ContainerAssume.assumeNotAuthServerUndertow();
ContainerAssume.assumeNotAuthServerQuarkus();
}
@ArquillianResource
private Deployer deployer;
@ -109,15 +108,17 @@ public class DeployedScriptPolicyTest extends AbstractAuthzTest {
}
@Before
public void onBefore() {
public void onBefore() throws Exception {
deployer.deploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
AuthorizationResource authorization = getAuthorizationResource();
authorization.resources().create(new ResourceRepresentation("Default Resource"));
}
@After
public void onAfter() {
public void onAfter() throws Exception {
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
}
@Test

View file

@ -67,20 +67,21 @@ public class UndeployedScriptMapperNotAvailableTest extends AbstractTestRealmKey
@BeforeClass
public static void verifyEnvironment() {
ContainerAssume.assumeNotAuthServerUndertow();
ContainerAssume.assumeNotAuthServerQuarkus();
}
@ArquillianResource
private Deployer deployer;
@Before
public void configureFlows() {
public void configureFlows() throws Exception {
deployer.deploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
}
@After
public void onAfter() {
public void onAfter() throws Exception {
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
reconnectAdminClient();
}
@Override
@ -92,7 +93,6 @@ public class UndeployedScriptMapperNotAvailableTest extends AbstractTestRealmKey
@EnableFeature(value = SCRIPTS, skipRestart = true, executeAsLast = false)
public void testMapperNotRecognizedWhenDisabled() throws Exception {
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
{
ProtocolMapperRepresentation mapper = createScriptMapper("test-script-mapper1", "computed-via-script",
"computed-via-script", "String", true, true, "'hello_' + user.username", false);
@ -101,9 +101,10 @@ public class UndeployedScriptMapperNotAvailableTest extends AbstractTestRealmKey
app.getProtocolMappers().createMapper(mapper).close();
}
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
assertTrue(app.getProtocolMappers().getMappers().isEmpty());
assertTrue(app.getProtocolMappers().getMappersPerProtocol(app.toRepresentation().getProtocol()).isEmpty());
reconnectAdminClient();
ClientResource cl = findClientResourceByClientId(adminClient.realm("test"), "test-app");
assertTrue(cl.getProtocolMappers().getMappers().isEmpty());
assertTrue(cl.getProtocolMappers().getMappersPerProtocol(cl.toRepresentation().getProtocol()).isEmpty());
}
}

View file

@ -3,12 +3,17 @@ package org.keycloak.testsuite.url;
import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.logging.Logger;
import org.keycloak.common.util.SystemEnvProperties;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer;
import org.wildfly.extras.creaper.core.online.ModelNodeResult;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
private static final Logger LOGGER = Logger.getLogger(AbstractHostnameTest.class);
@ -34,6 +39,11 @@ public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
executeCli("/subsystem=keycloak-server/spi=hostname:remove",
"/subsystem=keycloak-server/spi=hostname/:add(default-provider=default)",
"/subsystem=keycloak-server/spi=hostname/provider=default/:add(properties={frontendUrl => \"${keycloak.frontendUrl:}\",forceBackendUrlToFrontendUrl => \"false\"},enabled=true)");
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
container.resetConfiguration(false);
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else {
throw new RuntimeException("Don't know how to config");
}
@ -60,6 +70,17 @@ public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
"frontendUrl => \"" + frontendUrl + "\"" +
",forceBackendUrlToFrontendUrl => \"" + forceBackendUrlToFrontendUrl + "\"" +
(adminUrl != null ? ",adminUrl=\"" + adminUrl + "\"" : "") + "},enabled=true)");
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
List<String> runtimeProperties = new ArrayList<>();
runtimeProperties.add("--spi-hostname-default-frontend-url="+frontendUrl);
runtimeProperties.add("--spi-hostname-default-force-backend-url-to-frontend-url="+ forceBackendUrlToFrontendUrl);
if (adminUrl != null){
runtimeProperties.add("--spi-hostname-default-admin-url="+adminUrl);
}
container.setRuntimeProperties(runtimeProperties);
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else {
throw new RuntimeException("Don't know how to config");
}
@ -69,7 +90,6 @@ public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
void configureFixed(String hostname, int httpPort, int httpsPort, boolean alwaysHttps) throws Exception {
if (suiteContext.getAuthServerInfo().isUndertow()) {
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
System.setProperty("keycloak.hostname.provider", "fixed");
@ -82,7 +102,16 @@ public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
executeCli("/subsystem=keycloak-server/spi=hostname:remove",
"/subsystem=keycloak-server/spi=hostname/:add(default-provider=fixed)",
"/subsystem=keycloak-server/spi=hostname/provider=fixed/:add(properties={hostname => \"" + hostname + "\",httpPort => \"" + httpPort + "\",httpsPort => \"" + httpsPort + "\",alwaysHttps => \"" + alwaysHttps + "\"},enabled=true)");
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
List<String> runtimeProperties = new ArrayList<>();
runtimeProperties.add("--spi-hostname-fixed-hostname="+hostname);
runtimeProperties.add("--spi-hostname-fixed-http-port="+ httpPort);
runtimeProperties.add("--spi-hostname-fixed-https-port="+ httpsPort);
runtimeProperties.add("--spi-hostname-fixed-always-https="+ alwaysHttps);
container.setRuntimeProperties(runtimeProperties);
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else {
throw new RuntimeException("Don't know how to config");
}

View file

@ -38,12 +38,11 @@ import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.QUARKUS;
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT;
import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot;
@AuthServerContainerExclude({REMOTE, QUARKUS})
@AuthServerContainerExclude({REMOTE})
public class DefaultHostnameTest extends AbstractHostnameTest {
@ArquillianResource