KEYCLOAK-6068 Fix preflight request on admin endpoints
This commit is contained in:
parent
7d2d7e41d9
commit
e96c6a4bcb
3 changed files with 96 additions and 16 deletions
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.services.resources.Cors;
|
||||
|
||||
import javax.ws.rs.OPTIONS;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Created by st on 21/03/17.
|
||||
*/
|
||||
public class AdminCorsPreflightService {
|
||||
|
||||
private HttpRequest request;
|
||||
|
||||
public AdminCorsPreflightService(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* CORS preflight
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("{any:.*}")
|
||||
@OPTIONS
|
||||
public Response preflight() {
|
||||
return Cors.add(request, Response.ok()).preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
|
||||
}
|
||||
|
||||
}
|
|
@ -19,14 +19,12 @@ package org.keycloak.services.resources.admin;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.jboss.resteasy.spi.NoLogWebApplicationException;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.jboss.resteasy.spi.UnauthorizedException;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -39,11 +37,11 @@ import org.keycloak.services.managers.RealmManager;
|
|||
import org.keycloak.services.resources.Cors;
|
||||
import org.keycloak.services.resources.admin.info.ServerInfoAdminResource;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.services.resources.admin.permissions.RealmsPermissionEvaluator;
|
||||
import org.keycloak.theme.Theme;
|
||||
import org.keycloak.theme.ThemeProvider;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
|
@ -197,7 +195,6 @@ public class AdminRoot {
|
|||
return adminBaseUrl(base).path(AdminRoot.class, "getRealmsAdmin");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base Path to realm admin REST interface
|
||||
*
|
||||
|
@ -205,8 +202,10 @@ public class AdminRoot {
|
|||
* @return
|
||||
*/
|
||||
@Path("realms")
|
||||
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
|
||||
handlePreflightRequest();
|
||||
public Object getRealmsAdmin(@Context final HttpHeaders headers) {
|
||||
if (request.getHttpMethod().equals(HttpMethod.OPTIONS)) {
|
||||
return new AdminCorsPreflightService(request);
|
||||
}
|
||||
|
||||
AdminAuth auth = authenticateRealmAdminRequest(headers);
|
||||
if (auth != null) {
|
||||
|
@ -227,8 +226,10 @@ public class AdminRoot {
|
|||
* @return
|
||||
*/
|
||||
@Path("serverinfo")
|
||||
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
|
||||
handlePreflightRequest();
|
||||
public Object getServerInfo(@Context final HttpHeaders headers) {
|
||||
if (request.getHttpMethod().equals(HttpMethod.OPTIONS)) {
|
||||
return new AdminCorsPreflightService(request);
|
||||
}
|
||||
|
||||
AdminAuth auth = authenticateRealmAdminRequest(headers);
|
||||
if (!AdminPermissions.realms(session, auth).isAdmin()) {
|
||||
|
@ -246,14 +247,6 @@ public class AdminRoot {
|
|||
return adminResource;
|
||||
}
|
||||
|
||||
protected void handlePreflightRequest() {
|
||||
if (request.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
|
||||
logger.debug("Cors admin pre-flight");
|
||||
Response response = Cors.add(request, Response.ok()).preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
|
||||
throw new NoLogWebApplicationException(response);
|
||||
}
|
||||
}
|
||||
|
||||
public static Theme getTheme(KeycloakSession session, RealmModel realm) throws IOException {
|
||||
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
|
||||
return themeProvider.getTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package org.keycloak.testsuite.admin;
|
||||
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpOptions;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.services.resources.Cors;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class AdminPreflightTest extends AbstractAdminTest {
|
||||
|
||||
|
||||
private CloseableHttpClient client;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
client = HttpClientBuilder.create().build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
try {
|
||||
client.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreflight() throws IOException {
|
||||
HttpOptions options = new HttpOptions(getAdminUrl("realms/master/users"));
|
||||
options.setHeader("Origin", "http://test");
|
||||
|
||||
CloseableHttpResponse response = client.execute(options);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
assertEquals("true", response.getFirstHeader(Cors.ACCESS_CONTROL_ALLOW_CREDENTIALS).getValue());
|
||||
assertEquals("DELETE, POST, GET, PUT", response.getFirstHeader(Cors.ACCESS_CONTROL_ALLOW_METHODS).getValue());
|
||||
assertEquals("http://test", response.getFirstHeader(Cors.ACCESS_CONTROL_ALLOW_ORIGIN).getValue());
|
||||
assertEquals("3600", response.getFirstHeader(Cors.ACCESS_CONTROL_MAX_AGE).getValue());
|
||||
assertTrue(response.getFirstHeader(Cors.ACCESS_CONTROL_ALLOW_HEADERS).getValue().contains("Authorization"));
|
||||
assertTrue(response.getFirstHeader(Cors.ACCESS_CONTROL_ALLOW_HEADERS).getValue().contains("Content-Type"));
|
||||
}
|
||||
|
||||
private String getAdminUrl(String resource) {
|
||||
return suiteContext.getAuthServerInfo().getContextRoot().toString() + "/auth/admin/" + resource;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue