keycloak-aplcache
Changes
federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/membership/group/GroupLDAPStorageMapper.java 63(+52 -11)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperSyncTest.java 6(+5 -1)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperTest.java 89(+81 -8)
testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPGroupMapperNoImportTest.java 4(+2 -2)
Details
diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/membership/group/GroupLDAPStorageMapper.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/membership/group/GroupLDAPStorageMapper.java
index a92dfb0..f6a7c53 100644
--- a/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/membership/group/GroupLDAPStorageMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/membership/group/GroupLDAPStorageMapper.java
@@ -391,7 +391,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
// Create or update KC groups to LDAP including their attributes
for (GroupModel kcGroup : realm.getTopLevelGroups()) {
- processLdapGroupSyncToLDAP(kcGroup, ldapGroupsMap, ldapGroupNames, syncResult);
+ processKeycloakGroupSyncToLDAP(kcGroup, ldapGroupsMap, ldapGroupNames, syncResult);
}
// If dropNonExisting, then drop all groups, which doesn't exist in KC from LDAP as well
@@ -409,7 +409,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
// Finally process memberships,
if (config.isPreserveGroupsInheritance()) {
for (GroupModel kcGroup : realm.getTopLevelGroups()) {
- processLdapGroupMembershipsSyncToLDAP(kcGroup, ldapGroupsMap);
+ processKeycloakGroupMembershipsSyncToLDAP(kcGroup, ldapGroupsMap);
}
}
@@ -419,7 +419,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
// For given kcGroup check if it exists in LDAP (map) by name
// If not, create it in LDAP including attributes. Otherwise update attributes in LDAP.
// Process this recursively for all subgroups of KC group
- private void processLdapGroupSyncToLDAP(GroupModel kcGroup, Map<String, LDAPObject> ldapGroupsMap, Set<String> ldapGroupNames, SynchronizationResult syncResult) {
+ private void processKeycloakGroupSyncToLDAP(GroupModel kcGroup, Map<String, LDAPObject> ldapGroupsMap, Set<String> ldapGroupNames, SynchronizationResult syncResult) {
String groupName = kcGroup.getName();
// extract group attributes to be updated to LDAP
@@ -449,12 +449,12 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
// process KC subgroups
for (GroupModel kcSubgroup : kcGroup.getSubGroups()) {
- processLdapGroupSyncToLDAP(kcSubgroup, ldapGroupsMap, ldapGroupNames, syncResult);
+ processKeycloakGroupSyncToLDAP(kcSubgroup, ldapGroupsMap, ldapGroupNames, syncResult);
}
}
- // Sync memberships update. Update memberships of group in LDAP based on subgroups from KC. Do it recursively
- private void processLdapGroupMembershipsSyncToLDAP(GroupModel kcGroup, Map<String, LDAPObject> ldapGroupsMap) {
+ // Update memberships of group in LDAP based on subgroups from KC. Do it recursively
+ private void processKeycloakGroupMembershipsSyncToLDAP(GroupModel kcGroup, Map<String, LDAPObject> ldapGroupsMap) {
LDAPObject ldapGroup = ldapGroupsMap.get(kcGroup.getName());
Set<LDAPDn> toRemoveSubgroupsDNs = getLDAPSubgroups(ldapGroup);
@@ -481,7 +481,25 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
}
for (GroupModel kcSubgroup : kcGroup.getSubGroups()) {
- processLdapGroupMembershipsSyncToLDAP(kcSubgroup, ldapGroupsMap);
+ processKeycloakGroupMembershipsSyncToLDAP(kcSubgroup, ldapGroupsMap);
+ }
+ }
+
+ // Recursively check if parent group exists in LDAP. If yes, then return current group. If not, then recursively call this method
+ // for the predecessor. Result is the highest group, which doesn't yet exists in LDAP (and hence requires sync to LDAP)
+ private GroupModel getHighestPredecessorNotExistentInLdap(GroupModel group) {
+ GroupModel parentGroup = group.getParent();
+ if (parentGroup == null) {
+ return group;
+ }
+
+ LDAPObject ldapGroup = loadLDAPGroupByName(parentGroup.getName());
+ if (ldapGroup != null) {
+ // Parent exists in LDAP. Let's return current group
+ return group;
+ } else {
+ // Parent doesn't exists in LDAP. Let's recursively go up.
+ return getHighestPredecessorNotExistentInLdap(parentGroup);
}
}
@@ -500,11 +518,34 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
return membershipType.getGroupMembers(realm, this, ldapGroup, firstResult, maxResults);
}
- public void addGroupMappingInLDAP(RealmModel realm, String groupName, LDAPObject ldapUser) {
+ public void addGroupMappingInLDAP(RealmModel realm, GroupModel kcGroup, LDAPObject ldapUser) {
+ String groupName = kcGroup.getName();
LDAPObject ldapGroup = loadLDAPGroupByName(groupName);
+
if (ldapGroup == null) {
- syncDataFromKeycloakToFederationProvider(realm);
- ldapGroup = loadLDAPGroupByName(groupName);
+ // Needs to partially sync Keycloak groups to LDAP
+ if (config.isPreserveGroupsInheritance()) {
+ GroupModel highestGroupToSync = getHighestPredecessorNotExistentInLdap(kcGroup);
+
+ logger.debugf("Will sync group '%s' and it's subgroups from DB to LDAP", highestGroupToSync.getName());
+
+ Map<String, LDAPObject> syncedLDAPGroups = new HashMap<>();
+ processKeycloakGroupSyncToLDAP(highestGroupToSync, syncedLDAPGroups, new HashSet<>(), new SynchronizationResult());
+ processKeycloakGroupMembershipsSyncToLDAP(highestGroupToSync, syncedLDAPGroups);
+
+ ldapGroup = loadLDAPGroupByName(groupName);
+
+ // Finally update LDAP membership in the parent group
+ if (highestGroupToSync.getParent() != null) {
+ LDAPObject ldapParentGroup = loadLDAPGroupByName(highestGroupToSync.getParent().getName());
+ LDAPUtils.addMember(ldapProvider, MembershipType.DN, config.getMembershipLdapAttribute(), getMembershipUserLdapAttribute(), ldapParentGroup, ldapGroup, true);
+ }
+ } else {
+ // No care about group inheritance. Let's just sync current group
+ logger.debugf("Will sync group '%s' from DB to LDAP", groupName);
+ processKeycloakGroupSyncToLDAP(kcGroup, new HashMap<>(), new HashSet<>(), new SynchronizationResult());
+ ldapGroup = loadLDAPGroupByName(groupName);
+ }
}
String membershipUserLdapAttrName = getMembershipUserLdapAttribute();
@@ -614,7 +655,7 @@ public class GroupLDAPStorageMapper extends AbstractLDAPStorageMapper implements
if (config.getMode() == LDAPGroupMapperMode.LDAP_ONLY) {
// We need to create new role mappings in LDAP
cachedLDAPGroupMappings = null;
- addGroupMappingInLDAP(realm, group.getName(), ldapUser);
+ addGroupMappingInLDAP(realm, group, ldapUser);
} else {
super.joinGroup(group);
}
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperSyncTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperSyncTest.java
index 746b302..51f8fdd 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperSyncTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperSyncTest.java
@@ -317,7 +317,11 @@ public class LDAPGroupMapperSyncTest {
LDAPTestUtils.removeAllLDAPUsers(ldapProvider, realm);
LDAPObject johnLdap = LDAPTestUtils.addLDAPUser(ldapProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234");
LDAPTestUtils.updateLDAPPassword(ldapProvider, johnLdap, "Password1");
- groupMapper.addGroupMappingInLDAP(realm, "group11", johnLdap);
+
+ GroupMapperConfig groupMapperConfig = new GroupMapperConfig(mapperModel);
+ LDAPObject ldapGroup = groupMapper.loadLDAPGroupByName("group11");
+ LDAPUtils.addMember(ldapProvider, groupMapperConfig.getMembershipTypeLdapAttribute(), groupMapperConfig.getMembershipLdapAttribute(),
+ groupMapperConfig.getMembershipUserLdapAttribute(ldapProvider.getLdapIdentityStore().getConfig()), ldapGroup, johnLdap, true);
// Assert groups not yet imported to Keycloak DB
Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group1"));
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperTest.java
index 7380ba7..b7c9742 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPGroupMapperTest.java
@@ -243,8 +243,8 @@ public class LDAPGroupMapperTest {
GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ldapProvider, appRealm);
LDAPObject maryLdap = ldapProvider.loadLDAPUserByUsername(appRealm, "marykeycloak");
- groupMapper.addGroupMappingInLDAP(appRealm, "group1", maryLdap);
- groupMapper.addGroupMappingInLDAP(appRealm, "group11", maryLdap);
+ groupMapper.addGroupMappingInLDAP(appRealm, group1, maryLdap);
+ groupMapper.addGroupMappingInLDAP(appRealm, group11, maryLdap);
// Add some group mapping to model
mary.joinGroup(group12);
@@ -304,18 +304,18 @@ public class LDAPGroupMapperTest {
LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ldapProvider, appRealm);
+ GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
+ GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
+ GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
+
LDAPObject robLdap = ldapProvider.loadLDAPUserByUsername(appRealm, "robkeycloak");
- groupMapper.addGroupMappingInLDAP(appRealm, "group11", robLdap);
- groupMapper.addGroupMappingInLDAP(appRealm, "group12", robLdap);
+ groupMapper.addGroupMappingInLDAP(appRealm, group11, robLdap);
+ groupMapper.addGroupMappingInLDAP(appRealm, group12, robLdap);
// Get user and check that he has requested groupa from LDAP
UserModel rob = session.users().getUserByUsername("robkeycloak", appRealm);
Set<GroupModel> robGroups = rob.getGroups();
- GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
- GroupModel group11 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11");
- GroupModel group12 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group12");
-
Assert.assertFalse(robGroups.contains(group1));
Assert.assertTrue(robGroups.contains(group11));
Assert.assertTrue(robGroups.contains(group12));
@@ -450,6 +450,79 @@ public class LDAPGroupMapperTest {
}
+ // KEYCLOAK-5017
+ @Test
+ public void test06_addingUserToNewKeycloakGroup() throws Exception {
+ // Add some groups to Keycloak
+ KeycloakSession session = keycloakRule.startSession();
+ try {
+ RealmModel appRealm = session.realms().getRealmByName("test");
+
+ GroupModel group3 = appRealm.createGroup("group3");
+ session.realms().addTopLevelGroup(appRealm, group3);
+ GroupModel group31 = appRealm.createGroup("group31");
+ group3.addChild(group31);
+ GroupModel group32 = appRealm.createGroup("group32");
+ group3.addChild(group32);
+
+ GroupModel group4 = appRealm.createGroup("group4");
+ session.realms().addTopLevelGroup(appRealm, group4);
+
+ GroupModel group14 = appRealm.createGroup("group14");
+ GroupModel group1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
+ group1.addChild(group14);
+
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+
+ // Add user to some newly created KC groups
+ session = keycloakRule.startSession();
+ try {
+ RealmModel appRealm = session.realms().getRealmByName("test");
+
+ UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
+
+ GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
+ john.joinGroup(group4);
+
+ GroupModel group31 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3/group31");
+ GroupModel group32 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3/group32");
+
+ john.joinGroup(group31);
+ john.joinGroup(group32);
+
+ GroupModel group14 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group14");
+ john.joinGroup(group14);
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+
+ // Check user group memberships
+ session = keycloakRule.startSession();
+ try {
+ RealmModel appRealm = session.realms().getRealmByName("test");
+
+ UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
+
+ GroupModel group14 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group14");
+ GroupModel group3 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3");
+ GroupModel group31 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3/group31");
+ GroupModel group32 = KeycloakModelUtils.findGroupByPath(appRealm, "/group3/group32");
+ GroupModel group4 = KeycloakModelUtils.findGroupByPath(appRealm, "/group4");
+
+ Set<GroupModel> groups = john.getGroups();
+ Assert.assertTrue(groups.contains(group14));
+ Assert.assertFalse(groups.contains(group3));
+ Assert.assertTrue(groups.contains(group31));
+ Assert.assertTrue(groups.contains(group32));
+ Assert.assertTrue(groups.contains(group4));
+ } finally {
+ keycloakRule.stopSession(session, true);
+ }
+ }
+
+
private void deleteGroupMappingsInLDAP(GroupLDAPStorageMapper groupMapper, LDAPObject ldapUser, String groupName) {
LDAPObject ldapGroup = groupMapper.loadLDAPGroupByName(groupName);
groupMapper.deleteGroupMappingInLDAP(ldapUser, ldapGroup);
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPGroupMapperNoImportTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPGroupMapperNoImportTest.java
index 6cf6435..38ae0da 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPGroupMapperNoImportTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPGroupMapperNoImportTest.java
@@ -167,8 +167,8 @@ public class LDAPGroupMapperNoImportTest {
GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ldapProvider, appRealm);
LDAPObject maryLdap = ldapProvider.loadLDAPUserByUsername(appRealm, "marykeycloak");
- groupMapper.addGroupMappingInLDAP(appRealm, "group1", maryLdap);
- groupMapper.addGroupMappingInLDAP(appRealm, "group11", maryLdap);
+ groupMapper.addGroupMappingInLDAP(appRealm, KeycloakModelUtils.findGroupByPath(appRealm, "/group1"), maryLdap);
+ groupMapper.addGroupMappingInLDAP(appRealm, KeycloakModelUtils.findGroupByPath(appRealm, "/group1/group11"), maryLdap);
} finally {
keycloakRule.stopSession(session, true);
}
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/LdapManyGroupsInitializerCommand.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/LdapManyGroupsInitializerCommand.java
new file mode 100644
index 0000000..26c778c
--- /dev/null
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/LdapManyGroupsInitializerCommand.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017 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.util.cli;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.ldap.LDAPStorageProvider;
+import org.keycloak.storage.ldap.idm.model.LDAPObject;
+import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
+import org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapper;
+
+/**
+ * The command requires that:
+ * - Realm has 1 LDAP storage provider defined
+ * - The LDAP provider has group-mapper named "groupsMapper", with:
+ * -- "LDAP Groups DN" pointing to same DN, like this command <groups-dn> .
+ * -- It's supposed to PreserveGroupsInheritance on
+ *
+ * It will create top-groups-count "root" groups and "subgroups-in-every-top-group" groups in every child.
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class LdapManyGroupsInitializerCommand extends AbstractCommand {
+
+ @Override
+ public String getName() {
+ return "createLdapGroups";
+ }
+
+ @Override
+ public String printUsage() {
+ return super.printUsage() + " <realm-name> <groups-dn> <start-offset-top-groups> <top-groups-count> <subgroups-in-every-top-group>.\nSee javadoc of class LdapManyGroupsInitializerCommand for additional details.";
+ }
+
+ @Override
+ protected void doRunCommand(KeycloakSession session) {
+ String realmName = getArg(0);
+ String groupsDn = getArg(1);
+ int startOffsetTopGroups = getIntArg(2);
+ int topGroupsCount = getIntArg(3);
+ int subgroupsInEveryGroup = getIntArg(4);
+
+ RealmModel realm = session.realms().getRealmByName(realmName);
+ List<ComponentModel> components = realm.getComponents(realm.getId(), UserStorageProvider.class.getName());
+ if (components.size() != 1) {
+ log.errorf("Expected 1 LDAP Provider, but found: %d providers", components.size());
+ throw new HandledException();
+ }
+ ComponentModel ldapModel = components.get(0);
+
+ // Check that street mapper exists. It's required for now, so that "street" attribute is written to the LDAP
+ ComponentModel groupMapperModel = getMapperModel(realm, ldapModel, "groupsMapper");
+
+
+ // Create groups
+ for (int i=startOffsetTopGroups ; i<startOffsetTopGroups+topGroupsCount ; i++) {
+ final int iFinal = i;
+ KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession kcSession) -> {
+
+ LDAPStorageProvider ldapProvider = (LDAPStorageProvider)session.getProvider(UserStorageProvider.class, ldapModel);
+ RealmModel appRealm = session.realms().getRealmByName(realmName);
+ GroupLDAPStorageMapper groupMapper = (GroupLDAPStorageMapper) session.getProvider(LDAPStorageMapper.class, groupMapperModel);
+
+ Set<String> childGroupDns = new HashSet<>();
+
+ for (int j=0 ; j<subgroupsInEveryGroup ; j++) {
+ String groupName = "group-" + iFinal + "-" + j;
+ LDAPObject createdGroup = groupMapper.createLDAPGroup(groupName, new HashMap<>());
+ childGroupDns.add(createdGroup.getDn().toString());
+ }
+
+ String topGroupName = "group-" + iFinal;
+
+ Map<String, Set<String>> groupAttrs = new HashMap<>();
+ groupAttrs.put("member", new HashSet<>(childGroupDns));
+
+ groupMapper.createLDAPGroup(topGroupName, groupAttrs);
+
+ });
+ }
+ }
+
+
+ private ComponentModel getMapperModel(RealmModel realm, ComponentModel ldapModel, String mapperName) {
+ List<ComponentModel> ldapMappers = realm.getComponents(ldapModel.getId(), LDAPStorageMapper.class.getName());
+ Optional<ComponentModel> optional = ldapMappers.stream().filter((ComponentModel mapper) -> {
+ return mapper.getName().equals(mapperName);
+ }).findFirst();
+
+ if (!optional.isPresent()) {
+ log.errorf("Not present LDAP mapper called '%s'", mapperName);
+ throw new HandledException();
+ }
+
+ return optional.get();
+ }
+}
diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/TestsuiteCLI.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/TestsuiteCLI.java
index 9da8a84..751e397 100644
--- a/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/TestsuiteCLI.java
+++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/util/cli/TestsuiteCLI.java
@@ -66,7 +66,8 @@ public class TestsuiteCLI {
CacheCommands.GetCacheCommand.class,
CacheCommands.CacheRealmObjectsCommand.class,
ClusterProviderTaskCommand.class,
- LdapManyObjectsInitializerCommand.class
+ LdapManyObjectsInitializerCommand.class,
+ LdapManyGroupsInitializerCommand.class
};
private final KeycloakSessionFactory sessionFactory;