KEYCLOAK-4556 KEYCLOAK-5022 Only cache keycloak.js and iframe if specific version is requested (#4289)

This commit is contained in:
Stian Thorgersen authored and GitHub committed 2017-07-04 21:18:34 +02:00
1 parent 1e6f099eb0
commit 9a9f4137e5
10 files changed
+94 -52

No files matched your search

@@ -33,6 +33,13 @@
interval: 5
};
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
if ((scripts[i].src.indexOf('keycloak.js') !== -1 || scripts[i].src.indexOf('keycloak.min.js') !== -1) && scripts[i].src.indexOf('version=') !== -1) {
kc.iframeVersion = scripts[i].src.substring(scripts[i].src.indexOf('version=') + 8).split('&')[0];
}
}
kc.init = function (initOptions) {
kc.authenticated = false;
@@ -831,6 +838,10 @@
}
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
if (kc.iframeVersion) {
src = src + '?version=' + kc.iframeVersion;
}
iframe.setAttribute('src', src );
iframe.style.display = 'none';
document.body.appendChild(iframe);
@@ -28,7 +28,7 @@
} else if (!init) {
var req = new XMLHttpRequest();
var url = location.href + "/init";
var url = location.href.split("?")[0] + "/init";
url += "?client_id=" + encodeURIComponent(clientId);
url += "&origin=" + encodeURIComponent(origin);
@@ -171,7 +171,7 @@ public class OIDCLoginProtocolService {
@Path("login-status-iframe.html")
public Object getLoginStatusIframe() {
LoginStatusIframeEndpoint endpoint = new LoginStatusIframeEndpoint(realm);
LoginStatusIframeEndpoint endpoint = new LoginStatusIframeEndpoint();
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
return endpoint;
}
@@ -17,6 +17,7 @@
package org.keycloak.protocol.oidc.endpoints;
import org.keycloak.common.Version;
import org.keycloak.common.util.UriUtils;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
@@ -28,8 +29,10 @@ import org.keycloak.utils.MediaType;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -41,26 +44,26 @@ import java.util.Set;
*/
public class LoginStatusIframeEndpoint {
@Context
private UriInfo uriInfo;
@Context
private KeycloakSession session;
private RealmModel realm;
public LoginStatusIframeEndpoint(RealmModel realm) {
this.realm = realm;
}
@GET
@Produces(MediaType.TEXT_HTML_UTF_8)
public Response getLoginStatusIframe(@QueryParam("client_id") String client_id,
@QueryParam("origin") String origin) {
public Response getLoginStatusIframe(@QueryParam("version") String version) {
CacheControl cacheControl;
if (version != null) {
if (!version.equals(Version.RESOURCES_VERSION)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
cacheControl = CacheControlUtil.getDefaultCacheControl();
} else {
cacheControl = CacheControlUtil.noCache();
}
InputStream resource = getClass().getClassLoader().getResourceAsStream("login-status-iframe.html");
if (resource != null) {
P3PHelper.addP3PHeader(session);
return Response.ok(resource).cacheControl(CacheControlUtil.getDefaultCacheControl()).build();
return Response.ok(resource).cacheControl(cacheControl).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
@@ -70,6 +73,7 @@ public class LoginStatusIframeEndpoint {
@Path("init")
public Response preCheck(@QueryParam("client_id") String clientId, @QueryParam("origin") String origin) {
try {
UriInfo uriInfo = session.getContext().getUri();
RealmModel realm = session.getContext().getRealm();
ClientModel client = session.realms().getClientByClientId(clientId, realm);
if (client != null) {
@@ -17,14 +17,15 @@
package org.keycloak.services.resources;
import org.keycloak.Config;
import org.keycloak.common.Version;
import org.keycloak.services.util.CacheControlUtil;
import org.keycloak.utils.MediaType;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Response;
import java.io.InputStream;
@@ -45,37 +46,29 @@ public class JsResource {
@GET
@Path("/keycloak.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakJs() {
return getJs("keycloak.js");
public Response getKeycloakJs(@QueryParam("version") String version) {
return getJs("keycloak.js", version);
}
@GET
@Path("/{version}/keycloak.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakJsWithVersion(@PathParam("version") String version) {
if (!version.equals(Version.RESOURCES_VERSION)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return getKeycloakJs();
return getJs("keycloak.js", version);
}
@GET
@Path("/keycloak.min.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakMinJs() {
return getJs("keycloak.min.js");
public Response getKeycloakMinJs(@QueryParam("version") String version) {
return getJs("keycloak.min.js", version);
}
@GET
@Path("/{version}/keycloak.min.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakMinJsWithVersion(@PathParam("version") String version) {
if (!version.equals(Version.RESOURCES_VERSION)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return getKeycloakMinJs();
return getJs("keycloak.min.js", version);
}
/**
@@ -86,46 +79,44 @@ public class JsResource {
@GET
@Path("/keycloak-authz.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakAuthzJs() {
return getJs("keycloak-authz.js");
public Response getKeycloakAuthzJs(@QueryParam("version") String version) {
return getJs("keycloak-authz.js", version);
}
@GET
@Path("/{version}/keycloak-authz.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakAuthzJsWithVersion(@PathParam("version") String version) {
if (!version.equals(Version.RESOURCES_VERSION)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return getKeycloakAuthzJs();
return getJs("keycloak-authz.js", version);
}
@GET
@Path("/keycloak-authz.min.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakAuthzMinJs() {
return getJs("keycloak-authz.min.js");
public Response getKeycloakAuthzMinJs(@QueryParam("version") String version) {
return getJs("keycloak-authz.min.js", version);
}
@GET
@Path("/{version}/keycloak-authz.min.js")
@Produces(MediaType.TEXT_PLAIN_JAVASCRIPT)
public Response getKeycloakAuthzMinJsWithVersion(@PathParam("version") String version) {
if (!version.equals(Version.RESOURCES_VERSION)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return getKeycloakAuthzMinJs();
return getJs("keycloak-authz.min.js", version);
}
private Response getJs(String name) {
private Response getJs(String name, String version) {
CacheControl cacheControl;
if (version != null) {
if (!version.equals(Version.RESOURCES_VERSION)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
cacheControl = CacheControlUtil.getDefaultCacheControl();
} else {
cacheControl = CacheControlUtil.noCache();
}
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(name);
if (inputStream != null) {
CacheControl cacheControl = new CacheControl();
cacheControl.setNoTransform(false);
cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
@@ -50,7 +50,7 @@ public class SerializationUtil {
oos.writeObject(t);
oos.close();
return Base64.encodeBytes(os.toByteArray());
return "EXCEPTION:" + Base64.encodeBytes(os.toByteArray());
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -58,6 +58,7 @@ public class SerializationUtil {
public static Throwable decodeException(String result) {
try {
result = result.substring("EXCEPTION:".length());
byte[] bytes = Base64.decode(result);
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(is);
@@ -101,7 +101,7 @@ public class KeycloakTestingClient {
String encoded = SerializationUtil.encode(function);
String result = testing(realm != null ? realm : "master").runOnServer(encoded);
if (result != null && !result.isEmpty() && !result.trim().startsWith("{")) {
if (result != null && !result.isEmpty() && result.trim().startsWith("EXCEPTION:")) {
Throwable t = SerializationUtil.decodeException(result);
if (t instanceof AssertionError) {
throw (AssertionError) t;
@@ -117,7 +117,7 @@ public class KeycloakTestingClient {
String encoded = SerializationUtil.encode(function);
String result = testing(realm != null ? realm : "master").runOnServer(encoded);
if (result != null && !result.isEmpty() && !result.trim().startsWith("{")) {
if (result != null && !result.isEmpty() && result.trim().startsWith("EXCEPTION:")) {
Throwable t = SerializationUtil.decodeException(result);
if (t instanceof AssertionError) {
throw (AssertionError) t;
@@ -30,13 +30,18 @@ import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.common.Version;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.ActionURIUtils;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
import java.io.IOException;
import java.net.URLEncoder;
@@ -56,6 +61,11 @@ import static org.junit.Assert.assertTrue;
*/
public class LoginStatusIframeEndpointTest extends AbstractKeycloakTest {
@Deployment
public static WebArchive deploy() {
return RunOnServerDeployment.create(LoginStatusIframeEndpointTest.class);
}
@Test
public void checkIframe() throws IOException {
CookieStore cookieStore = new BasicCookieStore();
@@ -185,6 +195,24 @@ public class LoginStatusIframeEndpointTest extends AbstractKeycloakTest {
}
}
@Test
public void checkIframeCache() throws IOException {
String version = testingClient.server().fetch(session -> Version.RESOURCES_VERSION, String.class);
CloseableHttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html");
CloseableHttpResponse response = client.execute(get);
assertEquals(200, response.getStatusLine().getStatusCode());
assertEquals("no-cache, must-revalidate, no-transform, no-store", response.getHeaders("Cache-Control")[0].getValue());
get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html?version=" + version);
response = client.execute(get);
assertEquals(200, response.getStatusLine().getStatusCode());
assertTrue(response.getHeaders("Cache-Control")[0].getValue().contains("max-age"));
}
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
}
@@ -44,6 +44,12 @@ public class RunOnServerTest extends AbstractKeycloakTest {
return RunOnServerDeployment.create(RunOnServerTest.class);
}
@Test
public void runOnServerString() throws IOException {
String string = testingClient.server().fetch(session -> "Hello world!", String.class);
assertEquals("Hello world!", string);
}
@Test
public void runOnServerRep() throws IOException {
final String realmName = "master";
@@ -20,6 +20,7 @@
var consoleBaseUrl = '${consoleBaseUrl}';
var resourceUrl = '${resourceUrl}';
var masterRealm = '${masterRealm}';
var resourceVersion = '${resourceVersion}';
</script>
<!-- Minimized versions (for those that have one) -->
@@ -58,7 +59,7 @@
<script src="${resourceUrl}/lib/ui-ace/min/ace.js"></script>
<script src="${resourceUrl}/lib/ui-ace/ui-ace.min.js"></script>
<script src="${authUrl}/js/${resourceVersion}/keycloak.js" type="text/javascript"></script>
<script src="${authUrl}/js/keycloak.js?version=${resourceVersion}" type="text/javascript"></script>
<script src="${resourceUrl}/js/app.js" type="text/javascript"></script>
<script src="${resourceUrl}/js/controllers/realm.js" type="text/javascript"></script>