KEYCLOAK-4556 KEYCLOAK-5022 Only cache keycloak.js and iframe if specific version is requested (#4289)
This commit is contained in:
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;
|
||||
}
|
||||
|
||||
+16
-12
@@ -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();
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+28
@@ -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) {
|
||||
}
|
||||
|
||||
+6
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user