/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/
package org.olat.basesecurity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.persistence.EntityNotFoundException;
import javax.persistence.LockModeType;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.olat.admin.quota.GenericQuotaEditController;
import org.olat.admin.sysinfo.SysinfoController;
import org.olat.admin.user.UserAdminController;
import org.olat.admin.user.UserChangePasswordController;
import org.olat.admin.user.UserCreateController;
import org.olat.basesecurity.events.NewIdentityCreatedEvent;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.commons.persistence.DBQuery;
import org.olat.core.commons.persistence.PersistenceHelper;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.id.ModifiedInfo;
import org.olat.core.id.OLATResourceable;
import org.olat.core.id.Roles;
import org.olat.core.id.User;
import org.olat.core.id.UserConstants;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.Encoder;
import org.olat.core.util.Encoder.Algorithm;
import org.olat.core.util.Util;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.SyncerCallback;
import org.olat.core.util.resource.OresHelper;
import org.olat.login.LoginModule;
import org.olat.portfolio.manager.InvitationDAO;
import org.olat.resource.OLATResource;
import org.olat.resource.OLATResourceManager;
import org.olat.user.ChangePasswordController;
import org.olat.user.UserImpl;
import org.olat.user.UserManager;
/**
* <h3>Description:</h3>
* The PersistingManager implements the security manager and provide methods to
* manage identities and user objects based on a database persistence mechanism
* using hibernate.
* <p>
*
* @author Felix Jost, Florian Gnaegi
*/
public class BaseSecurityManager implements BaseSecurity {
private static final OLog log = Tracing.createLoggerFor(BaseSecurityManager.class);
private DB dbInstance;
private LoginModule loginModule;
private OLATResourceManager orm;
private InvitationDAO invitationDao;
private String dbVendor = "";
private static BaseSecurityManager INSTANCE;
private static String GUEST_USERNAME_PREFIX = "guest_";
public static final OLATResourceable IDENTITY_EVENT_CHANNEL = OresHelper.lookupType(Identity.class);
/**
* [used by spring]
*/
private BaseSecurityManager() {
INSTANCE = this;
}
/**
*
* @return the manager
*/
public static BaseSecurity getInstance() {
return INSTANCE;
}
public void setLoginModule(LoginModule loginModule) {
this.loginModule = loginModule;
}
/**
* [used by spring]
* @param orm
*/
public void setResourceManager(OLATResourceManager orm) {
this.orm = orm;
}
/**
* [used by Spring]
* @param dbInstance
*/
public void setDbInstance(DB dbInstance) {
this.dbInstance = dbInstance;
}
/**
* [used by Spring]
* @param invitationDao
*/
public void setInvitationDao(InvitationDAO invitationDao) {
this.invitationDao = invitationDao;
}
/**
* @see org.olat.basesecurity.Manager#init()
*/
public void init() { // called only once at startup and only from one thread
// init the system level groups and its policies
initSysGroupAdmin();
dbInstance.commit();
initSysGroupAuthors();
dbInstance.commit();
initSysGroupGroupmanagers();
dbInstance.commit();
initSysGroupPoolsmanagers();
dbInstance.commit();
initSysGroupUsermanagers();
dbInstance.commit();
initSysGroupUsers();
dbInstance.commit();
initSysGroupAnonymous();
dbInstance.commit();
initSysGroupInstitutionalResourceManager();
dbInstance.commitAndCloseSession();
}
/**
* OLAT system administrators, root, good, whatever you name it...
*/
private void initSysGroupAdmin() {
SecurityGroup adminGroup = findSecurityGroupByName(Constants.GROUP_ADMIN);
if (adminGroup == null)
adminGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_ADMIN);
// we check everthing by policies, so we must give admins the hasRole
// permission on the type resource "Admin"
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_ADMIN);
//admins have role "authors" by default
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
//admins have a groupmanager policy and access permissions to groupmanaging tools
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GROUPMANAGER);
//admins have a usemanager policy and access permissions to usermanagement tools
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_USERMANAGER);
//admins are also regular users
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_USERS);
//olat admins have access to all security groups
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ACCESS, Constants.ORESOURCE_SECURITYGROUPS);
// and to all courses
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ADMIN, Constants.ORESOURCE_COURSES);
// and to pool admiistration
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ADMIN, Constants.ORESOURCE_POOLS);
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(SysinfoController.class));
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(UserAdminController.class));
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(UserChangePasswordController.class));
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(UserCreateController.class));
createAndPersistPolicyIfNotExists(adminGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(GenericQuotaEditController.class));
}
/**
* Every active user that is an active user is in the user group. exceptions: logonDenied and anonymous users
*/
private void initSysGroupUsers() {
SecurityGroup olatuserGroup = findSecurityGroupByName(Constants.GROUP_OLATUSERS);
if (olatuserGroup == null)
olatuserGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_OLATUSERS);
//users have a user policy
createAndPersistPolicyIfNotExists(olatuserGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_USERS);
createAndPersistPolicyIfNotExists(olatuserGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(ChangePasswordController.class));
}
/**
* Users with access to group context management (groupmanagement that can be used in multiple courses
*/
private void initSysGroupGroupmanagers() {
SecurityGroup olatGroupmanagerGroup = findSecurityGroupByName(Constants.GROUP_GROUPMANAGERS);
if (olatGroupmanagerGroup == null)
olatGroupmanagerGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_GROUPMANAGERS);
//gropumanagers have a groupmanager policy and access permissions to groupmanaging tools
createAndPersistPolicyIfNotExists(olatGroupmanagerGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GROUPMANAGER);
}
/**
* Users with access to group context management (groupmanagement that can be used in multiple courses
*/
private void initSysGroupPoolsmanagers() {
SecurityGroup secGroup = findSecurityGroupByName(Constants.GROUP_POOL_MANAGER);
if (secGroup == null)
secGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_POOL_MANAGER);
//pools managers have a goupmanager policy and access permissions to groupmanaging tools
createAndPersistPolicyIfNotExists(secGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_POOLS);
}
/**
* Users with access to user management
*/
private void initSysGroupUsermanagers() {
SecurityGroup olatUsermanagerGroup = findSecurityGroupByName(Constants.GROUP_USERMANAGERS);
if (olatUsermanagerGroup == null)
olatUsermanagerGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_USERMANAGERS);
//gropumanagers have a groupmanager policy and access permissions to groupmanaging tools
createAndPersistPolicyIfNotExists(olatUsermanagerGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_USERMANAGER);
createAndPersistPolicyIfNotExists(olatUsermanagerGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(UserAdminController.class));
createAndPersistPolicyIfNotExists(olatUsermanagerGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(UserChangePasswordController.class));
createAndPersistPolicyIfNotExists(olatUsermanagerGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(UserCreateController.class));
createAndPersistPolicyIfNotExists(olatUsermanagerGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(GenericQuotaEditController.class));
}
/**
* Users with access to the authoring parts of the learning ressources repository
*/
private void initSysGroupAuthors() {
SecurityGroup olatauthorGroup = findSecurityGroupByName(Constants.GROUP_AUTHORS);
if (olatauthorGroup == null)
olatauthorGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_AUTHORS);
//authors have a author policy and access permissions to authoring tools
createAndPersistPolicyIfNotExists(olatauthorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
}
/**
* Users with access to the authoring parts of the learning ressources repository (all resources in his university)
*/
private void initSysGroupInstitutionalResourceManager() {
SecurityGroup institutionalResourceManagerGroup = findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER);
if (institutionalResourceManagerGroup == null)
institutionalResourceManagerGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_INST_ORES_MANAGER);
//manager have a author policy and access permissions to authoring tools
createAndPersistPolicyIfNotExists(institutionalResourceManagerGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_INSTORESMANAGER);
createAndPersistPolicyIfNotExists(institutionalResourceManagerGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(GenericQuotaEditController.class));
}
/**
* Unknown users with guest only rights
*/
private void initSysGroupAnonymous() {
SecurityGroup guestGroup = findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
if (guestGroup == null)
guestGroup = createAndPersistNamedSecurityGroup(Constants.GROUP_ANONYMOUS);
//guest(=anonymous) have a guest policy
createAndPersistPolicyIfNotExists(guestGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY);
}
/**
* @see org.olat.basesecurity.Manager#getPoliciesOfSecurityGroup(org.olat.basesecurity.SecurityGroup)
*/
@Override
public List<Policy> getPoliciesOfSecurityGroup(SecurityGroup secGroup) {
if(secGroup == null ) return Collections.emptyList();
StringBuilder sb = new StringBuilder();
sb.append("select poi from ").append(PolicyImpl.class.getName()).append(" as poi where poi.securityGroup.key=:secGroupKey");
List<Policy> policies = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Policy.class)
.setParameter("secGroupKey", secGroup.getKey())
.getResultList();
return policies;
}
/**
* @see org.olat.basesecurity.BaseSecurity#getPoliciesOfResource(org.olat.core.id.OLATResourceable)
*/
@Override
public List<Policy> getPoliciesOfResource(OLATResource resource, SecurityGroup secGroup) {
StringBuilder sb = new StringBuilder();
sb.append("select poi from ").append(PolicyImpl.class.getName()).append(" poi where ")
.append(" poi.olatResource.key=:resourceKey ");
if(secGroup != null) {
sb.append(" and poi.securityGroup.key=:secGroupKey");
}
TypedQuery<Policy> query = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Policy.class)
.setParameter("resourceKey", resource.getKey());
if(secGroup != null) {
query.setParameter("secGroupKey", secGroup.getKey());
}
return query.getResultList();
}
@Override
public boolean isIdentityPermittedOnResourceable(Identity identity, String permission, OLATResourceable olatResourceable) {
return isIdentityPermittedOnResourceable(identity, permission, olatResourceable, true);
}
/**
* @see org.olat.basesecurity.Manager#isIdentityPermittedOnResourceable(org.olat.core.id.Identity, java.lang.String, org.olat.core.id.OLATResourceable boolean)
*/
@Override
public boolean isIdentityPermittedOnResourceable(Identity identity, String permission, OLATResourceable olatResourceable, boolean checkTypeRight) {
if(identity == null || identity.getKey() == null) return false;//no identity, no permission
Long oresid = olatResourceable.getResourceableId();
if (oresid == null) oresid = new Long(0); //TODO: make a method in
// OLATResorceManager, since this
// is implementation detail
String oresName = olatResourceable.getResourceableTypeName();
// if the olatResourceable is not persisted as OLATResource, then the answer
// is false,
// therefore we can use the query assuming there is an OLATResource
TypedQuery<Number> query;
if(checkTypeRight) {
query = DBFactory.getInstance().getCurrentEntityManager().createNamedQuery("isIdentityPermittedOnResourceableCheckType", Number.class);
} else {
query = DBFactory.getInstance().getCurrentEntityManager().createNamedQuery("isIdentityPermittedOnResourceable", Number.class);
}
Number count = query.setParameter("identitykey", identity.getKey())
.setParameter("permission", permission)
.setParameter("resid", oresid)
.setParameter("resname", oresName)
.setHint("org.hibernate.cacheable", Boolean.TRUE)
.getSingleResult();
return count.longValue() > 0;
}
/**
* @see org.olat.basesecurity.Manager#getRoles(org.olat.core.id.Identity)
*/
@Override
public Roles getRoles(Identity identity) {
boolean isGuestOnly = false;
boolean isInvitee = false;
List<String> rolesStr = getRolesAsString(identity);
boolean admin = rolesStr.contains(Constants.GROUP_ADMIN);
boolean author = admin || rolesStr.contains(Constants.GROUP_AUTHORS);
boolean groupManager = admin || rolesStr.contains(Constants.GROUP_GROUPMANAGERS);
boolean userManager = admin || rolesStr.contains(Constants.GROUP_USERMANAGERS);
boolean resourceManager = rolesStr.contains(Constants.GROUP_INST_ORES_MANAGER);
boolean poolManager = admin || rolesStr.contains(Constants.GROUP_POOL_MANAGER);
if(!rolesStr.contains(Constants.GROUP_OLATUSERS)) {
isInvitee = invitationDao.isInvitee(identity);
isGuestOnly = isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY);
}
return new Roles(admin, userManager, groupManager, author, isGuestOnly, resourceManager, poolManager, isInvitee);
}
@Override
public List<String> getRolesAsString(Identity identity) {
StringBuilder sb = new StringBuilder();
sb.append("select ngroup.groupName from ").append(NamedGroupImpl.class.getName()).append(" as ngroup ")
.append(" where exists (")
.append(" select sgmsi from ").append(SecurityGroupMembershipImpl.class.getName())
.append(" as sgmsi where sgmsi.identity.key=:identityKey and sgmsi.securityGroup=ngroup.securityGroup")
.append(" )");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), String.class)
.setParameter("identityKey", identity.getKey())
.getResultList();
}
@Override
public void updateRoles(Identity actingIdentity, Identity updatedIdentity, Roles roles) {
SecurityGroup anonymousGroup = findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
boolean hasBeenAnonymous = isIdentityInSecurityGroup(updatedIdentity, anonymousGroup);
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, anonymousGroup, hasBeenAnonymous, roles.isGuestOnly(), Constants.GROUP_ANONYMOUS);
// system users - opposite of anonymous users
SecurityGroup usersGroup = findSecurityGroupByName(Constants.GROUP_OLATUSERS);
boolean hasBeenUser = isIdentityInSecurityGroup(updatedIdentity, usersGroup);
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, usersGroup, hasBeenUser, !roles.isGuestOnly(), Constants.GROUP_OLATUSERS);
SecurityGroup groupManagerGroup = findSecurityGroupByName(Constants.GROUP_GROUPMANAGERS);
boolean hasBeenGroupManager = isIdentityInSecurityGroup(updatedIdentity, groupManagerGroup);
boolean groupManager = roles.isGroupManager()
&& !roles.isGuestOnly() && !roles.isInvitee();
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, groupManagerGroup, hasBeenGroupManager, groupManager, Constants.GROUP_GROUPMANAGERS);
// author
SecurityGroup authorGroup = findSecurityGroupByName(Constants.GROUP_AUTHORS);
boolean hasBeenAuthor = isIdentityInSecurityGroup(updatedIdentity, authorGroup);
boolean isAuthor = (roles.isAuthor() || roles.isInstitutionalResourceManager())
&& !roles.isGuestOnly() && !roles.isInvitee();
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, authorGroup, hasBeenAuthor, isAuthor, Constants.GROUP_AUTHORS);
// user manager, only allowed by admin
SecurityGroup userManagerGroup = findSecurityGroupByName(Constants.GROUP_USERMANAGERS);
boolean hasBeenUserManager = isIdentityInSecurityGroup(updatedIdentity, userManagerGroup);
boolean userManager = roles.isUserManager()
&& !roles.isGuestOnly() && !roles.isInvitee();
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, userManagerGroup, hasBeenUserManager, userManager, Constants.GROUP_USERMANAGERS);
// institutional resource manager
SecurityGroup institutionalResourceManagerGroup = findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER);
boolean hasBeenInstitutionalResourceManager = isIdentityInSecurityGroup(updatedIdentity, institutionalResourceManagerGroup);
boolean institutionalResourceManager = roles.isInstitutionalResourceManager()
&& !roles.isGuestOnly() && !roles.isInvitee();
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, institutionalResourceManagerGroup, hasBeenInstitutionalResourceManager, institutionalResourceManager, Constants.GROUP_INST_ORES_MANAGER);
// institutional resource manager
SecurityGroup poolManagerGroup = findSecurityGroupByName(Constants.GROUP_POOL_MANAGER);
boolean hasBeenPoolManager = isIdentityInSecurityGroup(updatedIdentity, poolManagerGroup);
boolean poolManager = roles.isPoolAdmin() && !roles.isGuestOnly() && !roles.isInvitee();
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, poolManagerGroup, hasBeenPoolManager, poolManager, Constants.GROUP_POOL_MANAGER);
// system administrator
SecurityGroup adminGroup = findSecurityGroupByName(Constants.GROUP_ADMIN);
boolean hasBeenAdmin = isIdentityInSecurityGroup(updatedIdentity, adminGroup);
boolean isOLATAdmin = roles.isOLATAdmin() && !roles.isGuestOnly() && !roles.isInvitee();
updateRolesInSecurityGroup(actingIdentity, updatedIdentity, adminGroup, hasBeenAdmin, isOLATAdmin, Constants.GROUP_ADMIN);
}
private void updateRolesInSecurityGroup(Identity actingIdentity, Identity updatedIdentity, SecurityGroup securityGroup, boolean hasBeenInGroup, boolean isNowInGroup, String groupName) {
if (!hasBeenInGroup && isNowInGroup) {
// user not yet in security group, add him
addIdentityToSecurityGroup(updatedIdentity, securityGroup);
log.audit("User::" + (actingIdentity == null ? "unkown" : actingIdentity.getName()) + " added system role::" + groupName + " to user::" + updatedIdentity.getName(), null);
} else if (hasBeenInGroup && !isNowInGroup) {
// user not anymore in security group, remove him
removeIdentityFromSecurityGroup(updatedIdentity, securityGroup);
log.audit("User::" + (actingIdentity == null ? "unkown" : actingIdentity.getName()) + " removed system role::" + groupName + " from user::" + updatedIdentity.getName(), null);
}
}
/**
* scalar query : select sgi, poi, ori
* @param identity
* @return List of policies
*/
@Override
public List<Policy> getPoliciesOfIdentity(Identity identity) {
StringBuilder sb = new StringBuilder();
sb.append("select poi from ").append(PolicyImpl.class.getName()).append(" as poi ")
.append("inner join fetch poi.securityGroup as secGroup ")
.append("inner join fetch poi.olatResource as resource ")
.append("where secGroup in (select sgmi.securityGroup from ")
.append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmi where sgmi.identity.key=:identityKey)");
return DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Policy.class)
.setParameter("identityKey", identity.getKey())
.getResultList();
}
/**
* @see org.olat.basesecurity.Manager#isIdentityInSecurityGroup(org.olat.core.id.Identity, org.olat.basesecurity.SecurityGroup)
*/
public boolean isIdentityInSecurityGroup(Identity identity, SecurityGroup secGroup) {
if (secGroup == null || identity == null) return false;
String queryString = "select count(sgmsi) from org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi where sgmsi.identity = :identitykey and sgmsi.securityGroup = :securityGroup";
DBQuery query = DBFactory.getInstance().createQuery(queryString);
query.setLong("identitykey", identity.getKey());
query.setLong("securityGroup", secGroup.getKey());
query.setCacheable(true);
List res = query.list();
Long cntL = (Long) res.get(0);
if (cntL.longValue() != 0 && cntL.longValue() != 1) throw new AssertException("unique n-to-n must always yield 0 or 1");
return (cntL.longValue() == 1);
}
@Override
public void touchMembership(Identity identity, List<SecurityGroup> secGroups) {
if (secGroups == null || secGroups.isEmpty()) return;
StringBuilder sb = new StringBuilder();
sb.append("select sgmsi from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
.append("where sgmsi.identity.key=:identityKey and sgmsi.securityGroup in (:securityGroups)");
List<ModifiedInfo> infos = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), ModifiedInfo.class)
.setParameter("identityKey", identity.getKey())
.setParameter("securityGroups", secGroups)
.getResultList();
for(ModifiedInfo info:infos) {
info.setLastModified(new Date());
DBFactory.getInstance().getCurrentEntityManager().merge(info);
}
}
/**
* @see org.olat.basesecurity.Manager#createAndPersistSecurityGroup()
*/
public SecurityGroup createAndPersistSecurityGroup() {
SecurityGroupImpl sgi = new SecurityGroupImpl();
DBFactory.getInstance().saveObject(sgi);
return sgi;
}
/**
* @see org.olat.basesecurity.Manager#deleteSecurityGroup(org.olat.basesecurity.SecurityGroup)
*/
public void deleteSecurityGroup(SecurityGroup secGroup) {
// we do not use hibernate cascade="delete", but implement our own (to be
// sure to understand our code)
DB db = DBFactory.getInstance();
//FIXME: fj: Please review: Create rep entry, restart olat, delete the rep
// entry. previous implementation resulted in orange screen
// secGroup = (SecurityGroup)db.loadObject(secGroup); // so we can later
// delete it (hibernate needs an associated session)
secGroup = (SecurityGroup) db.loadObject(secGroup);
//o_clusterREVIEW
//db.reputInHibernateSessionCache(secGroup);
/*
* if (!db.contains(secGroup)) { secGroup = (SecurityGroupImpl)
* db.loadObject(SecurityGroupImpl.class, secGroup.getKey()); }
*/
// 1) delete associated users (need to do it manually, hibernate knows
// nothing about
// the membership, modeled manually via many-to-one and not via set)
db.delete("from org.olat.basesecurity.SecurityGroupMembershipImpl as msi where msi.securityGroup.key = ?", new Object[] { secGroup
.getKey() }, new Type[] { StandardBasicTypes.LONG });
// 2) delete all policies
db.delete("from org.olat.basesecurity.PolicyImpl as poi where poi.securityGroup = ?", new Object[] { secGroup.getKey() },
new Type[] { StandardBasicTypes.LONG });
// 3) delete security group
db.deleteObject(secGroup);
}
/**
*
*
* @see org.olat.basesecurity.Manager#addIdentityToSecurityGroup(org.olat.core.id.Identity, org.olat.basesecurity.SecurityGroup)
*/
@Override
public void addIdentityToSecurityGroup(Identity identity, SecurityGroup secGroup) {
SecurityGroupMembershipImpl sgmsi = new SecurityGroupMembershipImpl();
sgmsi.setIdentity(identity);
sgmsi.setSecurityGroup(secGroup);
sgmsi.setLastModified(new Date());
dbInstance.getCurrentEntityManager().persist(sgmsi);
}
/**
* @see org.olat.basesecurity.Manager#removeIdentityFromSecurityGroup(org.olat.core.id.Identity, org.olat.basesecurity.SecurityGroup)
*/
@Override
public boolean removeIdentityFromSecurityGroup(Identity identity, SecurityGroup secGroup) {
return removeIdentityFromSecurityGroups(Collections.singletonList(identity), Collections.singletonList(secGroup));
}
@Override
public boolean removeIdentityFromSecurityGroups(List<Identity> identities, List<SecurityGroup> secGroups) {
if(identities == null || identities.isEmpty()) return true;//nothing to do
if(secGroups == null || secGroups.isEmpty()) return true;//nothing to do
StringBuilder sb = new StringBuilder();
sb.append("delete from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as msi ")
.append(" where msi.identity.key in (:identityKeys) and msi.securityGroup.key in (:secGroupKeys)");
List<Long> identityKeys = new ArrayList<Long>();
for(Identity identity:identities) {
identityKeys.add(identity.getKey());
}
List<Long> secGroupKeys = new ArrayList<Long>();
for(SecurityGroup secGroup:secGroups) {
secGroupKeys.add(secGroup.getKey());
}
int rowsAffected = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString())
.setParameter("identityKeys", identityKeys)
.setParameter("secGroupKeys", secGroupKeys)
.executeUpdate();
return rowsAffected > 0;
}
/**
* @see org.olat.basesecurity.Manager#createAndPersistPolicy(org.olat.basesecurity.SecurityGroup, java.lang.String, org.olat.core.id.OLATResourceable
*/
@Override
public Policy createAndPersistPolicy(SecurityGroup secGroup, String permission, OLATResourceable olatResourceable) {
OLATResource olatResource = orm.findOrPersistResourceable(olatResourceable);
return createAndPersistPolicyWithResource(secGroup, permission, null, null, olatResource);
}
/**
* Creates a policy and persists on the database
* @see org.olat.basesecurity.BaseSecurity#createAndPersistPolicyWithResource(org.olat.basesecurity.SecurityGroup, java.lang.String, java.util.Date, java.util.Date, org.olat.resource.OLATResource)
*/
private Policy createAndPersistPolicyWithResource(SecurityGroup secGroup, String permission, Date from, Date to, OLATResource olatResource) {
PolicyImpl pi = new PolicyImpl();
pi.setSecurityGroup(secGroup);
pi.setOlatResource(olatResource);
pi.setPermission(permission);
pi.setFrom(from);
pi.setTo(to);
DBFactory.getInstance().saveObject(pi);
return pi;
}
/**
* Helper method that only creates a policy only if no such policy exists in the database
* @param secGroup
* @param permission
* @param olatResourceable
* @return Policy
*/
private Policy createAndPersistPolicyIfNotExists(SecurityGroup secGroup, String permission, OLATResourceable olatResourceable) {
OLATResource olatResource = orm.findOrPersistResourceable(olatResourceable);
Policy existingPolicy = findPolicy(secGroup, permission, olatResource);
if (existingPolicy == null) {
return createAndPersistPolicy(secGroup, permission, olatResource);
}
return existingPolicy;
}
public Policy findPolicy(SecurityGroup secGroup, String permission, OLATResource olatResource) {
StringBuilder sb = new StringBuilder();
sb.append("select poi from ").append(PolicyImpl.class.getName()).append(" as poi ")
.append(" where poi.permission=:permission and poi.olatResource.key=:resourceKey and poi.securityGroup.key=:secGroupKey");
List<Policy> policies = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Policy.class)
.setParameter("permission", permission)
.setParameter("resourceKey", olatResource.getKey())
.setParameter("secGroupKey", secGroup.getKey())
.getResultList();
if (policies.isEmpty()) {
return null;
}
return policies.get(0);
}
@Override
public void deletePolicies(OLATResource resource) {
StringBuilder sb = new StringBuilder();
sb.append("delete from ").append(PolicyImpl.class.getName()).append(" as poi ")
.append(" where poi.olatResource.key=:resourceKey");
int rowDeleted = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString())
.setParameter("resourceKey", resource.getKey())
.executeUpdate();
if(log.isDebug()) {
log.debug(rowDeleted + " policies deleted");
}
}
/**
* @param username the username
* @param user The persisted user (mandatory)
* @param authusername the username used as authentication credential
* (=username for provider "OLAT")
* @param provider the provider of the authentication ("OLAT" or "AAI"). If null, no
* authentication token is generated.
* @param credential the credentials or null if not used
* @return Identity
*
@Override
public Identity createAndPersistIdentity(String username, User user, String provider, String authusername, String credential) {
IdentityImpl iimpl = new IdentityImpl(username, user);
dbInstance.getCurrentEntityManager().persist(iimpl);
((UserImpl)user).setIdentity(iimpl);
if (provider != null) {
createAndPersistAuthenticationIntern(iimpl, provider, authusername, credential, loginModule.getDefaultHashAlgorithm());
}
notifyNewIdentityCreated(iimpl);
return iimpl;
}*/
/**
* @param username The username
* @param user The unpresisted User
* @param provider The provider of the authentication ("OLAT" or "AAI"). If null, no authentication token is generated.
* @param authusername The username used as authentication credential (=username for provider "OLAT")
* @return Identity
*/
@Override
public Identity createAndPersistIdentityAndUser(String username, String externalId, User user, String provider, String authusername) {
return createAndPersistIdentityAndUser(username, externalId, user, provider, authusername, null);
}
/**
* @param username the username
* @param user the unpresisted User
* @param authusername the username used as authentication credential
* (=username for provider "OLAT")
* @param provider the provider of the authentication ("OLAT" or "AAI"). If null, no
* authentication token is generated.
* @param credential the credentials or null if not used
* @return Identity
*/
@Override
public Identity createAndPersistIdentityAndUser(String username, String externalId, User user, String provider, String authusername, String credential) {
IdentityImpl iimpl = new IdentityImpl();
iimpl.setUser(user);
iimpl.setName(username);
iimpl.setLastLogin(new Date());
iimpl.setExternalId(externalId);
iimpl.setStatus(Identity.STATUS_ACTIV);
((UserImpl)user).setIdentity(iimpl);
dbInstance.getCurrentEntityManager().persist(iimpl);
if (provider != null) {
createAndPersistAuthenticationIntern(iimpl, provider, authusername, credential, loginModule.getDefaultHashAlgorithm());
}
notifyNewIdentityCreated(iimpl);
return iimpl;
}
/**
* Persists the given user, creates an identity for it and adds the user to
* the users system group
*
* @param loginName
* @param externalId
* @param pwd null: no OLAT authentication is generated. If not null, the password will be
* encrypted and and an OLAT authentication is generated.
* @param newUser unpersisted users
* @return Identity
*/
@Override
public Identity createAndPersistIdentityAndUserWithDefaultProviderAndUserGroup(String loginName, String externalId, String pwd, User newUser) {
Identity ident = null;
if (pwd == null) {
// when no password is used the provider must be set to null to not generate
// an OLAT authentication token. See method doku.
ident = createAndPersistIdentityAndUser(loginName, externalId, newUser, null, null);
log.audit("Create an identity without authentication (login=" + loginName + ")");
} else {
ident = createAndPersistIdentityAndUser(loginName, externalId, newUser, BaseSecurityModule.getDefaultAuthProviderIdentifier(), loginName, pwd);
log.audit("Create an identity with " + BaseSecurityModule.getDefaultAuthProviderIdentifier() + " authentication (login=" + loginName + ")");
}
// Add user to system users group
SecurityGroup olatuserGroup = findSecurityGroupByName(Constants.GROUP_OLATUSERS);
addIdentityToSecurityGroup(ident, olatuserGroup);
return ident;
}
/**
* Persists the given user, creates an identity for it and adds the user to
* the users system group, create an authentication for an external provider
*
* @param loginName
* @param externalId
* @param provider
* @param authusername
* @param newUser
* @return
*/
@Override
public Identity createAndPersistIdentityAndUserWithUserGroup(String loginName, String externalId, String provider, String authusername, User newUser) {
Identity ident = createAndPersistIdentityAndUser(loginName, externalId, newUser, provider, authusername, null);
log.audit("Create an identity with " + provider + " authentication (login=" + loginName + ",authusername=" + authusername + ")");
// Add user to system users group
SecurityGroup olatuserGroup = findSecurityGroupByName(Constants.GROUP_OLATUSERS);
addIdentityToSecurityGroup(ident, olatuserGroup);
return ident;
}
private void notifyNewIdentityCreated(Identity newIdentity) {
//Save the identity on the DB. So can the listeners of the event retrieve it
//in cluster mode
DBFactory.getInstance().commit();
CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new NewIdentityCreatedEvent(newIdentity), IDENTITY_EVENT_CHANNEL);
}
/**
* @see org.olat.basesecurity.Manager#getIdentitiesOfSecurityGroup(org.olat.basesecurity.SecurityGroup)
*/
public List<Identity> getIdentitiesOfSecurityGroup(SecurityGroup secGroup) {
if (secGroup == null) {
throw new AssertException("getIdentitiesOfSecurityGroup: ERROR secGroup was null !!");
}
DB db = DBFactory.getInstance();
if (db == null) {
throw new AssertException("getIdentitiesOfSecurityGroup: ERROR db was null !!");
}
List<Identity> idents = getIdentitiesOfSecurityGroup(secGroup, 0, -1);
return idents;
}
@Override
public List<Identity> getIdentitiesOfSecurityGroup(SecurityGroup secGroup, int firstResult, int maxResults) {
if (secGroup == null) {
throw new AssertException("getIdentitiesOfSecurityGroup: ERROR secGroup was null !!");
}
StringBuilder sb = new StringBuilder();
sb.append("select identity from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
.append(" inner join sgmsi.identity identity ")
.append(" inner join fetch identity.user user ")
.append(" where sgmsi.securityGroup=:secGroup");
TypedQuery<Identity> query = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("secGroup", secGroup);
if(firstResult >= 0) {
query.setFirstResult(firstResult);
}
if(maxResults > 0) {
query.setMaxResults(maxResults);
}
return query.getResultList();
}
/**
* Return a list of unique identities which are in the list of security groups
* @see org.olat.basesecurity.BaseSecurity#getIdentitiesOfSecurityGroups(java.util.List)
*/
@Override
public List<Identity> getIdentitiesOfSecurityGroups(List<SecurityGroup> secGroups) {
if (secGroups == null || secGroups.isEmpty()) {
return Collections.emptyList();
}
StringBuilder sb = new StringBuilder();
sb.append("select distinct(identity) from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
.append(" inner join sgmsi.identity identity ")
.append(" inner join fetch identity.user user ")
.append(" where sgmsi.securityGroup in (:secGroups)");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("secGroups", secGroups)
.getResultList();
}
/**
* @see org.olat.basesecurity.Manager#getIdentitiesAndDateOfSecurityGroup(org.olat.basesecurity.SecurityGroup)
*/
@Override
public List<Object[]> getIdentitiesAndDateOfSecurityGroup(SecurityGroup secGroup) {
StringBuilder sb = new StringBuilder();
sb.append("select ii, sgmsi.lastModified from ").append(IdentityImpl.class.getName()).append(" as ii")
.append(" inner join fetch ii.user as iuser, ")
.append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi")
.append(" where sgmsi.securityGroup=:secGroup and sgmsi.identity = ii");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Object[].class)
.setParameter("secGroup", secGroup)
.getResultList();
}
/**
* @see org.olat.basesecurity.Manager#countIdentitiesOfSecurityGroup(org.olat.basesecurity.SecurityGroup)
*/
@Override
public int countIdentitiesOfSecurityGroup(SecurityGroup secGroup) {
DB db = DBFactory.getInstance();
String q = "select count(sgm) from org.olat.basesecurity.SecurityGroupMembershipImpl sgm where sgm.securityGroup = :group";
DBQuery query = db.createQuery(q);
query.setEntity("group", secGroup);
query.setCacheable(true);
int result = ((Long) query.list().get(0)).intValue();
return result;
}
/**
* @see org.olat.basesecurity.Manager#createAndPersistNamedSecurityGroup(java.lang.String)
*/
@Override
public SecurityGroup createAndPersistNamedSecurityGroup(String groupName) {
SecurityGroup secG = createAndPersistSecurityGroup();
NamedGroupImpl ngi = new NamedGroupImpl(groupName, secG);
DBFactory.getInstance().saveObject(ngi);
return secG;
}
/**
* @see org.olat.basesecurity.Manager#findSecurityGroupByName(java.lang.String)
*/
@Override
public SecurityGroup findSecurityGroupByName(String securityGroupName) {
StringBuilder sb = new StringBuilder();
sb.append("select sgi from ").append(NamedGroupImpl.class.getName()).append(" as ngroup ")
.append(" inner join ngroup.securityGroup sgi")
.append(" where ngroup.groupName=:groupName");
List<SecurityGroup> group = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), SecurityGroup.class)
.setParameter("groupName", securityGroupName)
.setHint("org.hibernate.cacheable", Boolean.TRUE)
.getResultList();
int size = group.size();
if (size == 0) return null;
if (size != 1) throw new AssertException("non unique name in namedgroup: " + securityGroupName);
SecurityGroup sg = group.get(0);
return sg;
}
/**
* @see org.olat.basesecurity.Manager#findIdentityByName(java.lang.String)
*/
@Override
public Identity findIdentityByName(String identityName) {
if (identityName == null) throw new AssertException("findIdentitybyName: name was null");
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where ident.name=:username");
List<Identity> identities = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("username", identityName)
.getResultList();
if(identities.isEmpty()) {
return null;
}
return identities.get(0);
}
@Override
public Identity findIdentityByNameCaseInsensitive(String identityName) {
if (identityName == null) throw new AssertException("findIdentitybyName: name was null");
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident where lower(ident.name)=:username");
List<Identity> identities = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("username", identityName.toLowerCase())
.getResultList();
return identities == null || identities.isEmpty() ? null : identities.get(0);
}
/**
* Custom search operation by BiWa
* find identity by student/institution number
* @return
*/
@Override
public Identity findIdentityByNumber(String identityNumber) {
//default initializations
Map<String, String> userPropertiesSearch = new HashMap<String, String>();
// institutional identifier
userPropertiesSearch.put(UserConstants.INSTITUTIONALUSERIDENTIFIER, identityNumber);
List<Identity> identities = getIdentitiesByPowerSearch(null, userPropertiesSearch, true, null, null, null, null, null, null, null, null);
//check for unique search result
if(identities.size() == 1) {
return identities.get(0);
}
return null;
}
@Override
public List<Identity> findIdentitiesByNumber(Collection<String> identityNumbers) {
if(identityNumbers == null || identityNumbers.isEmpty()) return Collections.emptyList();
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" ident ")
.append(" inner join fetch ident.user user ")
.append(" where user.").append(UserConstants.INSTITUTIONALUSERIDENTIFIER).append(" in (:idNumbers) ")
.append(" and ident.status<:status");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("idNumbers", identityNumbers)
.setParameter("status", Identity.STATUS_VISIBLE_LIMIT)
.getResultList();
}
@Override
public List<Identity> findIdentitiesByName(Collection<String> identityNames) {
if (identityNames == null || identityNames.isEmpty()) return Collections.emptyList();
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where ident.name in (:username)");
List<Identity> identities = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("username", identityNames)
.getResultList();
return identities;
}
@Override
public List<Identity> findIdentitiesByNameCaseInsensitive(Collection<String> identityNames) {
if (identityNames == null || identityNames.isEmpty()) return Collections.emptyList();
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where lower(ident.name) in (:usernames)");
List<String> loweredIdentityNames = identityNames.stream()
.map(id -> id.toLowerCase()).collect(Collectors.toList());
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("usernames", loweredIdentityNames)
.getResultList();
}
@Override
public Identity findIdentityByUser(User user) {
if (user == null) return null;
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where user.key=:userKey");
List<Identity> identities = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("userKey", user.getKey())
.getResultList();
if(identities.isEmpty()) {
return null;
}
return identities.get(0);
}
@Override
public List<IdentityShort> findShortIdentitiesByName(Collection<String> identityNames) {
if (identityNames == null || identityNames.isEmpty()) {
return Collections.emptyList();
}
StringBuilder sb = new StringBuilder();
sb.append("select ident from bidentityshort as ident where ident.name in (:names)");
TypedQuery<IdentityShort> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), IdentityShort.class);
int count = 0;
int batch = 500;
List<String> names = new ArrayList<String>(identityNames);
List<IdentityShort> shortIdentities = new ArrayList<IdentityShort>(names.size());
do {
int toIndex = Math.min(count + batch, names.size());
List<String> toLoad = names.subList(count, toIndex);
List<IdentityShort> allProperties = query.setParameter("names", toLoad).getResultList();
shortIdentities.addAll(allProperties);
count += batch;
} while(count < names.size());
return shortIdentities;
}
@Override
public List<IdentityShort> findShortIdentitiesByKey(Collection<Long> identityKeys) {
if (identityKeys == null || identityKeys.isEmpty()) {
return Collections.emptyList();
}
StringBuilder sb = new StringBuilder();
sb.append("select ident from bidentityshort as ident where ident.key in (:keys)");
TypedQuery<IdentityShort> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), IdentityShort.class);
int count = 0;
int batch = 500;
List<Long> names = new ArrayList<Long>(identityKeys);
List<IdentityShort> shortIdentities = new ArrayList<IdentityShort>(names.size());
do {
int toIndex = Math.min(count + batch, names.size());
List<Long> toLoad = names.subList(count, toIndex);
List<IdentityShort> allProperties = query.setParameter("keys", toLoad).getResultList();
shortIdentities.addAll(allProperties);
count += batch;
} while(count < names.size());
return shortIdentities;
}
public List<Identity> findIdentitiesWithoutBusinessGroup(Integer status) {
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident ")
.append(" inner join fetch ident.user user ")
.append(" where not exists (")
.append(" select bgroup from businessgroup bgroup, bgroupmember as me")
.append(" where me.group.key=bgroup.baseGroup.key and me.identity.key=ident.key")
.append(" )");
if (status != null) {
if (status.equals(Identity.STATUS_VISIBLE_LIMIT)) {
// search for all status smaller than visible limit
sb.append(" and ident.status < :status ");
} else {
// search for certain status
sb.append(" and ident.status = :status ");
}
} else {
sb.append(" and ident.status < ").append(Identity.STATUS_DELETED);
}
TypedQuery<Identity> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class);
if (status != null) {
query.setParameter("status", status);
}
return query.getResultList();
}
/**
*
* @see org.olat.basesecurity.Manager#loadIdentityByKey(java.lang.Long)
*/
@Override
public Identity loadIdentityByKey(Long identityKey) {
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(Identity.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where ident.key=:key");
List<Identity> identities = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("key", identityKey)
.setFirstResult(0)
.setMaxResults(1)
.getResultList();
return identities != null && identities.size() == 1 ? identities.get(0) : null;
}
@Override
public List<Identity> loadIdentityByKeys(Collection<Long> identityKeys) {
if (identityKeys == null || identityKeys.isEmpty()) {
return Collections.emptyList();
}
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(Identity.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where ident.key in (:keys)");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("keys", identityKeys)
.getResultList();
}
/**
* @see org.olat.basesecurity.Manager#loadIdentityByKey(java.lang.Long,boolean)
*/
@Override
public Identity loadIdentityByKey(Long identityKey, boolean strict) {
if(strict) return loadIdentityByKey(identityKey);
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(Identity.class.getName()).append(" as ident")
.append(" inner join fetch ident.user user")
.append(" where ident.key=:identityKey");
List<Identity> identities = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("identityKey", identityKey)
.getResultList();
return identities.size() == 1 ? identities.get(0) : null;
}
@Override
public List<IdentityShort> searchIdentityShort(String search, int maxResults) {
String[] searchArr = search.split(" ");
String[] attributes = new String[]{ "name", "firstName", "lastName", "email" };
StringBuilder sb = new StringBuilder();
sb.append("select ident from bidentityshort as ident ")
.append(" where ident.status<").append(Identity.STATUS_VISIBLE_LIMIT).append(" and (");
boolean start = true;
for(int i=0; i<searchArr.length; i++) {
for(String attribute:attributes) {
if(start) {
start = false;
} else {
sb.append(" or ");
}
if (searchArr[i].contains("_") && dbVendor.equals("oracle")) {
//oracle needs special ESCAPE sequence to search for escaped strings
sb.append(" lower(ident.").append(attribute).append(") like :search").append(i).append(" ESCAPE '\\'");
} else if (dbVendor.equals("mysql")) {
sb.append(" ident.").append(attribute).append(" like :search").append(i);
} else {
sb.append(" lower(ident.").append(attribute).append(") like :search").append(i);
}
}
}
sb.append(")");
TypedQuery<IdentityShort> searchQuery = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), IdentityShort.class);
for(int i=searchArr.length; i-->0; ) {
searchQuery.setParameter("search" + i, PersistenceHelper.makeFuzzyQueryString(searchArr[i]));
}
return searchQuery
.setFirstResult(0)
.setMaxResults(maxResults)
.getResultList();
}
@Override
public IdentityShort loadIdentityShortByKey(Long identityKey) {
List<IdentityShort> idents = dbInstance.getCurrentEntityManager()
.createNamedQuery("getIdentityShortById", IdentityShort.class)
.setParameter("identityKey", identityKey)
.getResultList();
if(idents.isEmpty()) {
return null;
}
return idents.get(0);
}
@Override
public List<IdentityShort> loadIdentityShortByKeys(Collection<Long> identityKeys) {
if (identityKeys == null || identityKeys.isEmpty()) {
return Collections.emptyList();
}
StringBuilder sb = new StringBuilder();
sb.append("select ident from bidentityshort as ident where ident.key in (:keys)");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), IdentityShort.class)
.setParameter("keys", identityKeys)
.getResultList();
}
@Override
public List<Identity> loadVisibleIdentities(int firstResult, int maxResults) {
StringBuilder sb = new StringBuilder();
sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident ")
.append(" inner join fetch ident.user as user")
.append(" where ident.status<").append(Identity.STATUS_VISIBLE_LIMIT).append(" order by ident.key");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setFirstResult(firstResult)
.setMaxResults(maxResults)
.getResultList();
}
@Override
public List<Long> loadVisibleIdentityKeys() {
StringBuilder sb = new StringBuilder();
sb.append("select ident.key from ").append(IdentityImpl.class.getName()).append(" as ident")
.append(" where ident.status<").append(Identity.STATUS_VISIBLE_LIMIT).append(" order by ident.key");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Long.class)
.getResultList();
}
/**
*
* @see org.olat.basesecurity.Manager#countUniqueUserLoginsSince(java.util.Date)
*/
@Override
public Long countUniqueUserLoginsSince (Date lastLoginLimit){
String queryStr ="Select count(ident) from org.olat.core.id.Identity as ident where "
+ "ident.lastLogin > :lastLoginLimit and ident.lastLogin != ident.creationDate";
DBQuery dbq = DBFactory.getInstance().createQuery(queryStr);
dbq.setDate("lastLoginLimit", lastLoginLimit);
List res = dbq.list();
Long cntL = (Long) res.get(0);
return cntL;
}
/**
* @see org.olat.basesecurity.Manager#getAuthentications(org.olat.core.id.Identity)
*/
@Override
public List<Authentication> getAuthentications(Identity identity) {
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth ")
.append("inner join fetch auth.identity as ident")
.append(" where ident.key=:identityKey");
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("identityKey", identity.getKey())
.getResultList();
}
/**
* @see org.olat.basesecurity.Manager#createAndPersistAuthentication(org.olat.core.id.Identity, java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public Authentication createAndPersistAuthentication(final Identity ident, final String provider, final String authUserName,
final String credentials, final Encoder.Algorithm algorithm) {
OLATResourceable resourceable = OresHelper.createOLATResourceableInstanceWithoutCheck(provider, ident.getKey());
return CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(resourceable, new SyncerCallback<Authentication>() {
@Override
public Authentication execute() {
Authentication auth = findAuthentication(ident, provider);
if(auth == null) {
auth = createAndPersistAuthenticationIntern(ident, provider, authUserName, credentials, algorithm);
}
return auth;
}
});
}
/**
* This method is not protected by a doInSync and will not check if the authentication already exists.
* @param ident
* @param provider
* @param authUserName
* @param credentials
* @param algorithm
* @return
*/
private Authentication createAndPersistAuthenticationIntern(final Identity ident, final String provider, final String authUserName,
final String credentials, final Encoder.Algorithm algorithm) {
Authentication auth;
if(algorithm != null && credentials != null) {
String salt = algorithm.isSalted() ? Encoder.getSalt() : null;
String hash = Encoder.encrypt(credentials, salt, algorithm);
auth = new AuthenticationImpl(ident, provider, authUserName, hash, salt, algorithm.name());
} else {
auth = new AuthenticationImpl(ident, provider, authUserName, credentials);
}
dbInstance.getCurrentEntityManager().persist(auth);
dbInstance.commit();
log.audit("Create " + provider + " authentication (login=" + ident.getName() + ",authusername=" + authUserName + ")");
return auth;
}
/**
* @see org.olat.basesecurity.Manager#findAuthentication(org.olat.core.id.Identity, java.lang.String)
*/
@Override
public Authentication findAuthentication(IdentityRef identity, String provider) {
if (identity==null) {
throw new IllegalArgumentException("identity must not be null");
}
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName())
.append(" as auth where auth.identity.key=:identityKey and auth.provider=:provider");
List<Authentication> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("identityKey", identity.getKey())
.setParameter("provider", provider)
.getResultList();
if (results == null || results.size() == 0) return null;
if (results.size() > 1) {
throw new AssertException("Found more than one Authentication for a given subject and a given provider.");
}
return results.get(0);
}
@Override
public String findAuthenticationName(IdentityRef identity, String provider) {
if (identity==null) {
throw new IllegalArgumentException("identity must not be null");
}
StringBuilder sb = new StringBuilder();
sb.append("select auth.authusername from ").append(AuthenticationImpl.class.getName())
.append(" as auth where auth.identity.key=:identityKey and auth.provider=:provider");
List<String> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), String.class)
.setParameter("identityKey", identity.getKey())
.setParameter("provider", provider)
.getResultList();
if (results == null || results.size() == 0) return null;
if (results.size() > 1) {
throw new AssertException("Found more than one Authentication for a given subject and a given provider.");
}
return results.get(0);
}
/**
* @see org.olat.basesecurity.Manager#findAuthentication(org.olat.core.id.Identity, java.lang.String)
*/
@Override
public List<Authentication> findAuthenticationByToken(String provider, String securityToken) {
if (provider==null || securityToken==null) {
throw new IllegalArgumentException("provider and token must not be null");
}
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName())
.append(" as auth where auth.credential=:credential and auth.provider=:provider");
List<Authentication> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("credential", securityToken)
.setParameter("provider", provider)
.getResultList();
return results;
}
@Override
public List<Authentication> findOldAuthentication(String provider, Date creationDate) {
if (provider == null || creationDate == null) {
throw new IllegalArgumentException("provider and token must not be null");
}
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName())
.append(" as auth where auth.provider=:provider and auth.creationDate<:creationDate");
List<Authentication> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("creationDate", creationDate, TemporalType.TIMESTAMP)
.setParameter("provider", provider)
.getResultList();
return results;
}
@Override
public Authentication updateAuthentication(Authentication authentication) {
return dbInstance.getCurrentEntityManager().merge(authentication);
}
@Override
public boolean checkCredentials(Authentication authentication, String password) {
Algorithm algorithm = Algorithm.find(authentication.getAlgorithm());
String hash = Encoder.encrypt(password, authentication.getSalt(), algorithm);
return authentication.getCredential() != null && authentication.getCredential().equals(hash);
}
@Override
public Authentication updateCredentials(Authentication authentication, String password, Algorithm algorithm) {
if(authentication.getAlgorithm() != null && authentication.getAlgorithm().equals(algorithm.name())) {
//check if update is needed
String currentSalt = authentication.getSalt();
String newCredentials = Encoder.encrypt(password, currentSalt, algorithm);
if(newCredentials.equals(authentication.getCredential())) {
//same credentials
return authentication;
}
}
String salt = algorithm.isSalted() ? Encoder.getSalt() : null;
String newCredentials = Encoder.encrypt(password, salt, algorithm);
authentication.setSalt(salt);
authentication.setCredential(newCredentials);
authentication.setAlgorithm(algorithm.name());
return updateAuthentication(authentication);
}
/**
* @see org.olat.basesecurity.Manager#deleteAuthentication(org.olat.basesecurity.Authentication)
*/
@Override
public void deleteAuthentication(Authentication auth) {
if(auth == null || auth.getKey() == null) return;//nothing to do
try {
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
.append(" where auth.key=:authKey");
AuthenticationImpl authRef = dbInstance.getCurrentEntityManager().find(AuthenticationImpl.class, auth.getKey());
if(authRef != null) {
dbInstance.getCurrentEntityManager().remove(authRef);
}
} catch (EntityNotFoundException e) {
log.error("", e);
}
}
/**
* @see org.olat.basesecurity.Manager#findAuthenticationByAuthusername(java.lang.String, java.lang.String)
*/
@Override
public Authentication findAuthenticationByAuthusername(String authusername, String provider) {
StringBuilder sb = new StringBuilder();
sb.append("select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
.append(" inner join fetch auth.identity ident")
.append(" where auth.provider=:provider and auth.authusername=:authusername");
List<Authentication> results = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Authentication.class)
.setParameter("provider", provider)
.setParameter("authusername", authusername)
.getResultList();
if (results.size() == 0) return null;
if (results.size() != 1) {
throw new AssertException("more than one entry for the a given authusername and provider, should never happen (even db has a unique constraint on those columns combined) ");
}
return results.get(0);
}
/**
* @see org.olat.basesecurity.Manager#getVisibleIdentitiesByPowerSearch(java.lang.String, java.util.Map, boolean, org.olat.basesecurity.SecurityGroup[], org.olat.basesecurity.PermissionOnResourceable[], java.lang.String[], java.util.Date, java.util.Date)
*/
@Override
public List<Identity> getVisibleIdentitiesByPowerSearch(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch,
SecurityGroup[] groups, PermissionOnResourceable[] permissionOnResources, String[] authProviders, Date createdAfter, Date createdBefore) {
return getIdentitiesByPowerSearch(new SearchIdentityParams(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources,
authProviders, createdAfter, createdBefore, null, null, Identity.STATUS_VISIBLE_LIMIT), 0, -1);
}
@Override
public List<Identity> getVisibleIdentitiesByPowerSearch(String login, Map<String, String> userProperties,
boolean userPropertiesAsIntersectionSearch, SecurityGroup[] groups, PermissionOnResourceable[] permissionOnResources,
String[] authProviders, Date createdAfter, Date createdBefore, int firstResult, int maxResults) {
return getIdentitiesByPowerSearch(new SearchIdentityParams(login, userProperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources,
authProviders, createdAfter, createdBefore, null, null, Identity.STATUS_VISIBLE_LIMIT), firstResult, maxResults);
}
@Override
public long countIdentitiesByPowerSearch(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch, SecurityGroup[] groups,
PermissionOnResourceable[] permissionOnResources, String[] authProviders, Date createdAfter, Date createdBefore, Date userLoginAfter, Date userLoginBefore, Integer status) {
DBQuery dbq = createIdentitiesByPowerQuery(new SearchIdentityParams(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, authProviders, createdAfter, createdBefore, userLoginAfter, userLoginBefore, status), true);
Number count = (Number)dbq.uniqueResult();
return count.longValue();
}
/**
* @see org.olat.basesecurity.Manager#getIdentitiesByPowerSearch(java.lang.String, java.util.Map, boolean, org.olat.basesecurity.SecurityGroup[], org.olat.basesecurity.PermissionOnResourceable[], java.lang.String[], java.util.Date, java.util.Date, java.lang.Integer)
*/
@Override
public List<Identity> getIdentitiesByPowerSearch(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch, SecurityGroup[] groups,
PermissionOnResourceable[] permissionOnResources, String[] authProviders, Date createdAfter, Date createdBefore, Date userLoginAfter, Date userLoginBefore, Integer status) {
DBQuery dbq = createIdentitiesByPowerQuery(new SearchIdentityParams(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, authProviders, createdAfter, createdBefore, userLoginAfter, userLoginBefore, status), false);
return dbq.list();
}
@Override
public int countIdentitiesByPowerSearch(SearchIdentityParams params) {
DBQuery dbq = createIdentitiesByPowerQuery(params, true);
Number count = (Number)dbq.uniqueResult();
return count.intValue();
}
@Override
public List<Identity> getIdentitiesByPowerSearch(SearchIdentityParams params, int firstResult, int maxResults) {
DBQuery dbq = createIdentitiesByPowerQuery(params, false);
if(firstResult >= 0) {
dbq.setFirstResult(firstResult);
}
if(maxResults > 0) {
dbq.setMaxResults(maxResults);
}
@SuppressWarnings("unchecked")
List<Identity> identities = dbq.list();
return identities;
}
private DBQuery createIdentitiesByPowerQuery(SearchIdentityParams params, boolean count) {
boolean hasGroups = (params.getGroups() != null && params.getGroups().length > 0);
boolean hasPermissionOnResources = (params.getPermissionOnResources() != null && params.getPermissionOnResources().length > 0);
boolean hasAuthProviders = (params.getAuthProviders() != null && params.getAuthProviders().length > 0);
// select identity and inner join with user to optimize query
StringBuilder sb = new StringBuilder(5000);
if (hasAuthProviders) {
// I know, it looks wrong but I need to do the join reversed since it is not possible to
// do this query with a left join that starts with the identity using hibernate HQL. A left
// or right join is necessary since it is totally ok to have null values as authentication
// providers (e.g. when searching for users that do not have any authentication providers at all!).
// It took my quite a while to make this work, so think twice before you change anything here!
if(count) {
sb.append("select count(distinct ident.key) from org.olat.basesecurity.AuthenticationImpl as auth ")
.append(" right join auth.identity as ident")
.append(" inner join ident.user as user ");
} else {
sb.append("select distinct ident from org.olat.basesecurity.AuthenticationImpl as auth ")
.append(" right join auth.identity as ident")
.append(" inner join fetch ident.user as user ");
}
} else {
if(count) {
sb.append("select count(distinct ident.key) from org.olat.core.id.Identity as ident ")
.append(" inner join ident.user as user ");
} else {
sb.append("select distinct ident from org.olat.core.id.Identity as ident ")
.append(" inner join fetch ident.user as user ");
}
}
// In any case join with the user. Don't join-fetch user, this breaks the query
// because of the user fields (don't know exactly why this behaves like
// this)
if (hasGroups) {
// join over security group memberships
sb.append(" ,org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi ");
}
if (hasPermissionOnResources) {
// join over policies
sb.append(" ,org.olat.basesecurity.SecurityGroupMembershipImpl as policyGroupMembership ");
sb.append(" ,org.olat.basesecurity.PolicyImpl as policy ");
sb.append(" ,org.olat.resource.OLATResourceImpl as resource ");
}
String login = params.getLogin();
Map<String,String> userproperties = params.getUserProperties();
Date createdAfter = params.getCreatedAfter();
Date createdBefore = params.getCreatedBefore();
Integer status = params.getStatus();
Collection<Long> identityKeys = params.getIdentityKeys();
Boolean managed = params.getManaged();
// complex where clause only when values are available
if (login != null || (userproperties != null && !userproperties.isEmpty())
|| (identityKeys != null && !identityKeys.isEmpty()) || createdAfter != null || createdBefore != null
|| hasAuthProviders || hasGroups || hasPermissionOnResources || status != null
|| managed != null) {
sb.append(" where ");
boolean needsAnd = false;
boolean needsUserPropertiesJoin = false;
// treat login and userProperties as one element in this query
if (login != null && (userproperties != null && !userproperties.isEmpty())) {
sb.append(" ( ");
}
// append query for login
if (login != null) {
login = makeFuzzyQueryString(login);
if (login.contains("_") && dbVendor.equals("oracle")) {
//oracle needs special ESCAPE sequence to search for escaped strings
sb.append(" lower(ident.name) like :login ESCAPE '\\'");
} else if (dbVendor.equals("mysql")) {
sb.append(" ident.name like :login");
} else {
sb.append(" lower(ident.name) like :login");
}
// if user fields follow a join element is needed
needsUserPropertiesJoin = true;
// at least one user field used, after this and is required
needsAnd = true;
}
// append queries for user fields
if (userproperties != null && !userproperties.isEmpty()) {
Map<String, String> emailProperties = new HashMap<String, String>();
Map<String, String> otherProperties = new HashMap<String, String>();
// split the user fields into two groups
for (String key : userproperties.keySet()) {
if (key.toLowerCase().contains("email")) {
emailProperties.put(key, userproperties.get(key));
} else {
otherProperties.put(key, userproperties.get(key));
}
}
// handle email fields special: search in all email fields
if (!emailProperties.isEmpty()) {
needsUserPropertiesJoin = checkIntersectionInUserProperties(sb, needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch());
boolean moreThanOne = emailProperties.size() > 1;
if (moreThanOne) sb.append("(");
boolean needsOr = false;
for (String key : emailProperties.keySet()) {
if (needsOr) sb.append(" or ");
if(dbVendor.equals("mysql")) {
sb.append(" user.").append(key).append(" like :").append(key).append("_value ");
} else {
sb.append(" lower(user.").append(key).append(") like :").append(key).append("_value ");
}
if(dbVendor.equals("oracle")) {
sb.append(" escape '\\'");
}
needsOr = true;
}
if (moreThanOne) sb.append(")");
// cleanup
emailProperties.clear();
}
// add other fields
for (String key : otherProperties.keySet()) {
needsUserPropertiesJoin = checkIntersectionInUserProperties(sb, needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch());
if(dbVendor.equals("mysql")) {
sb.append(" user.").append(key).append(" like :").append(key).append("_value ");
} else {
sb.append(" lower(user.").append(key).append(") like :").append(key).append("_value ");
}
if(dbVendor.equals("oracle")) {
sb.append(" escape '\\'");
}
needsAnd = true;
}
// cleanup
otherProperties.clear();
// at least one user field used, after this and is required
needsAnd = true;
}
// end of user fields and login part
if (login != null && (userproperties != null && !userproperties.isEmpty())) {
sb.append(" ) ");
}
// now continue with the other elements. They are joined with an AND connection
// append query for identity primary keys
if(identityKeys != null && !identityKeys.isEmpty()) {
needsAnd = checkAnd(sb, needsAnd);
sb.append("ident.key in (:identityKeys)");
}
if(managed != null) {
needsAnd = checkAnd(sb, needsAnd);
if(managed.booleanValue()) {
sb.append("ident.externalId is not null");
} else {
sb.append("ident.externalId is null");
}
}
// append query for named security groups
if (hasGroups) {
SecurityGroup[] groups = params.getGroups();
needsAnd = checkAnd(sb, needsAnd);
sb.append(" (");
for (int i = 0; i < groups.length; i++) {
sb.append(" sgmsi.securityGroup=:group_").append(i);
if (i < (groups.length - 1)) sb.append(" or ");
}
sb.append(") ");
sb.append(" and sgmsi.identity=ident ");
}
// append query for policies
if (hasPermissionOnResources) {
needsAnd = checkAnd(sb, needsAnd);
sb.append(" (");
PermissionOnResourceable[] permissionOnResources = params.getPermissionOnResources();
for (int i = 0; i < permissionOnResources.length; i++) {
sb.append(" (");
sb.append(" policy.permission=:permission_").append(i);
sb.append(" and policy.olatResource = resource ");
sb.append(" and resource.resId = :resourceId_").append(i);
sb.append(" and resource.resName = :resourceName_").append(i);
sb.append(" ) ");
if (i < (permissionOnResources.length - 1)) sb.append(" or ");
}
sb.append(") ");
sb.append(" and policy.securityGroup=policyGroupMembership.securityGroup ");
sb.append(" and policyGroupMembership.identity=ident ");
}
// append query for authentication providers
if (hasAuthProviders) {
needsAnd = checkAnd(sb, needsAnd);
sb.append(" (");
String[] authProviders = params.getAuthProviders();
for (int i = 0; i < authProviders.length; i++) {
// special case for null auth provider
if (authProviders[i] == null) {
sb.append(" auth is null ");
} else {
sb.append(" auth.provider=:authProvider_").append(i);
}
if (i < (authProviders.length - 1)) sb.append(" or ");
}
sb.append(") ");
}
// append query for creation date restrictions
if (createdAfter != null) {
needsAnd = checkAnd(sb, needsAnd);
sb.append(" ident.creationDate >= :createdAfter ");
}
if (createdBefore != null) {
needsAnd = checkAnd(sb, needsAnd);
sb.append(" ident.creationDate <= :createdBefore ");
}
if(params.getUserLoginAfter() != null){
needsAnd = checkAnd(sb, needsAnd);
sb.append(" ident.lastLogin >= :lastloginAfter ");
}
if(params.getUserLoginBefore() != null){
needsAnd = checkAnd(sb, needsAnd);
sb.append(" ident.lastLogin <= :lastloginBefore ");
}
if (status != null) {
if (status.equals(Identity.STATUS_VISIBLE_LIMIT)) {
// search for all status smaller than visible limit
needsAnd = checkAnd(sb, needsAnd);
sb.append(" ident.status < :status ");
} else {
// search for certain status
needsAnd = checkAnd(sb, needsAnd);
sb.append(" ident.status = :status ");
}
}
}
// create query object now from string
String query = sb.toString();
DBQuery dbq = dbInstance.createQuery(query);
// add user attributes
if (login != null) {
dbq.setString("login", login.toLowerCase());
}
if(identityKeys != null && !identityKeys.isEmpty()) {
dbq.setParameterList("identityKeys", identityKeys);
}
// add user properties attributes
if (userproperties != null && !userproperties.isEmpty()) {
for (String key : userproperties.keySet()) {
String value = userproperties.get(key);
value = makeFuzzyQueryString(value);
dbq.setString(key + "_value", value.toLowerCase());
}
}
// add named security group names
if (hasGroups) {
SecurityGroup[] groups = params.getGroups();
for (int i = 0; i < groups.length; i++) {
SecurityGroupImpl group = (SecurityGroupImpl) groups[i]; // need to work with impls
dbq.setEntity("group_" + i, group);
}
}
// add policies
if (hasPermissionOnResources) {
PermissionOnResourceable[] permissionOnResources = params.getPermissionOnResources();
for (int i = 0; i < permissionOnResources.length; i++) {
PermissionOnResourceable permissionOnResource = permissionOnResources[i];
dbq.setString("permission_" + i, permissionOnResource.getPermission());
Long id = permissionOnResource.getOlatResourceable().getResourceableId();
dbq.setLong("resourceId_" + i, (id == null ? 0 : id.longValue()));
dbq.setString("resourceName_" + i, permissionOnResource.getOlatResourceable().getResourceableTypeName());
}
}
// add authentication providers
if (hasAuthProviders) {
String[] authProviders = params.getAuthProviders();
for (int i = 0; i < authProviders.length; i++) {
String authProvider = authProviders[i];
if (authProvider != null) {
dbq.setString("authProvider_" + i, authProvider);
}
// ignore null auth provider, already set to null in query
}
}
// add date restrictions
if (createdAfter != null) {
dbq.setDate("createdAfter", createdAfter);
}
if (createdBefore != null) {
dbq.setDate("createdBefore", createdBefore);
}
if(params.getUserLoginAfter() != null){
dbq.setDate("lastloginAfter", params.getUserLoginAfter());
}
if(params.getUserLoginBefore() != null){
dbq.setDate("lastloginBefore", params.getUserLoginBefore());
}
if (status != null) {
dbq.setInteger("status", status);
}
// execute query
return dbq;
}
/**
*
* @param dbVendor
*/
public void setDbVendor(String dbVendor) {
this.dbVendor = dbVendor;
}
@Override
public boolean isIdentityVisible(Identity identity) {
if(identity == null) return false;
Integer status = identity.getStatus();
return (status != null && status.intValue() < Identity.STATUS_VISIBLE_LIMIT);
}
private boolean checkAnd(StringBuilder sb, boolean needsAnd) {
if (needsAnd) sb.append(" and ");
return true;
}
private boolean checkIntersectionInUserProperties(StringBuilder sb, boolean needsJoin, boolean userPropertiesAsIntersectionSearch) {
if (needsJoin) {
if (userPropertiesAsIntersectionSearch) {
sb.append(" and ");
} else {
sb.append(" or ");
}
}
return true;
}
/**
* Helper method that replaces * with % and appends and
* prepends % to the string to make fuzzy SQL match when using like
* @param email
* @return fuzzized string
*/
private String makeFuzzyQueryString(String string) {
// By default only fuzzyfy at the end. Usually it makes no sense to do a
// fuzzy search with % at the beginning, but it makes the query very very
// slow since it can not use any index and must perform a fulltext search.
// User can always use * to make it a really fuzzy search query
// fxdiff FXOLAT-252: use "" to disable this feature and use exact match
if (string.length() > 1 && string.startsWith("\"") && string.endsWith("\"")) {
string = string.substring(1, string.length()-1);
} else {
string = string + "%";
string = string.replace('*', '%');
}
// with 'LIKE' the character '_' is a wildcard which matches exactly one character.
// To test for literal instances of '_', we have to escape it.
string = string.replace("_", "\\_");
return string;
}
/**
* @see org.olat.basesecurity.Manager#saveIdentityStatus(org.olat.core.id.Identity)
*/
@Override
public Identity saveIdentityStatus(Identity identity, Integer status) {
IdentityImpl reloadedIdentity = loadForUpdate(identity);
reloadedIdentity.setStatus(status);
reloadedIdentity = dbInstance.getCurrentEntityManager().merge(reloadedIdentity);
dbInstance.commit();
return reloadedIdentity;
}
@Override
public void setIdentityLastLogin(IdentityRef identity) {
dbInstance.getCurrentEntityManager()
.createNamedQuery("updateIdentityLastLogin")
.setParameter("identityKey", identity.getKey())
.setParameter("now", new Date())
.executeUpdate();
dbInstance.commit();
}
@Override
public Identity saveIdentityName(Identity identity, String newName, String newExternalId) {
IdentityImpl reloadedIdentity = loadForUpdate(identity);
reloadedIdentity.setName(newName);
reloadedIdentity.setExternalId(newExternalId);
reloadedIdentity = dbInstance.getCurrentEntityManager().merge(reloadedIdentity);
dbInstance.commit();
return reloadedIdentity;
}
@Override
public Identity setExternalId(Identity identity, String externalId) {
IdentityImpl reloadedIdentity = loadForUpdate(identity);
reloadedIdentity.setExternalId(externalId);
reloadedIdentity = dbInstance.getCurrentEntityManager().merge(reloadedIdentity);
dbInstance.commit();
return reloadedIdentity;
}
/**
* Don't forget to commit/roolback the transaction as soon as possible
* @param identityKey
* @return
*/
private IdentityImpl loadForUpdate(Identity identity) {
StringBuilder sb = new StringBuilder();
sb.append("select id from ").append(IdentityImpl.class.getName()).append(" as id")
.append(" inner join fetch id.user user ")
.append(" where id.key=:identityKey");
dbInstance.getCurrentEntityManager().detach(identity);
List<IdentityImpl> identities = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), IdentityImpl.class)
.setParameter("identityKey", identity.getKey())
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getResultList();
if(identities.isEmpty()) {
return null;
}
return identities.get(0);
}
@Override
public List<SecurityGroup> getSecurityGroupsForIdentity(Identity identity) {
StringBuilder sb = new StringBuilder();
sb.append("select sgi from ").append(SecurityGroupImpl.class.getName()).append(" as sgi, ")
.append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
.append(" where sgmsi.securityGroup=sgi and sgmsi.identity.key=:identityKey");
List<SecurityGroup> secGroups = DBFactory.getInstance().getCurrentEntityManager()
.createQuery(sb.toString(), SecurityGroup.class)
.setParameter("identityKey", identity.getKey())
.getResultList();
return secGroups;
}
/**
* @see org.olat.basesecurity.Manager#getAndUpdateAnonymousUserForLanguage(java.util.Locale)
*/
public Identity getAndUpdateAnonymousUserForLanguage(Locale locale) {
Translator trans = Util.createPackageTranslator(UserManager.class, locale);
String guestUsername = GUEST_USERNAME_PREFIX + locale.toString();
Identity guestIdentity = findIdentityByName(guestUsername);
if (guestIdentity == null) {
// Create it lazy on demand
User guestUser = UserManager.getInstance().createUser(trans.translate("user.guest"), null, null);
guestUser.getPreferences().setLanguage(locale.toString());
guestIdentity = createAndPersistIdentityAndUser(guestUsername, null, guestUser, null, null, null);
SecurityGroup anonymousGroup = findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
addIdentityToSecurityGroup(guestIdentity, anonymousGroup);
} else if (!guestIdentity.getUser().getProperty(UserConstants.FIRSTNAME, locale).equals(trans.translate("user.guest"))) {
//Check if guest name has been updated in the i18n tool
guestIdentity.getUser().setProperty(UserConstants.FIRSTNAME, trans.translate("user.guest"));
guestIdentity = dbInstance.getCurrentEntityManager().merge(guestIdentity);
}
return guestIdentity;
}
}