diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js index 845ea3006a..e67ee0eff9 100755 --- a/adapters/oidc/js/src/main/resources/keycloak.js +++ b/adapters/oidc/js/src/main/resources/keycloak.js @@ -362,8 +362,24 @@ } } + function domReady() { + var promise = createPromise(); + + var checkReadyState = function () { + if (document.readyState === 'interactive' || document.readyState === 'complete') { + document.removeEventListener('readystatechange', checkReadyState); + promise.setSuccess(); + } + } + document.addEventListener('readystatechange', checkReadyState); + + checkReadyState(); // just in case the event was already fired and we missed it (in case the init is done later than at the load time, i.e. it's done from code) + + return promise.promise; + } + configPromise.then(function () { - check3pCookiesSupported().then(processInit) + domReady().then(check3pCookiesSupported).then(processInit) .catch(function() { promise.setError(); }); diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestJavascriptResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestJavascriptResource.java index 992ab892c2..7bfe6d8163 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestJavascriptResource.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestJavascriptResource.java @@ -41,6 +41,14 @@ public class TestJavascriptResource { return resourceToString("/javascript/index.html"); } + @GET + @Path("/init-in-head.html") + @Produces(MediaType.TEXT_HTML) + public String getJavascriptTestingEnvironmentWithInitInHead() throws IOException { + session.getProvider(SecurityHeadersProvider.class).options().skipHeaders(); + return resourceToString("/javascript/init-in-head.html"); + } + @GET @Path("/silent-check-sso.html") @Produces(MediaType.TEXT_HTML) diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/init-in-head.html b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/init-in-head.html new file mode 100644 index 0000000000..5cea6bd608 --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/javascript/init-in-head.html @@ -0,0 +1,65 @@ + + + + + + + + + +

Result

+

+
+

Events

+

+
+
+
+
+
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java
index 54b33be1c5..9a2693b0d9 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/javascript/JavascriptTestExecutor.java
@@ -322,4 +322,9 @@ public class JavascriptTestExecutor {
 
         return this;
     }
+
+    public JavascriptTestExecutor validateOutputField(JavascriptStateValidator validator) {
+        validator.validate(jsDriver, output, events);
+        return this;
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java
index ba30f75e81..97ad45d3f1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/javascript/JavascriptAdapterTest.java
@@ -18,6 +18,8 @@ import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.arquillian.SuiteContext;
+import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
+import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
 import org.keycloak.testsuite.auth.page.account.Applications;
 import org.keycloak.testsuite.auth.page.login.OAuthGrant;
 import org.keycloak.testsuite.auth.page.login.UpdatePassword;
@@ -47,16 +49,11 @@ import static org.hamcrest.collection.IsMapContaining.hasEntry;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
-import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
-
-import static org.junit.Assume.assumeFalse;
+import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_HOST;
 import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
 import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
 import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
-import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_HOST;
 
 /**
  * @author mhajas
@@ -65,6 +62,7 @@ import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_HOST;
 public class JavascriptAdapterTest extends AbstractJavascriptTest {
 
     private String testAppUrl;
+    private String testAppWithInitInHeadUrl;
     protected JavascriptTestExecutor testExecutor;
     private static int TIME_SKEW_TOLERANCE = 3;
 
@@ -90,7 +88,9 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
 
     @Before
     public void setDefaultEnvironment() {
-        testAppUrl = authServerContextRootPage.toString().replace(AUTH_SERVER_HOST, JS_APP_HOST) + JAVASCRIPT_URL + "/index.html";
+        String testAppRootUrl = authServerContextRootPage.toString().replace(AUTH_SERVER_HOST, JS_APP_HOST) + JAVASCRIPT_URL;
+        testAppUrl = testAppRootUrl + "/index.html";
+        testAppWithInitInHeadUrl = testAppRootUrl + "/init-in-head.html";
 
         jsDriverTestRealmLoginPage.setAuthRealm(REALM_NAME);
         oAuthGrantPage.setAuthRealm(REALM_NAME);
@@ -101,10 +101,8 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
         events.poll();
         jsDriver.manage().deleteAllCookies();
 
-        jsDriver.navigate().to(testAppUrl);
+        navigateToTestApp(testAppUrl);
 
-        waitUntilElement(outputArea).is().present();
-        assertCurrentUrlStartsWith(testAppUrl, jsDriver);
         testExecutor = JavascriptTestExecutor.create(jsDriver, jsDriverTestRealmLoginPage);
 
         jsDriver.manage().deleteAllCookies();
@@ -121,6 +119,14 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
     }
 
     private void assertOnTestAppUrl(WebDriver jsDriver, Object output, WebElement events) {
+        assertOnTestAppUrl(jsDriver, output, events, testAppUrl);
+    }
+
+    private void assertOnTestAppWithInitInHeadUrl(WebDriver jsDriver, Object output, WebElement events) {
+        assertOnTestAppUrl(jsDriver, output, events, testAppWithInitInHeadUrl);
+    }
+
+    private void assertOnTestAppUrl(WebDriver jsDriver, Object output, WebElement events, String testAppUrl) {
         waitForPageToLoad();
         assertCurrentUrlStartsWith(testAppUrl, jsDriver);
     }
@@ -748,7 +754,24 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
         });
     }
 
+    @Test
+    // KEYCLOAK-15158
+    public void testInitInHead() {
+        navigateToTestApp(testAppWithInitInHeadUrl);
+
+        testExecutor.validateOutputField(this::assertInitNotAuth)
+                .login(this::assertOnLoginPage)
+                .loginForm(testUser, this::assertOnTestAppWithInitInHeadUrl)
+                .validateOutputField(this::assertInitAuth);
+    }
+
     protected void assertAdapterIsLoggedIn(WebDriver driver1, Object output, WebElement events) {
         assertTrue(testExecutor.isLoggedIn());
     }
+
+    protected void navigateToTestApp(final String testAppUrl) {
+        jsDriver.navigate().to(testAppUrl);
+        waitUntilElement(outputArea).is().present();
+        assertCurrentUrlStartsWith(testAppUrl, jsDriver);
+    }
 }