Details
diff --git a/testsuite/integration-arquillian/test-apps/js-console/example-realm.json b/testsuite/integration-arquillian/test-apps/js-console/example-realm.json
index 4e3adca..e90217a 100755
--- a/testsuite/integration-arquillian/test-apps/js-console/example-realm.json
+++ b/testsuite/integration-arquillian/test-apps/js-console/example-realm.json
@@ -19,6 +19,7 @@
],
"realmRoles": [ "user" ],
"clientRoles": {
+ "realm-management" : [ "view-realm" ],
"account": ["view-profile", "manage-account"]
}
},{
diff --git a/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html b/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html
index 468f98e..1c2b61d 100755
--- a/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html
+++ b/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html
@@ -29,6 +29,7 @@
<button onclick="keycloak.register()">Register</button>
<button onclick="refreshToken(9999)">Refresh Token</button>
<button onclick="refreshToken(30)">Refresh Token (if <30s validity)</button>
+ <button onclick="refreshToken(5)">Refresh Token (if <5s validity)</button>
<button onclick="showError()">Show Error Response</button>
<button onclick="loadProfile()">Get Profile</button>
<button onclick="loadUserInfo()">Get User Info</button>
@@ -41,6 +42,13 @@
<button onclick="output(keycloak.createLogoutUrl())">Show Logout URL</button>
<button onclick="output(keycloak.createRegisterUrl())">Show Register URL</button>
<button onclick="createBearerRequest()">Create Bearer Request</button>
+ <button onclick="output(showTime())">Show current time</button>
+ <input id="timeSkewInput"/>
+ <button onclick="addToTimeSkew()">timeSkew offset</button>
+ <button onclick="refreshTimeSkew()">refresh timeSkew</button>
+ <button onclick="sendBearerToKeycloak()">Bearer to keycloak</button>
+
+
<select id="flowSelect">
<option value="standard">standard</option>
<option value="implicit">implicit</option>
@@ -62,6 +70,9 @@
<h2>Events</h2>
<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="events"></pre>
+<h2>Info</h2>
+TimeSkew: <div id="timeSkew"></div>
+
<script>
function loadProfile() {
@@ -135,6 +146,16 @@
document.getElementById('events').innerHTML = new Date().toLocaleString() + "\t" + event + "\n" + e;
}
+ function addToTimeSkew() {
+ var offset = document.getElementById("timeSkewInput").value;
+ keycloak.timeSkew += parseInt(offset);
+ document.getElementById("timeSkew").innerHTML = keycloak.timeSkew;
+ }
+
+ function refreshTimeSkew() {
+ document.getElementById("timeSkew").innerHTML = keycloak.timeSkew;
+ }
+
function createBearerRequest() {
var url = 'http://localhost:8280/js-database/customers';
@@ -167,6 +188,33 @@
req.send();
}
+ function sendBearerToKeycloak() {
+ var url = 'http://localhost:8180/auth/admin/realms/example/roles';
+ if (window.location.href.indexOf("8543") > -1) {
+ url = url.replace("8180","8543");
+ url = url.replace("http","https");
+ }
+
+ var req = new XMLHttpRequest();
+ req.open('GET', url, true);
+ req.setRequestHeader('Accept', 'application/json');
+ req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200) {
+ output('Success');
+ } else if (req.status == 403) {
+ output('Forbidden');
+ } else if (req.status == 401) {
+ output('Unauthorized');
+ }
+ }
+ };
+
+ req.send();
+ }
+
var keycloak;
function keycloakInit() {
@@ -182,6 +230,7 @@
keycloak.onAuthRefreshSuccess = function () {
event('Auth Refresh Success');
+ document.getElementById("timeSkew").innerHTML = keycloak.timeSkew;
};
keycloak.onAuthRefreshError = function () {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleTestApp.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleTestApp.java
index 2a57739..4822c4b 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleTestApp.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSConsoleTestApp.java
@@ -56,6 +56,8 @@ public class JSConsoleTestApp extends AbstractPageWithInjectedUrl {
private WebElement refreshTokenButton;
@FindBy(xpath = "//button[contains(text(),'Refresh Token (if <30s')]")
private WebElement refreshTokenIfUnder30sButton;
+ @FindBy(xpath = "//button[contains(text(),'Refresh Token (if <5s')]")
+ private WebElement refreshTokenIfUnder5sButton;
@FindBy(xpath = "//button[text() = 'Get Profile']")
private WebElement getProfileButton;
@@ -73,6 +75,17 @@ public class JSConsoleTestApp extends AbstractPageWithInjectedUrl {
private WebElement showDetailsButton;
@FindBy(xpath = "//button[text() = 'Create Bearer Request']")
private WebElement createBearerRequest;
+ @FindBy(xpath = "//button[text() = 'Bearer to keycloak']")
+ private WebElement createBearerRequestToKeycloakButton;
+ @FindBy(xpath = "//button[text() = 'refresh timeSkew']")
+ private WebElement refreshTimeSkewButton;
+
+ @FindBy(id = "timeSkew")
+ private WebElement timeSkewValue;
+ @FindBy(id = "timeSkewInput")
+ private WebElement timeSkewInput;
+ @FindBy(xpath = "//button[text() = 'timeSkew offset']")
+ private WebElement timeSkewButton;
@FindBy(id = "flowSelect")
private Select flowSelect;
@@ -104,6 +117,10 @@ public class JSConsoleTestApp extends AbstractPageWithInjectedUrl {
refreshTokenIfUnder30sButton.click();
}
+ public void refreshTokenIfUnder5s() {
+ refreshTokenIfUnder5sButton.click();
+ }
+
public void getProfile() {
getProfileButton.click();
}
@@ -124,6 +141,10 @@ public class JSConsoleTestApp extends AbstractPageWithInjectedUrl {
createBearerRequest.click();
}
+ public void createBearerRequestToKeycloak() {
+ createBearerRequestToKeycloakButton.click();
+ }
+
public void setResponseMode(String value) {
responseModeSelect.selectByValue(value);
}
@@ -143,4 +164,18 @@ public class JSConsoleTestApp extends AbstractPageWithInjectedUrl {
public void showErrorResponse() {
showErrorButton.click();
}
+
+ public WebElement getTimeSkewValue() {
+ return timeSkewValue;
+ }
+
+ public void setTimeSkewOffset(int value) {
+ timeSkewInput.clear();
+ timeSkewInput.sendKeys(Integer.toString(value));
+ timeSkewButton.click();
+ }
+
+ public void refreshTimeSkew() {
+ refreshTimeSkewButton.click();
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
index a91b26b..481f022 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
@@ -66,6 +66,8 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
@Page
private Applications applicationsPage;
+ private static int TIME_SKEW_TOLERANCE = 3;
+
public static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
@Deployment(name = JSConsoleTestApp.DEPLOYMENT_NAME)
@@ -351,6 +353,42 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Authenticated)");
}
+ @Test
+ public void testUpdateToken() {
+ logInAndInit("standard");
+
+ jsConsoleTestAppPage.setTimeSkewOffset(-33);
+ setTimeOffset(33);
+
+ jsConsoleTestAppPage.refreshTokenIfUnder5s();
+
+ jsConsoleTestAppPage.setTimeSkewOffset(-34);
+ setTimeOffset(67);
+
+ jsConsoleTestAppPage.refreshTokenIfUnder5s();
+ jsConsoleTestAppPage.createBearerRequestToKeycloak();
+ waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Success");
+ }
+
+ @Test
+ public void timeSkewTest() {
+ logInAndInit("standard");
+
+ jsConsoleTestAppPage.refreshTimeSkew();
+
+ int timeSkew = Integer.parseInt(jsConsoleTestAppPage.getTimeSkewValue().getText());
+ assertTrue("TimeSkew was: " + timeSkew + ", but should be ~0", timeSkew >= 0 - TIME_SKEW_TOLERANCE);
+ assertTrue("TimeSkew was: " + timeSkew + ", but should be ~0", timeSkew <= TIME_SKEW_TOLERANCE);
+
+ setTimeOffset(40);
+ jsConsoleTestAppPage.refreshToken();
+ jsConsoleTestAppPage.refreshTimeSkew();
+
+ timeSkew = Integer.parseInt(jsConsoleTestAppPage.getTimeSkewValue().getText());
+ assertTrue("TimeSkew was: " + timeSkew + ", but should be ~-40", timeSkew + 40 >= 0 - TIME_SKEW_TOLERANCE);
+ assertTrue("TimeSkew was: " + timeSkew + ", but should be ~-40", timeSkew + 40 <= TIME_SKEW_TOLERANCE);
+ }
+
private void setImplicitFlowForClient() {
ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "js-console");
ClientRepresentation client = clientResource.toRepresentation();