KEYCLOAK-10734 Let the check-sso feature do the check in hidden iframe
This commit is contained in:
parent
b3004482fb
commit
49e9cd759b
6 changed files with 103 additions and 4 deletions
|
@ -106,6 +106,13 @@ declare namespace Keycloak {
|
|||
*/
|
||||
redirectUri?: string;
|
||||
|
||||
/**
|
||||
* Specifies an uri to redirect to after silent check-sso.
|
||||
* Silent check-sso will only happen, when this redirect uri is given and
|
||||
* the specified uri is available whithin the application.
|
||||
*/
|
||||
silentCheckSsoRedirectUri?: string;
|
||||
|
||||
/**
|
||||
* Set the OpenID Connect flow.
|
||||
* @default standard
|
||||
|
|
|
@ -116,6 +116,10 @@
|
|||
kc.redirectUri = initOptions.redirectUri;
|
||||
}
|
||||
|
||||
if (initOptions.silentCheckSsoRedirectUri) {
|
||||
kc.silentCheckSsoRedirectUri = initOptions.silentCheckSsoRedirectUri;
|
||||
}
|
||||
|
||||
if (initOptions.pkceMethod) {
|
||||
if (initOptions.pkceMethod !== "S256") {
|
||||
throw 'Invalid value for pkceMethod';
|
||||
|
@ -157,6 +161,29 @@
|
|||
});
|
||||
}
|
||||
|
||||
var checkSsoSilently = function() {
|
||||
var ifrm = document.createElement("iframe");
|
||||
var src = kc.createLoginUrl({prompt: 'none', redirectUri: kc.silentCheckSsoRedirectUri});
|
||||
ifrm.setAttribute("src", src);
|
||||
ifrm.setAttribute("title", "keycloak-silent-check-sso");
|
||||
ifrm.style.display = "none";
|
||||
document.body.appendChild(ifrm);
|
||||
|
||||
var messageCallback = function(event) {
|
||||
if (event.origin !== window.location.origin || ifrm.contentWindow !== event.source) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oauth = parseCallback(event.data);
|
||||
processCallback(oauth, initPromise);
|
||||
|
||||
document.body.removeChild(ifrm);
|
||||
window.removeEventListener("message", messageCallback);
|
||||
};
|
||||
|
||||
window.addEventListener("message", messageCallback);
|
||||
};
|
||||
|
||||
var options = {};
|
||||
switch (initOptions.onLoad) {
|
||||
case 'check-sso':
|
||||
|
@ -164,7 +191,7 @@
|
|||
setupCheckLoginIframe().success(function() {
|
||||
checkLoginIframe().success(function (unchanged) {
|
||||
if (!unchanged) {
|
||||
doLogin(false);
|
||||
kc.silentCheckSsoRedirectUri ? checkSsoSilently() : doLogin(false);
|
||||
} else {
|
||||
initPromise.setSuccess();
|
||||
}
|
||||
|
@ -173,7 +200,7 @@
|
|||
});
|
||||
});
|
||||
} else {
|
||||
doLogin(false);
|
||||
kc.silentCheckSsoRedirectUri ? checkSsoSilently() : doLogin(false);
|
||||
}
|
||||
break;
|
||||
case 'login-required':
|
||||
|
|
|
@ -30,6 +30,13 @@ public class TestJavascriptResource {
|
|||
return resourceToString("/javascript/index.html");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/silent-check-sso.html")
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
public String getJavascriptTestingEnvironmentSilentCheckSso() throws IOException {
|
||||
return resourceToString("/javascript/silent-check-sso.html");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/keycloak.json")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<html><body><script>parent.postMessage(location.href, location.origin)</script></body></html>
|
|
@ -78,6 +78,10 @@ public class JSObjectBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
private boolean skipQuotes(Object o) {
|
||||
return (o instanceof Integer || o instanceof Boolean);
|
||||
}
|
||||
|
||||
public String build() {
|
||||
StringBuilder argument = new StringBuilder("{");
|
||||
String comma = "";
|
||||
|
@ -86,11 +90,11 @@ public class JSObjectBuilder {
|
|||
.append(option.getKey())
|
||||
.append(" : ");
|
||||
|
||||
if (!(option.getValue() instanceof Integer)) argument.append("\"");
|
||||
if (!skipQuotes(option.getValue())) argument.append("\"");
|
||||
|
||||
argument.append(option.getValue());
|
||||
|
||||
if (!(option.getValue() instanceof Integer)) argument.append("\"");
|
||||
if (!skipQuotes(option.getValue())) argument.append("\"");
|
||||
comma = ",";
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ 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 static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
|
@ -153,6 +154,58 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
|
|||
.init(pkceS256, this::assertInitNotAuth);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSilentCheckSso() {
|
||||
JSObjectBuilder checkSSO = defaultArguments().checkSSOOnLoad();
|
||||
testExecutor.init(checkSSO, this::assertInitNotAuth)
|
||||
.login(this::assertOnLoginPage)
|
||||
.loginForm(testUser, this::assertOnTestAppUrl)
|
||||
.init(checkSSO, this::assertSuccessfullyLoggedIn)
|
||||
.refresh()
|
||||
.init(checkSSO
|
||||
.add("silentCheckSsoRedirectUri", authServerContextRootPage + JAVASCRIPT_URL + "/silent-check-sso.html")
|
||||
, this::assertSuccessfullyLoggedIn);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSilentCheckSsoLoginWithLoginIframeDisabled() {
|
||||
JSObjectBuilder checkSSO = defaultArguments().checkSSOOnLoad();
|
||||
testExecutor.init(checkSSO, this::assertInitNotAuth)
|
||||
.login(this::assertOnLoginPage)
|
||||
.loginForm(testUser, this::assertOnTestAppUrl)
|
||||
.init(checkSSO, this::assertSuccessfullyLoggedIn)
|
||||
.refresh()
|
||||
.init(checkSSO
|
||||
.add("checkLoginIframe", false)
|
||||
.add("silentCheckSsoRedirectUri", authServerContextRootPage + JAVASCRIPT_URL + "/silent-check-sso.html")
|
||||
, this::assertSuccessfullyLoggedIn);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSilentCheckSsoWithoutRedirectUri() {
|
||||
JSObjectBuilder checkSSO = defaultArguments().checkSSOOnLoad();
|
||||
try {
|
||||
testExecutor.init(checkSSO, this::assertInitNotAuth)
|
||||
.login(this::assertOnLoginPage)
|
||||
.loginForm(testUser, this::assertOnTestAppUrl)
|
||||
.init(checkSSO, this::assertSuccessfullyLoggedIn)
|
||||
.refresh()
|
||||
.init(checkSSO);
|
||||
fail();
|
||||
} catch (WebDriverException e) {
|
||||
// should happen
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSilentCheckSsoNotAuthenticated() {
|
||||
JSObjectBuilder checkSSO = defaultArguments().checkSSOOnLoad();
|
||||
testExecutor.init(checkSSO
|
||||
.add("checkLoginIframe", false)
|
||||
.add("silentCheckSsoRedirectUri", authServerContextRootPage + JAVASCRIPT_URL + "/silent-check-sso.html")
|
||||
, this::assertInitNotAuth);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshToken() {
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
|
|
Loading…
Reference in a new issue