Invalidating domain cache and introducing cache for more query methods

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2024-07-18 21:21:50 -03:00 committed by Michal Hajas
parent 1f8280c71a
commit 04bd6653ec
8 changed files with 417 additions and 43 deletions

View file

@ -0,0 +1,49 @@
/*
* Copyright 2024 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.models.cache.infinispan.organization;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.models.cache.infinispan.entities.InRealm;
public class CachedMembership extends AbstractRevisioned implements InRealm {
private final RealmModel realm;
private final boolean managed;
private final boolean isMember;
public CachedMembership(Long revision, String key, RealmModel realm, boolean managed, boolean isMember) {
super(revision, key);
this.realm = realm;
this.managed = managed;
this.isMember = isMember;
}
@Override
public String getRealm() {
return realm.getId();
}
public boolean isManaged() {
return managed;
}
public boolean isMember() {
return isMember;
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2024 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.models.cache.infinispan.organization;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import org.keycloak.models.OrganizationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.infinispan.entities.AbstractRevisioned;
import org.keycloak.models.cache.infinispan.entities.InRealm;
public class CachedOrganizationIds extends AbstractRevisioned implements InRealm {
private final RealmModel realm;
private final Set<String> orgIds = new HashSet<>();
public CachedOrganizationIds(Long revision, String id, RealmModel realm, Stream<OrganizationModel> organizations) {
super(revision, id);
this.realm = realm;
organizations.map(OrganizationModel::getId).forEach(orgIds::add);
}
@Override
public String getRealm() {
return realm.getId();
}
public Set<String> getOrgIds() {
return orgIds;
}
}

View file

@ -21,7 +21,7 @@ import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.MembershipMetadata; import org.keycloak.models.OrganizationDomainModel;
import org.keycloak.models.OrganizationModel; import org.keycloak.models.OrganizationModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
@ -56,7 +56,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
@Override @Override
public boolean remove(OrganizationModel organization) { public boolean remove(OrganizationModel organization) {
registerOrganizationInvalidation(organization.getId()); registerOrganizationInvalidation(organization);
registerCountInvalidation(); registerCountInvalidation();
return orgDelegate.remove(organization); return orgDelegate.remove(organization);
} }
@ -73,47 +73,42 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
Long loaded = realmCache.getCache().getCurrentRevision(id); Long loaded = realmCache.getCache().getCurrentRevision(id);
OrganizationModel model = orgDelegate.getById(id); OrganizationModel model = orgDelegate.getById(id);
if (model == null) return null; if (model == null) return null;
if (realmCache.getInvalidations().contains(id)) return model; if (isInvalid(id)) return model;
cached = new CachedOrganization(loaded, getRealm(), model); cached = new CachedOrganization(loaded, getRealm(), model);
realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision()); realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision());
// no need to check for realm invalidation as IdP changes are handled by events within InfinispanOrganizationProviderFactory // no need to check for realm invalidation as IdP changes are handled by events within InfinispanOrganizationProviderFactory
} else if (realmCache.getInvalidations().contains(id)) { } else if (isInvalid(id)) {
return orgDelegate.getById(id); return orgDelegate.getById(id);
} else if (managedOrganizations.containsKey(id)) { } else if (managedOrganizations.containsKey(id)) {
return managedOrganizations.get(id); return managedOrganizations.get(id);
} }
OrganizationAdapter adapter = new OrganizationAdapter(cached, realmCache, orgDelegate); OrganizationAdapter adapter = new OrganizationAdapter(cached, realmCache, orgDelegate, this);
managedOrganizations.put(id, adapter); managedOrganizations.put(id, adapter);
return adapter; return adapter;
} }
@Override @Override
public OrganizationModel getByDomainName(String domainName) { public OrganizationModel getByDomainName(String domainName) {
String cacheKey = getRealm().getId() + "+.org.domain.name." + domainName; String cacheKey = cacheKeyByDomain(domainName);
CachedOrganization cached = realmCache.getCache().get(cacheKey, CachedOrganization.class);
String realmId = getRealm().getId(); if (isInvalid(cacheKey)) {
if (cached != null && !cached.getRealm().equals(realmId)) { return orgDelegate.getByDomainName(domainName);
cached = null;
} }
CachedOrganizationIds cached = realmCache.getCache().get(cacheKey, CachedOrganizationIds.class);
if (cached == null) { if (cached == null) {
Long loaded = realmCache.getCache().getCurrentRevision(cacheKey); Long loaded = realmCache.getCache().getCurrentRevision(cacheKey);
OrganizationModel model = orgDelegate.getByDomainName(domainName); OrganizationModel model = orgDelegate.getByDomainName(domainName);
if (model == null) return null; if (model == null) {
if (realmCache.getInvalidations().contains(model.getId())) return model; return null;
cached = new CachedOrganization(loaded, getRealm(), model); }
cached = new CachedOrganizationIds(loaded, cacheKey, getRealm(), Stream.of(model));
realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision()); realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision());
// no need to check for realm invalidation as IdP changes are handled by events within InfinispanOrganizationProviderFactory
} else if (realmCache.getInvalidations().contains(cached.getId())) {
return orgDelegate.getByDomainName(domainName);
} else if (managedOrganizations.containsKey(cached.getId())) {
return managedOrganizations.get(cached.getId());
} }
OrganizationAdapter adapter = new OrganizationAdapter(cached, realmCache, orgDelegate);
managedOrganizations.put(cacheKey, adapter); return cached.getOrgIds().stream().map(this::getById).findAny().orElse(null);
return adapter;
} }
@Override @Override
@ -137,16 +132,19 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
@Override @Override
public boolean addManagedMember(OrganizationModel organization, UserModel user) { public boolean addManagedMember(OrganizationModel organization, UserModel user) {
registerMemberInvalidation(organization, user);
return orgDelegate.addManagedMember(organization, user); return orgDelegate.addManagedMember(organization, user);
} }
@Override @Override
public boolean addMember(OrganizationModel organization, UserModel user) { public boolean addMember(OrganizationModel organization, UserModel user) {
registerMemberInvalidation(organization, user);
return orgDelegate.addMember(organization, user); return orgDelegate.addMember(organization, user);
} }
@Override @Override
public boolean removeMember(OrganizationModel organization, UserModel member) { public boolean removeMember(OrganizationModel organization, UserModel member) {
registerMemberInvalidation(organization, member);
return orgDelegate.removeMember(organization, member); return orgDelegate.removeMember(organization, member);
} }
@ -157,24 +155,76 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
@Override @Override
public UserModel getMemberById(OrganizationModel organization, String id) { public UserModel getMemberById(OrganizationModel organization, String id) {
return orgDelegate.getMemberById(organization, id); RealmModel realm = getRealm();
UserModel user = session.users().getUserById(realm, id);
if (user == null) {
return null;
}
String cacheKey = cacheKeyMembership(realm, organization, user);
if (isInvalid(cacheKey)) {
return orgDelegate.getMemberById(organization, user.getId());
}
CachedMembership cached = realmCache.getCache().get(cacheKey, CachedMembership.class);
if (cached == null) {
boolean isManaged = orgDelegate.isManagedMember(organization, user);
Long loaded = realmCache.getCache().getCurrentRevision(cacheKey);
UserModel member = orgDelegate.getMemberById(organization, user.getId());
cached = new CachedMembership(loaded, cacheKeyMembership(realm, organization, user), realm, isManaged, member != null);
realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision());
}
return cached.isMember() ? user : null;
} }
@Override @Override
public Stream<OrganizationModel> getByMember(UserModel member) { public Stream<OrganizationModel> getByMember(UserModel member) {
return orgDelegate.getByMember(member); String cacheKey = cacheKeyByMember(member);
if (isInvalid(cacheKey)) {
return orgDelegate.getByMember(member);
}
CachedOrganizationIds cached = realmCache.getCache().get(cacheKey, CachedOrganizationIds.class);
if (cached == null) {
Long loaded = realmCache.getCache().getCurrentRevision(cacheKey);
Stream<OrganizationModel> model = orgDelegate.getByMember(member);
cached = new CachedOrganizationIds(loaded, cacheKey, getRealm(), model);
realmCache.getCache().addRevisioned(cached, realmCache.getStartupRevision());
}
return cached.getOrgIds().stream().map(this::getById);
} }
@Override @Override
public boolean isManagedMember(OrganizationModel organization, UserModel member) { public boolean isManagedMember(OrganizationModel organization, UserModel user) {
return orgDelegate.isManagedMember(organization, member); UserModel member = getMemberById(organization, user.getId());
if (member == null) {
return false;
}
String cacheKey = cacheKeyMembership(getRealm(), organization, member);
CachedMembership cached = realmCache.getCache().get(cacheKey, CachedMembership.class);
if (cached == null) {
return orgDelegate.isManagedMember(organization, user);
}
return cached.isManaged();
} }
@Override @Override
public boolean addIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider) { public boolean addIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider) {
boolean added = orgDelegate.addIdentityProvider(organization, identityProvider); boolean added = orgDelegate.addIdentityProvider(organization, identityProvider);
if (added) { if (added) {
registerOrganizationInvalidation(organization.getId()); registerOrganizationInvalidation(organization);
} }
return added; return added;
} }
@ -188,7 +238,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
public boolean removeIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider) { public boolean removeIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider) {
boolean removed = orgDelegate.removeIdentityProvider(organization, identityProvider); boolean removed = orgDelegate.removeIdentityProvider(organization, identityProvider);
if (removed) { if (removed) {
registerOrganizationInvalidation(organization.getId()); registerOrganizationInvalidation(organization);
} }
return removed; return removed;
} }
@ -204,7 +254,7 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
CachedOrganizationCount cached = realmCache.getCache().get(cacheKey, CachedOrganizationCount.class); CachedOrganizationCount cached = realmCache.getCache().get(cacheKey, CachedOrganizationCount.class);
// cached and not invalidated // cached and not invalidated
if (cached != null && !realmCache.getInvalidations().contains(cacheKey)) { if (cached != null && !isInvalid(cacheKey)) {
return cached.getCount(); return cached.getCount();
} }
@ -221,13 +271,20 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
orgDelegate.close(); orgDelegate.close();
} }
void registerOrganizationInvalidation(String orgId) { void registerOrganizationInvalidation(OrganizationModel organization) {
OrganizationAdapter adapter = managedOrganizations.get(orgId); String id = organization.getId();
realmCache.registerInvalidation(id);
organization.getDomains()
.map(OrganizationDomainModel::getName)
.map(this::cacheKeyByDomain)
.forEach(realmCache::registerInvalidation);
OrganizationAdapter adapter = managedOrganizations.get(id);
if (adapter != null) { if (adapter != null) {
adapter.invalidate(); adapter.invalidate();
} }
realmCache.registerInvalidation(orgId);
} }
private void registerCountInvalidation() { private void registerCountInvalidation() {
@ -245,4 +302,25 @@ public class InfinispanOrganizationProvider implements OrganizationProvider {
private Stream<OrganizationModel> getCacheDelegates(Stream<OrganizationModel> backendOrganizations) { private Stream<OrganizationModel> getCacheDelegates(Stream<OrganizationModel> backendOrganizations) {
return backendOrganizations.map(OrganizationModel::getId).map(this::getById); return backendOrganizations.map(OrganizationModel::getId).map(this::getById);
} }
private String cacheKeyByDomain(String domainName) {
return getRealm().getId() + ".org.domain.name." + domainName;
}
private String cacheKeyByMember(UserModel user) {
return getRealm().getId() + ".org.member." + user.getId() + ".orgs";
}
private String cacheKeyMembership(RealmModel realm, OrganizationModel organization, UserModel user) {
return realm.getId() + ".org." + organization.getId() + ".member." + user.getId() + ".membership";
}
void registerMemberInvalidation(OrganizationModel organization, UserModel member) {
realmCache.registerInvalidation(cacheKeyByMember(member));
realmCache.registerInvalidation(cacheKeyMembership(getRealm(), organization, member));
}
private boolean isInvalid(String cacheKey) {
return realmCache.getInvalidations().contains(cacheKey);
}
} }

View file

@ -22,6 +22,7 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.organization.OrganizationProvider; import org.keycloak.organization.OrganizationProvider;
import org.keycloak.models.OrganizationModel; import org.keycloak.models.OrganizationModel;
import org.keycloak.organization.OrganizationProviderFactory; import org.keycloak.organization.OrganizationProviderFactory;
@ -41,12 +42,17 @@ public class InfinispanOrganizationProviderFactory implements OrganizationProvid
@Override @Override
public void postInit(KeycloakSessionFactory factory) { public void postInit(KeycloakSessionFactory factory) {
factory.register(event -> { factory.register(e -> {
if (event instanceof RealmModel.IdentityProviderUpdatedEvent idpUpdatedEvent) { if (e instanceof RealmModel.IdentityProviderUpdatedEvent event) {
registerOrganizationInvalidation(idpUpdatedEvent.getKeycloakSession(), idpUpdatedEvent.getUpdatedIdentityProvider()); registerOrganizationInvalidation(event.getKeycloakSession(), event.getUpdatedIdentityProvider());
} }
if (event instanceof RealmModel.IdentityProviderRemovedEvent idpRemovedEvent) { if (e instanceof RealmModel.IdentityProviderRemovedEvent event) {
registerOrganizationInvalidation(idpRemovedEvent.getKeycloakSession(), idpRemovedEvent.getRemovedIdentityProvider()); registerOrganizationInvalidation(event.getKeycloakSession(), event.getRemovedIdentityProvider());
}
if (e instanceof UserModel.UserRemovedEvent event) {
KeycloakSession session = event.getKeycloakSession();
InfinispanOrganizationProvider orgProvider = (InfinispanOrganizationProvider) session.getProvider(OrganizationProvider.class, getId());
orgProvider.getByMember(event.getUser()).forEach(organization -> orgProvider.registerMemberInvalidation(organization, event.getUser()));
} }
}); });
} }
@ -55,7 +61,8 @@ public class InfinispanOrganizationProviderFactory implements OrganizationProvid
if (idp.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE) != null) { if (idp.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE) != null) {
InfinispanOrganizationProvider orgProvider = (InfinispanOrganizationProvider) session.getProvider(OrganizationProvider.class, getId()); InfinispanOrganizationProvider orgProvider = (InfinispanOrganizationProvider) session.getProvider(OrganizationProvider.class, getId());
if (orgProvider != null) { if (orgProvider != null) {
orgProvider.registerOrganizationInvalidation(idp.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE)); OrganizationModel organization = orgProvider.getById(idp.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE));
orgProvider.registerOrganizationInvalidation(organization);
} }
} }
} }

View file

@ -36,11 +36,13 @@ public class OrganizationAdapter implements OrganizationModel {
private final CacheRealmProvider realmCache; private final CacheRealmProvider realmCache;
private final CachedOrganization cached; private final CachedOrganization cached;
private final OrganizationProvider delegate; private final OrganizationProvider delegate;
private final InfinispanOrganizationProvider organizationCache;
public OrganizationAdapter(CachedOrganization cached, CacheRealmProvider realmCache, OrganizationProvider delegate) { public OrganizationAdapter(CachedOrganization cached, CacheRealmProvider realmCache, OrganizationProvider delegate, InfinispanOrganizationProvider organizationCache) {
this.cached = cached; this.cached = cached;
this.realmCache = realmCache; this.realmCache = realmCache;
this.delegate = delegate; this.delegate = delegate;
this.organizationCache = organizationCache;
this.modelSupplier = this::getOrganizationModel; this.modelSupplier = this::getOrganizationModel;
} }
@ -62,8 +64,8 @@ public class OrganizationAdapter implements OrganizationModel {
private void getDelegateForUpdate() { private void getDelegateForUpdate() {
if (updated == null) { if (updated == null) {
realmCache.registerInvalidation(cached.getId());
updated = modelSupplier.get(); updated = modelSupplier.get();
organizationCache.registerOrganizationInvalidation(updated);
if (updated == null) throw new IllegalStateException("Not found in database"); if (updated == null) throw new IllegalStateException("Not found in database");
} }
} }

View file

@ -125,8 +125,9 @@ public class JpaOrganizationProvider implements OrganizationProvider {
GroupModel group = getOrganizationGroup(entity); GroupModel group = getOrganizationGroup(entity);
if (group != null) { if (group != null) {
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
//TODO: won't scale, requires a better mechanism for bulk deleting users //TODO: won't scale, requires a better mechanism for bulk deleting users
userProvider.getGroupMembersStream(realm, group).forEach(userModel -> removeMember(organization, userModel)); userProvider.getGroupMembersStream(realm, group).forEach(userModel -> provider.removeMember(organization, userModel));
groupProvider.removeGroup(realm, group); groupProvider.removeGroup(realm, group);
} }

View file

@ -417,7 +417,6 @@ public abstract class AbstractBrokerSelfRegistrationTest extends AbstractOrganiz
List<FederatedIdentityRepresentation> federatedIdentities = testRealm().users().get(user.getId()).getFederatedIdentity(); List<FederatedIdentityRepresentation> federatedIdentities = testRealm().users().get(user.getId()).getFederatedIdentity();
assertEquals(1, federatedIdentities.size()); assertEquals(1, federatedIdentities.size());
assertEquals(bc.getIDPAlias(), federatedIdentities.get(0).getIdentityProvider()); assertEquals(bc.getIDPAlias(), federatedIdentities.get(0).getIdentityProvider());
} }
@Test @Test

View file

@ -0,0 +1,190 @@
/*
* Copyright 2024 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.organization.cache;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.common.Profile.Feature;
import org.keycloak.models.OrganizationDomainModel;
import org.keycloak.models.OrganizationModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.organization.OrganizationProvider;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest;
import org.keycloak.testsuite.runonserver.RunOnServer;
@EnableFeature(Feature.ORGANIZATION)
public class OrganizationCacheTest extends AbstractOrganizationTest {
@Before
public void onBefore() {
createOrganization("orga");
createOrganization("orgb");
}
@After
public void onAfter() {
List<UserRepresentation> users = testRealm().users().search("member");
if (!users.isEmpty()) {
UserRepresentation member = users.get(0);
testRealm().users().get(member.getId()).remove();
}
}
@Test
public void testGetByDomain() {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel acme = orgProvider.getByDomainName("orga.org");
assertNotNull(acme);
acme.setDomains(Set.of(new OrganizationDomainModel("acme.org")));
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel acme = orgProvider.getByDomainName("orga.org");
assertNull(acme);
acme = orgProvider.getByDomainName("acme.org");
assertNotNull(acme);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel acme = orgProvider.getByDomainName("acme.org");
assertNotNull(acme);
orgProvider.remove(acme);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel acme = orgProvider.getByDomainName("acme.org");
assertNull(acme);
});
}
@Test
public void testGetByMember() {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel orga = orgProvider.getByDomainName("orga.org");
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().addUser(realm, "member");
member.setEnabled(true);
orgProvider.addMember(orga, member);
OrganizationModel orgb = orgProvider.getByDomainName("orgb.org");
orgProvider.addMember(orgb, member);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
Stream<OrganizationModel> memberOf = orgProvider.getByMember(member);
assertEquals(2, memberOf.count());
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel orga = orgProvider.getByDomainName("orga.org");
orgProvider.remove(orga);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
Stream<OrganizationModel> memberOf = orgProvider.getByMember(member);
assertEquals(1, memberOf.count());
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
OrganizationModel orgb = orgProvider.getByDomainName("orgb.org");
orgProvider.removeMember(orgb, member);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
Stream<OrganizationModel> memberOf = orgProvider.getByMember(member);
assertEquals(0, memberOf.count());
});
}
@Test
public void testGetByMemberId() {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel orga = orgProvider.getByDomainName("orga.org");
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().addUser(realm, "member");
member.setEnabled(true);
orgProvider.addMember(orga, member);
OrganizationModel orgb = orgProvider.getByDomainName("orgb.org");
orgProvider.addMember(orgb, member);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel org = orgProvider.getByDomainName("orga.org");
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
UserModel memberOf = orgProvider.getMemberById(org, member.getId());
assertNotNull(memberOf);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel org = orgProvider.getByDomainName("orga.org");
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
orgProvider.removeMember(org, member);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel orga = orgProvider.getByDomainName("orga.org");
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
assertNull(orgProvider.getMemberById(orga, member.getId()));
OrganizationModel orgb = orgProvider.getByDomainName("orgb.org");
assertNotNull(orgProvider.getMemberById(orgb, member.getId()));
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
OrganizationModel orgb = orgProvider.getByDomainName("orgb.org");
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
assertEquals(1, orgProvider.getByMember(member).count());
orgProvider.remove(orgb);
});
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) session -> {
OrganizationProvider orgProvider = session.getProvider(OrganizationProvider.class);
RealmModel realm = session.getContext().getRealm();
UserModel member = session.users().getUserByUsername(realm, "member");
assertEquals(0, orgProvider.getByMember(member).count());
});
}
}