diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
index 72a1e77..0bb71c0 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
@@ -274,6 +274,10 @@ public class UserCacheSession implements UserCache {
}
protected UserModel validateCache(RealmModel realm, CachedUser cached) {
+ if (!realm.getId().equals(cached.getRealm())) {
+ return null;
+ }
+
StorageId storageId = new StorageId(cached.getId());
if (!storageId.isLocal()) {
ComponentModel component = realm.getComponent(storageId.getProviderId());
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index de64bf8..8ab450e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -152,10 +152,10 @@ public class UsersResource {
try {
UserModel user = session.users().getUserById(id, realm);
if (user == null) {
- throw new NotFoundException("User not found");
+ return Response.status(Status.NOT_FOUND).build();
}
- Set<String> attrsToRemove;
+ Set<String> attrsToRemove;
if (rep.getAttributes() != null) {
attrsToRemove = new HashSet<>(user.getAttributes().keySet());
attrsToRemove.removeAll(rep.getAttributes().keySet());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/CrossRealmPermissionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/CrossRealmPermissionsTest.java
new file mode 100644
index 0000000..100e452
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/CrossRealmPermissionsTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.admin;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.common.util.Time;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.Constants;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.resources.admin.RealmAuth.Resource;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.CredentialBuilder;
+import org.keycloak.testsuite.util.GreenMailRule;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+
+import javax.ws.rs.ClientErrorException;
+import javax.ws.rs.core.Response;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class CrossRealmPermissionsTest extends AbstractKeycloakTest {
+
+ private static final String REALM_NAME = "crossrealm-test";
+ private static final String REALM2_NAME = "crossrealm2-test";
+
+ private RealmResource realm1;
+ private RealmResource realm2;
+
+ @Rule public GreenMailRule greenMailRule = new GreenMailRule();
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ RealmBuilder builder = RealmBuilder.create().name(REALM_NAME).testMail();
+ builder.client(ClientBuilder.create().clientId("test-client").publicClient().directAccessGrants());
+
+ builder.user(UserBuilder.create()
+ .username(AdminRoles.REALM_ADMIN)
+ .role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN)
+ .addPassword("password"));
+ testRealms.add(builder.build());
+
+ realm1 = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth", REALM_NAME, AdminRoles.REALM_ADMIN, "password", "test-client", "secret").realm(REALM_NAME);
+
+ builder = RealmBuilder.create().name(REALM2_NAME).testMail();
+ builder.client(ClientBuilder.create().clientId("test-client").publicClient().directAccessGrants());
+
+ builder.user(UserBuilder.create()
+ .username(AdminRoles.REALM_ADMIN)
+ .role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN)
+ .addPassword("password"));
+
+ testRealms.add(builder.build());
+
+ realm2 = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth", REALM2_NAME, AdminRoles.REALM_ADMIN, "password", "test-client", "secret").realm(REALM2_NAME);
+ }
+
+ @Test
+ public void users() {
+ UserRepresentation user = UserBuilder.create().username("randomuser-" + Time.currentTimeMillis()).build();
+ Response response = realm1.users().create(user);
+ String userId = ApiUtil.getCreatedId(response);
+ response.close();
+
+ realm1.users().get(userId).toRepresentation();
+
+ expectNotFound(new PermissionsTest.Invocation() {
+ @Override
+ public void invoke(RealmResource realm) {
+ realm.users().get(userId).toRepresentation();
+ }
+ }, realm2);
+
+ expectNotFound(new PermissionsTest.Invocation() {
+ @Override
+ public void invoke(RealmResource realm) {
+ realm.users().get(userId).update(new UserRepresentation());
+ }
+ }, realm2);
+
+ expectNotFound(new PermissionsTest.Invocation() {
+ @Override
+ public void invoke(RealmResource realm) {
+ realm.users().get(userId).remove();
+ }
+ }, realm2);
+
+ expectNotFound(new PermissionsTest.Invocation() {
+ @Override
+ public void invoke(RealmResource realm) {
+ realm.users().get(userId).getUserSessions();
+ }
+ }, realm2);
+ }
+
+ private void expectNotFound(final PermissionsTest.Invocation invocation, RealmResource realm) {
+ expectNotFound(new PermissionsTest.InvocationWithResponse() {
+ public void invoke(RealmResource realm, AtomicReference<Response> response) {
+ invocation.invoke(realm);
+ }
+ }, realm);
+ }
+
+ private void expectNotFound(PermissionsTest.InvocationWithResponse invocation, RealmResource realm) {
+ int statusCode = 0;
+ try {
+ AtomicReference<Response> responseReference = new AtomicReference<>();
+ invocation.invoke(realm, responseReference);
+ Response response = responseReference.get();
+ if (response != null) {
+ statusCode = response.getStatus();
+ } else {
+ fail("Expected failure");
+ }
+ } catch (ClientErrorException e) {
+ statusCode = e.getResponse().getStatus();
+ }
+
+ assertEquals(404, statusCode);
+ }
+
+}