admin cors
This commit is contained in:
parent
0d9e14d4c7
commit
236f3ab768
10 changed files with 165 additions and 27 deletions
|
@ -34,6 +34,24 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h2><span>Realm Roles</span></h2>
|
||||
<button type="submit" data-ng-click="loadRoles()">load Roles</button>
|
||||
<button type="submit" data-ng-click="addRole()">Add Role</button>
|
||||
<button type="submit" data-ng-click="deleteRole()">Delete Role</button>
|
||||
<table class="table" data-ng-show="roles.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role Listing</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="r in roles">
|
||||
<td>{{r.name}}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -29,12 +29,32 @@ angular.element(document).ready(function ($http) {
|
|||
|
||||
module.controller('GlobalCtrl', function($scope, $http) {
|
||||
$scope.products = [];
|
||||
$scope.roles = [];
|
||||
$scope.reloadData = function() {
|
||||
$http.get("http://localhost-db:8080/database/products").success(function(data) {
|
||||
$scope.products = angular.fromJson(data);
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
$scope.loadRoles = function() {
|
||||
$http.query("http://localhost-auth:8080/auth/admin/realms/" + keycloakAuth.realm + "/roles").success(function(data) {
|
||||
$scope.roles = angular.fromJson(data);
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
$scope.addRole = function() {
|
||||
$http.post("http://localhost-auth:8080/auth/admin/realms/" + keycloakAuth.realm + "/roles", {name: 'stuff'}).success(function() {
|
||||
$scope.loadRoles();
|
||||
});
|
||||
|
||||
};
|
||||
$scope.deleteRole = function() {
|
||||
$http.delete("http://localhost-auth:8080/auth/admin/realms/" + keycloakAuth.realm + "/roles/stuff").success(function() {
|
||||
$scope.loadRoles();
|
||||
});
|
||||
|
||||
};
|
||||
$scope.logout = logout;
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"realm" : "cors-realm",
|
||||
"realm" : "cors",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://localhost-auth:8080/auth",
|
||||
"ssl-not-required" : true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"realm": "cors-realm",
|
||||
"realm": "cors",
|
||||
"enabled": true,
|
||||
"accessTokenLifespan": 3000,
|
||||
"accessCodeLifespan": 10,
|
||||
|
@ -57,5 +57,22 @@
|
|||
"http://localhost:8080"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"applicationRoleMappings": {
|
||||
"realm-management": [
|
||||
{
|
||||
"username": "bburke@redhat.com",
|
||||
"roles": ["realm-admin"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"applicationScopeMappings": {
|
||||
"realm-management": [
|
||||
{
|
||||
"client": "angular-product",
|
||||
"roles": ["realm-admin"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,15 @@ public class Auth {
|
|||
this.client = client;
|
||||
}
|
||||
|
||||
public Auth(RealmModel realm, AccessToken token, UserModel user, ClientModel client) {
|
||||
this.cookie = false;
|
||||
this.token = token;
|
||||
this.realm = realm;
|
||||
|
||||
this.user = user;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public boolean isCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ public class AuthenticationManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
return new AuthResult(user, session);
|
||||
return new AuthResult(user, session, token);
|
||||
} catch (VerificationException e) {
|
||||
logger.info("Failed to verify identity token", e);
|
||||
}
|
||||
|
@ -361,10 +361,12 @@ public class AuthenticationManager {
|
|||
public class AuthResult {
|
||||
private final UserModel user;
|
||||
private final UserSessionModel session;
|
||||
private final AccessToken token;
|
||||
|
||||
public AuthResult(UserModel user, UserSessionModel session) {
|
||||
public AuthResult(UserModel user, UserSessionModel session, AccessToken token) {
|
||||
this.user = user;
|
||||
this.session = session;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public UserSessionModel getSession() {
|
||||
|
@ -374,6 +376,10 @@ public class AuthenticationManager {
|
|||
public UserModel getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public AccessToken getToken() {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -103,7 +103,8 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
protected void setupAdminConsole(RealmModel realm) {
|
||||
ApplicationModel adminConsole = new ApplicationManager(this).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
|
||||
ApplicationModel adminConsole = realm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||
if (adminConsole == null) adminConsole = new ApplicationManager(this).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
|
||||
String baseUrl = contextPath + "/admin/" + realm.getName() + "/console";
|
||||
adminConsole.setBaseUrl(baseUrl + "/index.html");
|
||||
adminConsole.setEnabled(true);
|
||||
|
@ -113,12 +114,10 @@ public class RealmManager {
|
|||
RoleModel adminRole;
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||
realm.addScopeMapping(adminConsole, adminRole);
|
||||
} else {
|
||||
ApplicationModel realmApp = realm.getApplicationByName(getRealmAdminApplicationName(realm));
|
||||
adminRole = realmApp.getRole(AdminRoles.REALM_ADMIN);
|
||||
|
||||
// security roles are defined in application for the realm.
|
||||
}
|
||||
realm.addScopeMapping(adminConsole, adminRole);
|
||||
}
|
||||
|
||||
public String getMasterRealmAdminApplicationName(RealmModel realm) {
|
||||
|
@ -265,7 +264,11 @@ public class RealmManager {
|
|||
|
||||
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession));
|
||||
|
||||
ApplicationModel realmAdminApp = applicationManager.createApplication(realm, getRealmAdminApplicationName(realm));
|
||||
String realmAdminApplicationName = getRealmAdminApplicationName(realm);
|
||||
ApplicationModel realmAdminApp = realm.getApplicationByName(realmAdminApplicationName);
|
||||
if (realmAdminApp == null) {
|
||||
realmAdminApp = applicationManager.createApplication(realm, realmAdminApplicationName);
|
||||
}
|
||||
RoleModel adminRole = realmAdminApp.addRole(AdminRoles.REALM_ADMIN);
|
||||
realmAdminApp.setBearerOnly(true);
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ import javax.ws.rs.core.Response;
|
|||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.util.CollectionUtil;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +35,7 @@ public class Cors {
|
|||
|
||||
|
||||
private HttpRequest request;
|
||||
private ResponseBuilder response;
|
||||
private ResponseBuilder builder;
|
||||
private Set<String> allowedOrigins;
|
||||
private Set<String> allowedMethods;
|
||||
private Set<String> exposedHeaders;
|
||||
|
@ -43,13 +45,21 @@ public class Cors {
|
|||
|
||||
public Cors(HttpRequest request, ResponseBuilder response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.builder = response;
|
||||
}
|
||||
|
||||
public Cors(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public static Cors add(HttpRequest request, ResponseBuilder response) {
|
||||
return new Cors(request, response);
|
||||
}
|
||||
|
||||
public static Cors add(HttpRequest request) {
|
||||
return new Cors(request);
|
||||
}
|
||||
|
||||
public Cors preflight() {
|
||||
preflight = true;
|
||||
return this;
|
||||
|
@ -67,6 +77,13 @@ public class Cors {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Cors allowedOrigins(AccessToken token) {
|
||||
if (token != null) {
|
||||
allowedOrigins = token.getAllowedOrigins();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cors allowedMethods(String... allowedMethods) {
|
||||
this.allowedMethods = new HashSet<String>(Arrays.asList(allowedMethods));
|
||||
return this;
|
||||
|
@ -80,35 +97,66 @@ public class Cors {
|
|||
public Response build() {
|
||||
String origin = request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN_HEADER);
|
||||
if (origin == null) {
|
||||
return response.build();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
if (!preflight && (allowedOrigins == null || !allowedOrigins.contains(origin))) {
|
||||
return response.build();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
response.header(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||
builder.header(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||
|
||||
if (allowedMethods != null) {
|
||||
response.header(ACCESS_CONTROL_ALLOW_METHODS, CollectionUtil.join(allowedMethods));
|
||||
builder.header(ACCESS_CONTROL_ALLOW_METHODS, CollectionUtil.join(allowedMethods));
|
||||
} else {
|
||||
response.header(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
|
||||
builder.header(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
|
||||
}
|
||||
|
||||
if (exposedHeaders != null) {
|
||||
response.header(ACCESS_CONTROL_EXPOSE_HEADERS, CollectionUtil.join(exposedHeaders));
|
||||
builder.header(ACCESS_CONTROL_EXPOSE_HEADERS, CollectionUtil.join(exposedHeaders));
|
||||
}
|
||||
|
||||
response.header(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
|
||||
builder.header(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
|
||||
if (auth) {
|
||||
response.header(ACCESS_CONTROL_ALLOW_HEADERS, String.format("%s, %s", DEFAULT_ALLOW_HEADERS, AUTHORIZATION_HEADER));
|
||||
builder.header(ACCESS_CONTROL_ALLOW_HEADERS, String.format("%s, %s", DEFAULT_ALLOW_HEADERS, AUTHORIZATION_HEADER));
|
||||
} else {
|
||||
response.header(ACCESS_CONTROL_ALLOW_HEADERS, DEFAULT_ALLOW_HEADERS);
|
||||
builder.header(ACCESS_CONTROL_ALLOW_HEADERS, DEFAULT_ALLOW_HEADERS);
|
||||
}
|
||||
|
||||
response.header(ACCESS_CONTROL_MAX_AGE, DEFAULT_MAX_AGE);
|
||||
builder.header(ACCESS_CONTROL_MAX_AGE, DEFAULT_MAX_AGE);
|
||||
|
||||
return response.build();
|
||||
return builder.build();
|
||||
}
|
||||
public void build(HttpResponse response) {
|
||||
String origin = request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN_HEADER);
|
||||
if (origin == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preflight && (allowedOrigins == null || !allowedOrigins.contains(origin))) {
|
||||
return;
|
||||
}
|
||||
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||
|
||||
if (allowedMethods != null) {
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_METHODS, CollectionUtil.join(allowedMethods));
|
||||
} else {
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
|
||||
}
|
||||
|
||||
if (exposedHeaders != null) {
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_EXPOSE_HEADERS, CollectionUtil.join(exposedHeaders));
|
||||
}
|
||||
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
|
||||
if (auth) {
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_HEADERS, String.format("%s, %s", DEFAULT_ALLOW_HEADERS, AUTHORIZATION_HEADER));
|
||||
} else {
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_HEADERS, DEFAULT_ALLOW_HEADERS);
|
||||
}
|
||||
|
||||
response.getOutputHeaders().add(ACCESS_CONTROL_MAX_AGE, DEFAULT_MAX_AGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.spi.DefaultOptionsMethodException;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.jboss.resteasy.spi.UnauthorizedException;
|
||||
|
@ -17,10 +20,12 @@ import org.keycloak.services.managers.Auth;
|
|||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.resources.Cors;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
@ -39,6 +44,12 @@ public class AdminRoot {
|
|||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
||||
@Context
|
||||
protected HttpRequest request;
|
||||
|
||||
@Context
|
||||
protected HttpResponse response;
|
||||
|
||||
protected AppAuthManager authManager;
|
||||
protected TokenManager tokenManager;
|
||||
|
||||
|
@ -127,7 +138,7 @@ public class AdminRoot {
|
|||
if (consoleApp == null) {
|
||||
throw new NotFoundException("Could not find admin console application");
|
||||
}
|
||||
Auth auth = new Auth(realm, authResult.getUser(), consoleApp);
|
||||
Auth auth = new Auth(realm, token, authResult.getUser(), consoleApp);
|
||||
return auth;
|
||||
|
||||
|
||||
|
@ -143,10 +154,18 @@ public class AdminRoot {
|
|||
|
||||
@Path("realms")
|
||||
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
|
||||
if (request.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
|
||||
Response response = Cors.add(request, Response.ok()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
|
||||
throw new WebApplicationException(response);
|
||||
}
|
||||
|
||||
Auth auth = authenticateRealmAdminRequest(headers);
|
||||
if (auth != null) {
|
||||
logger.info("authenticated admin access for: " + auth.getUser().getLoginName());
|
||||
}
|
||||
|
||||
Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response);
|
||||
|
||||
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
|
||||
//resourceContext.initResource(adminResource);
|
||||
|
|
|
@ -158,12 +158,10 @@ public class AccountTest {
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void forever() throws Exception{
|
||||
while (true) Thread.sleep(5000);
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void returnToAppFromQueryParam() {
|
||||
|
|
Loading…
Reference in a new issue