diff --git a/src/main/java/org/olat/basesecurity/BaseSecurity.java b/src/main/java/org/olat/basesecurity/BaseSecurity.java
index efcf8f615fd5349ef110ea0151aa7055d1ee109b..f9390bf8e66d6089674c2647fcdd088f2b857f60 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurity.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurity.java
@@ -516,6 +516,13 @@ public interface BaseSecurity {
 	public List<Identity> getVisibleIdentitiesByPowerSearch(String login, Map<String, String> userProperties, boolean userPropertiesAsIntersectionSearch, SecurityGroup[] groups, PermissionOnResourceable[] permissionOnResources, String[] authProviders, Date createdAfter,
 			Date createdBefore);
 	
+	/**
+	 * Like the following method but compact
+	 * @param params
+	 * @return
+	 */
+	public List<Identity> getIdentitiesByPowerSearch(SearchIdentityParams params);
+	
 	/**
 	 * Get a list of identities that match the following conditions. All
 	 * parameters are additive. NULL values mean "no constraints" (e.g. all
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index 0c53ece13499e30501fcf828e053a45986289915..f7185b9637f05da112c41309c45e6bc267fd6778 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -1264,15 +1264,15 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	/**
 	 * @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)
 	 */
-	public List getVisibleIdentitiesByPowerSearch(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch,
+	public List<Identity> getVisibleIdentitiesByPowerSearch(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch,
 			SecurityGroup[] groups, PermissionOnResourceable[] permissionOnResources, String[] authProviders, Date createdAfter, Date createdBefore) {
-		return getIdentitiesByPowerSearch(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, 
-				                              authProviders, createdAfter, createdBefore, null, null, Identity.STATUS_VISIBLE_LIMIT ); 
+		return getIdentitiesByPowerSearch(new SearchIdentityParams(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, 
+				                              authProviders, createdAfter, createdBefore, null, null, Identity.STATUS_VISIBLE_LIMIT)); 
 	}
 	
 	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(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, authProviders, createdAfter, createdBefore, userLoginAfter, userLoginBefore, status, true);
+		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();
 	}
@@ -1282,16 +1282,22 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
    */
 	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(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, authProviders, createdAfter, createdBefore, userLoginAfter, userLoginBefore, status, false);
+		DBQuery dbq = createIdentitiesByPowerQuery(new SearchIdentityParams(login, userproperties, userPropertiesAsIntersectionSearch, groups, permissionOnResources, authProviders, createdAfter, createdBefore, userLoginAfter, userLoginBefore, status), false);
 		return dbq.list();
 	}
 	
-	private DBQuery createIdentitiesByPowerQuery(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch, SecurityGroup[] groups,
-			PermissionOnResourceable[] permissionOnResources, String[] authProviders, Date createdAfter, Date createdBefore, Date userLoginAfter, Date userLoginBefore, Integer status, boolean count) {
+	@Override
+	public List<Identity> getIdentitiesByPowerSearch(SearchIdentityParams params) {
+		DBQuery dbq = createIdentitiesByPowerQuery(params, false);
+		@SuppressWarnings("unchecked")
+		List<Identity> identities = dbq.list();
+		return identities;
+	}
 
-		boolean hasGroups = (groups != null && groups.length > 0);
-		boolean hasPermissionOnResources = (permissionOnResources != null && permissionOnResources.length > 0);
-		boolean hasAuthProviders = (authProviders != null && authProviders.length > 0);
+	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();
@@ -1328,11 +1334,19 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 			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();
 		
 		// complex where clause only when values are available
-		if (login != null || (userproperties != null && !userproperties.isEmpty()) || createdAfter != null	|| createdBefore != null || 
-				hasAuthProviders || hasGroups || hasPermissionOnResources || status != null) {
+		if (login != null || (userproperties != null && !userproperties.isEmpty())
+				|| (identityKeys != null && !identityKeys.isEmpty()) || createdAfter != null	|| createdBefore != null
+				|| hasAuthProviders || hasGroups || hasPermissionOnResources || status != null) {
 			sb.append(" where ");		
 			boolean needsAnd = false;
 			boolean needsUserPropertiesJoin = false;
@@ -1341,17 +1355,17 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 			if (login != null && (userproperties != null && !userproperties.isEmpty())) {
 				sb.append(" ( ");			
 			}
-			// append queries for user attributes
-				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");
-					}
+			// 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
@@ -1360,8 +1374,8 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 
 			// append queries for user fields
 			if (userproperties != null && !userproperties.isEmpty()) {
-				HashMap<String, String> emailProperties = new HashMap<String, String>();
-				HashMap<String, String> otherProperties = new HashMap<String, String>();
+				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()) {
@@ -1374,7 +1388,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	
 				// handle email fields special: search in all email fields
 				if (!emailProperties.isEmpty()) {
-					needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, userPropertiesAsIntersectionSearch);
+					needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch());
 					boolean moreThanOne = emailProperties.size() > 1;
 					if (moreThanOne) sb.append("(");
 					boolean needsOr = false;
@@ -1401,7 +1415,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	
 				// add other fields
 				for (String key : otherProperties.keySet()) {
-					needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, userPropertiesAsIntersectionSearch);
+					needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch());
 					if(dbVendor.equals("mysql")) {
 						sb.append(" user.properties['").append(key).append("'] like :").append(key).append("_value ");
 					} else {
@@ -1419,15 +1433,22 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 				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)");
+			}
+			
 			// 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++) {
@@ -1442,6 +1463,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 			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);
@@ -1460,6 +1482,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 			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) {
@@ -1481,11 +1504,11 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 				needsAnd = checkAnd(sb, needsAnd);
 				sb.append(" ident.creationDate <= :createdBefore ");
 			}
-			if(userLoginAfter != null){
+			if(params.getUserLoginAfter() != null){
 				needsAnd = checkAnd(sb, needsAnd);
 				sb.append(" ident.lastLogin >= :lastloginAfter ");
 			}
-			if(userLoginBefore != null){
+			if(params.getUserLoginBefore() != null){
 				needsAnd = checkAnd(sb, needsAnd);
 				sb.append(" ident.lastLogin <= :lastloginBefore ");
 			}
@@ -1509,8 +1532,13 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		DBQuery dbq = db.createQuery(query);
 		
 		// add user attributes
-		if (login != null) 
+		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()) {
@@ -1523,6 +1551,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 
 		// 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);
@@ -1531,6 +1560,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		
 		// 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());
@@ -1542,6 +1572,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 
 		// add authentication providers
 		if (hasAuthProviders) {
+			String[] authProviders = params.getAuthProviders();
 			for (int i = 0; i < authProviders.length; i++) {
 				String authProvider = authProviders[i];
 				if (authProvider != null) {
@@ -1558,11 +1589,11 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		if (createdBefore != null) {
 			dbq.setDate("createdBefore", createdBefore);
 		}
-		if(userLoginAfter != null){
-			dbq.setDate("lastloginAfter", userLoginAfter);
+		if(params.getUserLoginAfter() != null){
+			dbq.setDate("lastloginAfter", params.getUserLoginAfter());
 		}
-		if(userLoginBefore != null){
-			dbq.setDate("lastloginBefore", userLoginBefore);
+		if(params.getUserLoginBefore() != null){
+			dbq.setDate("lastloginBefore", params.getUserLoginBefore());
 		}
 		
 		if (status != null) {
diff --git a/src/main/java/org/olat/basesecurity/SearchIdentityParams.java b/src/main/java/org/olat/basesecurity/SearchIdentityParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1f53ad5be686ca879f01d72a441e9125cb31397
--- /dev/null
+++ b/src/main/java/org/olat/basesecurity/SearchIdentityParams.java
@@ -0,0 +1,159 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.basesecurity;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class SearchIdentityParams {
+	private String login;
+	private Map<String, String> userProperties;
+	private boolean userPropertiesAsIntersectionSearch;
+	private SecurityGroup[] groups;
+	private PermissionOnResourceable[] permissionOnResources;
+	private String[] authProviders;
+	private Date createdAfter;
+	private Date createdBefore;
+	private Date userLoginAfter;
+	private Date userLoginBefore;
+	private Integer status;
+	private Collection<Long> identityKeys;
+	
+	public SearchIdentityParams() {
+		//
+	}
+	
+	public SearchIdentityParams(String login, Map<String, String> userproperties, boolean userPropertiesAsIntersectionSearch,
+			SecurityGroup[] groups, PermissionOnResourceable[] permissionOnResources, String[] authProviders,
+			Date createdAfter, Date createdBefore, Date userLoginAfter, Date userLoginBefore, Integer status) {
+		this.login = login;
+		this.userProperties = userproperties;
+		this.userPropertiesAsIntersectionSearch = userPropertiesAsIntersectionSearch;
+		this.groups = groups;
+		this.permissionOnResources = permissionOnResources;
+		this.authProviders = authProviders;
+		this.createdAfter = createdAfter;
+		this.createdBefore = createdBefore;
+		this.userLoginAfter = userLoginAfter;
+		this.userLoginBefore = userLoginBefore;
+		this.status = status;
+	}
+	
+	public String getLogin() {
+		return login;
+	}
+	
+	public void setLogin(String login) {
+		this.login = login;
+	}
+	
+	public Map<String, String> getUserProperties() {
+		return userProperties;
+	}
+	
+	public void setUserProperties(Map<String, String> userProperties) {
+		this.userProperties = userProperties;
+	}
+	
+	public boolean isUserPropertiesAsIntersectionSearch() {
+		return userPropertiesAsIntersectionSearch;
+	}
+	
+	public void setUserPropertiesAsIntersectionSearch(boolean userPropertiesAsIntersectionSearch) {
+		this.userPropertiesAsIntersectionSearch = userPropertiesAsIntersectionSearch;
+	}
+	
+	public SecurityGroup[] getGroups() {
+		return groups;
+	}
+	
+	public void setGroups(SecurityGroup[] groups) {
+		this.groups = groups;
+	}
+	
+	public PermissionOnResourceable[] getPermissionOnResources() {
+		return permissionOnResources;
+	}
+	
+	public void setPermissionOnResources(PermissionOnResourceable[] permissionOnResources) {
+		this.permissionOnResources = permissionOnResources;
+	}
+	
+	public String[] getAuthProviders() {
+		return authProviders;
+	}
+	
+	public void setAuthProviders(String[] authProviders) {
+		this.authProviders = authProviders;
+	}
+	
+	public Date getCreatedAfter() {
+		return createdAfter;
+	}
+	
+	public void setCreatedAfter(Date createdAfter) {
+		this.createdAfter = createdAfter;
+	}
+	
+	public Date getCreatedBefore() {
+		return createdBefore;
+	}
+	
+	public void setCreatedBefore(Date createdBefore) {
+		this.createdBefore = createdBefore;
+	}
+	
+	public Date getUserLoginAfter() {
+		return userLoginAfter;
+	}
+	
+	public void setUserLoginAfter(Date userLoginAfter) {
+		this.userLoginAfter = userLoginAfter;
+	}
+	
+	public Date getUserLoginBefore() {
+		return userLoginBefore;
+	}
+	
+	public void setUserLoginBefore(Date userLoginBefore) {
+		this.userLoginBefore = userLoginBefore;
+	}
+	
+	public Integer getStatus() {
+		return status;
+	}
+	
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+	
+	public Collection<Long> getIdentityKeys() {
+		return identityKeys;
+	}
+	
+	public void setIdentityKeys(Collection<Long> identityKeys) {
+		this.identityKeys = identityKeys;
+	}
+}
diff --git a/src/main/java/org/olat/course/member/AbstractMemberListController.java b/src/main/java/org/olat/course/member/AbstractMemberListController.java
index 300ddc0117cb90dc5feed171e580cf4adcccdec5..1c08954ab739533a2c2e897d1712bd78920c234f 100644
--- a/src/main/java/org/olat/course/member/AbstractMemberListController.java
+++ b/src/main/java/org/olat/course/member/AbstractMemberListController.java
@@ -29,7 +29,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.olat.basesecurity.BaseSecurity;
-import org.olat.basesecurity.IdentityShort;
+import org.olat.basesecurity.SearchIdentityParams;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
@@ -53,6 +53,8 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle
 import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
 import org.olat.course.member.MemberListTableModel.Cols;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupMembership;
@@ -64,12 +66,15 @@ import org.olat.repository.RepositoryManager;
 import org.olat.repository.model.RepositoryEntryMembership;
 import org.olat.repository.model.RepositoryEntryPermissionChangeEvent;
 import org.olat.user.UserManager;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 public abstract class AbstractMemberListController extends BasicController {
+
+	protected static final String USER_PROPS_ID = MemberListController.class.getCanonicalName();
 	
 	public static final String TABLE_ACTION_EDIT = "tbl_edit";
 	public static final String TABLE_ACTION_MAIL = "tbl_mail";
@@ -82,6 +87,7 @@ public abstract class AbstractMemberListController extends BasicController {
 	private DialogBoxController leaveDialogBox;
 	protected CloseableModalController cmc;
 	private EditMembershipController editMemberCtrl;
+	private final List<UserPropertyHandler> userPropertyHandlers;
 
 	private final UserManager userManager;
 	private final RepositoryEntry repoEntry;
@@ -90,7 +96,7 @@ public abstract class AbstractMemberListController extends BasicController {
 	private final BusinessGroupService businessGroupService;
 	
 	public AbstractMemberListController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry, String page) {
-		super(ureq, wControl);
+		super(ureq, wControl, Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale()));
 		
 		this.repoEntry = repoEntry;
 		userManager = CoreSpringFactory.getImpl(UserManager.class);
@@ -103,12 +109,14 @@ public abstract class AbstractMemberListController extends BasicController {
 		//table
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
 		tableConfig.setPreferencesOffered(true, this.getClass().getSimpleName());
-		tableConfig.setTableEmptyMessage(translate("nomembers"));			
-		memberListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator(), false);
+		tableConfig.setTableEmptyMessage(translate("nomembers"));
+		
+		memberListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator(), true);
 		listenTo(memberListCtr);
 
-		int numOfColumns = initColumns();
-		memberListModel = new MemberListTableModel(numOfColumns);
+		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, false);
+		initColumns();
+		memberListModel = new MemberListTableModel(userPropertyHandlers);
 		memberListCtr.setTableDataModel(memberListModel);
 		memberListCtr.setMultiSelect(true);
 		memberListCtr.addMultiSelectAction("table.header.edit", TABLE_ACTION_EDIT);
@@ -125,9 +133,15 @@ public abstract class AbstractMemberListController extends BasicController {
 		//
 	}
 	
-	protected int initColumns() {
-		memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.lastName.i18n(), Cols.lastName.ordinal(), null, getLocale()));
-		memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.firstName.i18n(), Cols.firstName.ordinal(), null, getLocale()));
+	protected void initColumns() {
+		int offset = Cols.values().length;
+		int i=0;
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			if (userPropertyHandler == null) continue;
+			boolean visible = UserManager.getInstance().isMandatoryUserProperty(USER_PROPS_ID , userPropertyHandler);
+			memberListCtr.addColumnDescriptor(visible, userPropertyHandler.getColumnDescriptor(i++ + offset, null, getLocale()));
+		}
+		
 		memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.firstTime.i18n(), Cols.firstTime.ordinal(), null, getLocale()));
 		memberListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.lastTime.i18n(), Cols.lastTime.ordinal(), null, getLocale()));
 		CustomCellRenderer roleRenderer = new CourseRoleCellRenderer(getLocale());
@@ -136,7 +150,6 @@ public abstract class AbstractMemberListController extends BasicController {
 		memberListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.groups.i18n(), Cols.groups.ordinal(), null, getLocale(),  ColumnDescriptor.ALIGNMENT_LEFT, groupRenderer));
 		memberListCtr.addColumnDescriptor(new StaticColumnDescriptor(TABLE_ACTION_EDIT, "action", translate("table.header.edit")));
 		memberListCtr.addColumnDescriptor(new StaticColumnDescriptor(TABLE_ACTION_REMOVE, "action", translate("table.header.remove")));
-		return 8;
 	}
 
 	@Override
@@ -253,7 +266,7 @@ public abstract class AbstractMemberListController extends BasicController {
 
 	protected abstract SearchMembersParams getSearchParams();
 	
-	protected void reloadModel() {
+	public void reloadModel() {
 		updateTableModel(getSearchParams());
 	}
 
@@ -281,13 +294,20 @@ public abstract class AbstractMemberListController extends BasicController {
 		for(BusinessGroupMembership membership:memberships) {
 			identityKeys.add(membership.getIdentityKey());
 		}
-		List<IdentityShort> identities = securityManager.findShortIdentitiesByKey(identityKeys);
+		SearchIdentityParams idParams = new SearchIdentityParams();
+		idParams.setIdentityKeys(identityKeys);
+		if(params.getUserPropertiesSearch() != null && !params.getUserPropertiesSearch().isEmpty()) {
+			idParams.setUserProperties(params.getUserPropertiesSearch());
+		}
+		if(StringHelper.containsNonWhitespace(params.getLogin())) {
+			idParams.setLogin(params.getLogin());
+		}
+		List<Identity> identities = securityManager.getIdentitiesByPowerSearch(idParams);
+
 		Map<Long,MemberView> keyToMemberMap = new HashMap<Long,MemberView>();
 		List<MemberView> memberList = new ArrayList<MemberView>();
-		for(IdentityShort identity:identities) {
-			MemberView member = new MemberView(identity.getKey());
-			member.setFirstName(identity.getFirstName());
-			member.setLastName(identity.getLastName());
+		for(Identity identity:identities) {
+			MemberView member = new MemberView(identity);
 			memberList.add(member);
 			keyToMemberMap.put(identity.getKey(), member);
 		}
@@ -332,12 +352,34 @@ public abstract class AbstractMemberListController extends BasicController {
 			}
 		}
 		
+		//the order of the filter is important
 		filterByRoles(memberList, params);
+		filterByOrigin(memberList, params);
 		memberListModel.setObjects(memberList);
 		memberListCtr.modelChanged();
 		return memberList;
 	}
 	
+	private void filterByOrigin(List<MemberView> memberList, SearchMembersParams params) {
+		if(params.isGroupOrigin() && params.isRepoOrigin()) {
+			//do ntohing not very useful :-)
+		} else if(params.isGroupOrigin()) {
+			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
+				CourseMembership m = it.next().getMembership();
+				if(!m.isGroupTutor() && !m.isGroupParticipant() && !m.isGroupWaiting()) {
+					it.remove();
+				}
+			}
+		} else if(params.isRepoOrigin()) {
+			for(Iterator<MemberView> it=memberList.iterator(); it.hasNext(); ) {
+				CourseMembership m = it.next().getMembership();
+				if(!m.isRepoOwner() && !m.isRepoTutor() && !m.isRepoParticipant()) {
+					it.remove();
+				}
+			}
+		}
+	}
+	
 	/**
 	 * This filter method preserve the multiple roles of a member. If we want only the waiting list but
 	 * a member is in the waiting list and owner of the course, we want it to know.
@@ -347,6 +389,7 @@ public abstract class AbstractMemberListController extends BasicController {
 	 */
 	private void filterByRoles(List<MemberView> memberList, SearchMembersParams params) {
 		List<MemberView> members = new ArrayList<MemberView>(memberList);
+
 		if(params.isRepoOwners()) {
 			for(Iterator<MemberView> it=members.iterator(); it.hasNext(); ) {
 				if(it.next().getMembership().isRepoOwner()) {
diff --git a/src/main/java/org/olat/course/member/CourseRoleCellRenderer.java b/src/main/java/org/olat/course/member/CourseRoleCellRenderer.java
index 9ba236e8d4234213d52b4497946a4ec926778823..7b80231399e41ea22fe9c4d68095973d6b7ea53a 100644
--- a/src/main/java/org/olat/course/member/CourseRoleCellRenderer.java
+++ b/src/main/java/org/olat/course/member/CourseRoleCellRenderer.java
@@ -47,19 +47,27 @@ public class CourseRoleCellRenderer implements CustomCellRenderer {
 			boolean and = false;
 			if(membership.isOwner()) {
 				and = and(sb, and);
-				sb.append(translator.translate("role.owner"));
+				sb.append(translator.translate("role.repo.owner"));
 			}
-			if(membership.isTutor()) {
+			if(membership.isRepoTutor()) {
 				and = and(sb, and);
-				sb.append(translator.translate("role.tutor"));
+				sb.append(translator.translate("role.repo.tutor"));
 			}
-			if(membership.isParticipant()) {
+			if(membership.isGroupTutor()) {
 				and = and(sb, and);
-				sb.append(translator.translate("role.participant"));
+				sb.append(translator.translate("role.group.tutor"));
+			}
+			if(membership.isRepoParticipant()) {
+				and = and(sb, and);
+				sb.append(translator.translate("role.repo.participant"));
+			}
+			if(membership.isGroupParticipant()) {
+				and = and(sb, and);
+				sb.append(translator.translate("role.group.participant"));
 			}
 			if(membership.isWaiting()) {
 				and = and(sb, and);
-				sb.append(translator.translate("role.waiting"));
+				sb.append(translator.translate("role.group.waiting"));
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/course/member/EditMembershipController.java b/src/main/java/org/olat/course/member/EditMembershipController.java
index fa9eb96e8e17b64261799096eb094dc3ba814507..d4726732abd9235e2becb7f42f8b47ec0efb7f35 100644
--- a/src/main/java/org/olat/course/member/EditMembershipController.java
+++ b/src/main/java/org/olat/course/member/EditMembershipController.java
@@ -152,7 +152,7 @@ public class EditMembershipController extends FormBasicController {
 		//repository entry rights
 		
 		String[] repoValues = new String[] {
-				translate("role.owner"), translate("role.tutor"), translate("role.participant")
+				translate("role.repo.owner"), translate("role.repo.tutor"), translate("role.repo.participant")
 		};
 		repoRightsEl = uifactory.addCheckboxesVertical("repoRights", formLayout, repoRightsKeys, repoValues, null, 1);
 		if(member != null) {
diff --git a/src/main/java/org/olat/course/member/MemberListController.java b/src/main/java/org/olat/course/member/MemberListController.java
index cca71c9125c906f1ac67006386e4259bad83d398..f94bca1c2ba488d6a0091d55ed7aa836a7c42035 100644
--- a/src/main/java/org/olat/course/member/MemberListController.java
+++ b/src/main/java/org/olat/course/member/MemberListController.java
@@ -21,6 +21,7 @@ package org.olat.course.member;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
 import org.olat.repository.RepositoryEntry;
 
 /**
@@ -32,9 +33,13 @@ public class MemberListController extends AbstractMemberListController {
 	private final SearchMembersParams searchParams;
 	
 	public MemberListController(UserRequest ureq, WindowControl wControl,
-			RepositoryEntry repoEntry, SearchMembersParams searchParams) {
+			RepositoryEntry repoEntry, SearchMembersParams searchParams, String infos) {
 		super(ureq, wControl, repoEntry, "all_member_list");
 		this.searchParams = searchParams;
+		
+		if(StringHelper.containsNonWhitespace(infos)) {
+			mainVC.contextPut("infos", infos);
+		}
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/member/MemberListTableModel.java b/src/main/java/org/olat/course/member/MemberListTableModel.java
index c264e3c1c2c6eaf13479bbf3befffee7a13806f9..74fbc83936f98bb4b89c9dfdd3d2f16896b39513 100644
--- a/src/main/java/org/olat/course/member/MemberListTableModel.java
+++ b/src/main/java/org/olat/course/member/MemberListTableModel.java
@@ -20,8 +20,10 @@
 package org.olat.course.member;
 
 import java.util.Collections;
+import java.util.List;
 
 import org.olat.core.gui.components.table.DefaultTableDataModel;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
 
 /**
  * 
@@ -29,35 +31,39 @@ import org.olat.core.gui.components.table.DefaultTableDataModel;
  */
 public class MemberListTableModel extends DefaultTableDataModel<MemberView> {
 	
-	private final int numOfColumns;
+	private final List<UserPropertyHandler> userPropertyHandlers;
 	
-	public MemberListTableModel(int numOfColumns) {
+	public MemberListTableModel(List<UserPropertyHandler> userPropertyHandlers) {
 		super(Collections.<MemberView>emptyList());
-		this.numOfColumns = numOfColumns;
+		this.userPropertyHandlers = userPropertyHandlers;
 	}
 
 	@Override
 	public int getColumnCount() {
-		return numOfColumns;
+		return 4 + userPropertyHandlers.size();
 	}
 
 	@Override
 	public Object getValueAt(int row, int col) {
 		MemberView member = getObject(row);
-		switch(Cols.values()[col]) {
-			case firstName: return member.getFirstName();
-			case lastName: return member.getLastName();
-			case firstTime: return member.getFirstTime();
-			case lastTime: return member.getLastTime();
-			case role: return member.getMembership();
-			case groups: return member;
-			default: return "ERROR";
+		switch(col) {
+			case 0: return member.getFirstTime();
+			case 1: return member.getLastTime();
+			case 2: return member.getMembership();
+			case 3: return member;
+			default: {
+				int propPos = col-4;
+				if(propPos < userPropertyHandlers.size()) {
+					UserPropertyHandler handler = userPropertyHandlers.get(propPos);
+					String value = handler.getUserProperty(member.getIdentity().getUser(), getLocale());
+					return value;
+				}
+				return null;
+			}
 		}
 	}
 	
 	public enum Cols {
-		firstName("table.header.firstName"),
-		lastName("table.header.lastName"),
 		firstTime("table.header.firstTime"),
 		lastTime("table.header.lastTime"),
 		role("table.header.role"),
diff --git a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
new file mode 100644
index 0000000000000000000000000000000000000000..321fd260a6e3702ca53c978541eb86be70628499
--- /dev/null
+++ b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
@@ -0,0 +1,69 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.member;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class MemberListWithOriginFilterController extends AbstractMemberListController {
+	
+	private final SearchMembersParams searchParams;
+	private final OriginFilterController filterController;
+	
+	public MemberListWithOriginFilterController(UserRequest ureq, WindowControl wControl,
+			RepositoryEntry repoEntry, SearchMembersParams searchParams, String infos) {
+		super(ureq, wControl, repoEntry, "member_list_origin_filter");
+		this.searchParams = searchParams;
+		
+		filterController = new OriginFilterController(ureq, wControl);
+		listenTo(filterController);
+		mainVC.put("originFilter", filterController.getInitialComponent());
+		
+		if(StringHelper.containsNonWhitespace(infos)) {
+			mainVC.contextPut("infos", infos);
+		}
+	}
+
+	@Override
+	public SearchMembersParams getSearchParams() {
+		return searchParams;
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == filterController) {
+			if(event instanceof SearchOriginParams) {
+				SearchOriginParams filter = (SearchOriginParams)event;
+				searchParams.setRepoOrigin(filter.isRepoOrigin());
+				searchParams.setGroupOrigin(filter.isGroupOrigin());
+				reloadModel();
+			}
+		}
+		super.event(ureq, source, event);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/MemberSearchController.java b/src/main/java/org/olat/course/member/MemberSearchController.java
new file mode 100644
index 0000000000000000000000000000000000000000..97c39fcb620d05e6b154557e285f537f1a636cd8
--- /dev/null
+++ b/src/main/java/org/olat/course/member/MemberSearchController.java
@@ -0,0 +1,62 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.member;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class MemberSearchController extends AbstractMemberListController {
+	
+	private SearchMembersParams searchParams = new SearchMembersParams();
+	private final MemberSearchForm searchForm;
+	
+	public MemberSearchController(UserRequest ureq, WindowControl wControl,
+			RepositoryEntry repoEntry) {
+		super(ureq, wControl, repoEntry, "search_member_list");
+		
+		searchForm = new MemberSearchForm(ureq, wControl);
+		listenTo(searchForm);
+		
+		mainVC.put("searchForm", searchForm.getInitialComponent());
+	}
+
+	@Override
+	public SearchMembersParams getSearchParams() {
+		return searchParams;
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == searchForm) {
+			if(event instanceof SearchMembersParams) {
+				searchParams = (SearchMembersParams)event;
+				reloadModel();
+			}
+		}
+		super.event(ureq, source, event);
+	}
+}
diff --git a/src/main/java/org/olat/course/member/MemberSearchForm.java b/src/main/java/org/olat/course/member/MemberSearchForm.java
new file mode 100644
index 0000000000000000000000000000000000000000..fffbc70585abfcc49bc34bf5f859cef8ce3d6d7a
--- /dev/null
+++ b/src/main/java/org/olat/course/member/MemberSearchForm.java
@@ -0,0 +1,170 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.member;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.user.UserManager;
+import org.olat.user.propertyhandlers.EmailProperty;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class MemberSearchForm extends FormBasicController {
+	
+	private String[] roleKeys = {"owner", "tutor", "attendee", "waiting"};
+	private String[] originKeys = new String[]{"all", "repo", "group"};
+	
+	private TextElement login;
+	private SingleSelection originEl;
+	private MultipleSelectionElement rolesEl;
+	
+	private Map<String,FormItem> propFormItems;
+	private List<UserPropertyHandler> userPropertyHandlers;
+	
+	private final UserManager userManager;
+
+	public MemberSearchForm(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, "search_form", Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale()));
+		
+		userManager = CoreSpringFactory.getImpl(UserManager.class);
+
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		FormLayoutContainer leftContainer = FormLayoutContainer.createDefaultFormLayout("left_1", getTranslator());
+		leftContainer.setRootForm(mainForm);
+		formLayout.add(leftContainer);
+		//user property
+		login = uifactory.addTextElement("login", "search.login", 128, "", leftContainer);
+
+		userPropertyHandlers = userManager.getUserPropertyHandlersFor(getClass().getCanonicalName(), false);
+		propFormItems = new HashMap<String,FormItem>();
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			if (userPropertyHandler == null) continue;
+
+			FormItem fi = userPropertyHandler.addFormItem(getLocale(), null, getClass().getCanonicalName(), false, leftContainer);
+			fi.setTranslator(this.getTranslator());
+			// DO NOT validate email field => see OLAT-3324, OO-155, OO-222
+			if (userPropertyHandler instanceof EmailProperty && fi instanceof TextElement) {
+				TextElement textElement = (TextElement)fi;
+				textElement.setItemValidatorProvider(null);
+			}
+			propFormItems.put(userPropertyHandler.getName(), fi);
+		}
+
+		//others
+		FormLayoutContainer rightContainer = FormLayoutContainer.createDefaultFormLayout("right_1", getTranslator());
+		rightContainer.setRootForm(mainForm);
+		formLayout.add(rightContainer);
+		
+		//roles
+		String[] roleValues = new String[roleKeys.length];
+		for(int i=roleKeys.length; i-->0; ) {
+			roleValues[i] = translate("search." + roleKeys[i]);
+		}
+		rolesEl = uifactory.addCheckboxesHorizontal("roles", "search.roles", rightContainer, roleKeys, roleValues, null);
+		for(String roleKey: roleKeys) {
+			rolesEl.select(roleKey, true);
+		}
+
+		String[] openValues = new String[originKeys.length];
+		for(int i=originKeys.length; i-->0; ) {
+			openValues[i] = translate("search." + originKeys[i]);
+		}
+		originEl = uifactory.addRadiosHorizontal("openBg", "search.origin", rightContainer, originKeys, openValues);
+		originEl.select("all", true);
+
+		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
+		formLayout.add(buttonLayout);
+		uifactory.addFormSubmitButton("search", "search", buttonLayout);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		SearchMembersParams params = new SearchMembersParams();
+		//roles
+		Set<String> selectedKeys = rolesEl.getSelectedKeys();
+		params.setRepoOwners(selectedKeys.contains("owner"));
+		params.setRepoTutors(selectedKeys.contains("tutor"));
+		params.setGroupTutors(selectedKeys.contains("tutor"));
+		params.setRepoParticipants(selectedKeys.contains("attendee"));
+		params.setGroupParticipants(selectedKeys.contains("attendee"));
+		params.setGroupWaitingList(selectedKeys.contains("waiting"));
+
+		//origin
+		if(!originEl.isOneSelected() || originEl.isSelected(0)) {
+			params.setRepoOrigin(true);
+			params.setGroupOrigin(true);
+		} else if(originEl.isSelected(1)) {
+			params.setRepoOrigin(true);
+			params.setGroupOrigin(false);
+		} else if(originEl.isSelected(2)) {
+			params.setRepoOrigin(false);
+			params.setGroupOrigin(true);
+		}
+		
+		String loginVal = login.getValue();
+		if(StringHelper.containsNonWhitespace(loginVal)) {
+			params.setLogin(loginVal);
+		}
+		
+		//user properties
+		Map<String, String> userPropertiesSearch = new HashMap<String, String>();				
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			if (userPropertyHandler == null) continue;
+			FormItem ui = propFormItems.get(userPropertyHandler.getName());
+			String uiValue = userPropertyHandler.getStringValue(ui);
+			if (StringHelper.containsNonWhitespace(uiValue)) {
+				userPropertiesSearch.put(userPropertyHandler.getName(), uiValue);
+			}
+		}
+		if(!userPropertiesSearch.isEmpty()) {
+			params.setUserPropertiesSearch(userPropertiesSearch);
+		}
+
+		fireEvent(ureq, params);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/MemberView.java b/src/main/java/org/olat/course/member/MemberView.java
index 2669974bbe2cc7f810f9901f88ab39860004e4b3..501fd44eb78dce0ed25c37670805f36fe4cb7966 100644
--- a/src/main/java/org/olat/course/member/MemberView.java
+++ b/src/main/java/org/olat/course/member/MemberView.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
+import org.olat.core.id.Identity;
 import org.olat.group.BusinessGroupShort;
 
 /**
@@ -31,37 +32,23 @@ import org.olat.group.BusinessGroupShort;
  */
 public class MemberView {
 	
-	private final Long identityKey;
-	private String firstName;
-	private String lastName;
+	private final Identity identity;
 	private Date firstTime;
 	private Date lastTime;
 	private final CourseMembership membership = new CourseMembership();
 	private List<BusinessGroupShort> groups;
 	
 	
-	public MemberView(Long identityKey) {
-		this.identityKey = identityKey;
+	public MemberView(Identity identity) {
+		this.identity = identity;
 	}
 
 	public Long getIdentityKey() {
-		return identityKey;
+		return identity.getKey();
 	}
-
-	public String getFirstName() {
-		return firstName;
-	}
-
-	public void setFirstName(String firstName) {
-		this.firstName = firstName;
-	}
-
-	public String getLastName() {
-		return lastName;
-	}
-
-	public void setLastName(String lastName) {
-		this.lastName = lastName;
+	
+	public Identity getIdentity() {
+		return identity;
 	}
 
 	public CourseMembership getMembership() {
@@ -109,7 +96,7 @@ public class MemberView {
 
 	@Override
 	public int hashCode() {
-		return identityKey == null ? 2878 : identityKey.hashCode();
+		return getIdentityKey() == null ? 2878 : getIdentityKey().hashCode();
 	}
 
 	@Override
@@ -119,7 +106,7 @@ public class MemberView {
 		}
 		if(obj instanceof MemberView) {
 			MemberView member = (MemberView)obj;
-			return identityKey != null && identityKey.equals(member.getIdentityKey());
+			return getIdentityKey() != null && getIdentityKey().equals(member.getIdentityKey());
 		}
 		return false;
 	}
@@ -127,8 +114,8 @@ public class MemberView {
 	@Override
 	public String toString() {
 		StringBuilder sb = new StringBuilder();
-		sb.append("memberView[name=").append(firstName == null ? "" : firstName)
-			.append(" ").append(lastName == null ? "NULL" : lastName).append("]");
+		sb.append("memberView[identityKey=").append(getIdentityKey() == null ? "" : getIdentityKey())
+			.append(":login=").append(identity == null ? "NULL" : identity.getName()).append("]");
 		return sb.toString();
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/MembersOverviewController.java b/src/main/java/org/olat/course/member/MembersOverviewController.java
index 6a92999346c6dfdb98554f92a8c587cd6df36d53..a006bf07a69913bad945c95c413def891bab6474 100644
--- a/src/main/java/org/olat/course/member/MembersOverviewController.java
+++ b/src/main/java/org/olat/course/member/MembersOverviewController.java
@@ -27,7 +27,6 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
-import org.olat.core.gui.components.panel.Panel;
 import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
 import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
 import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
@@ -70,12 +69,13 @@ public class MembersOverviewController extends BasicController implements Activa
 	private final SegmentViewComponent segmentView;
 	private final VelocityContainer mainVC;
 	
-	private MemberListController allMemberListCtrl;
-	private MemberListController ownersCtrl;
-	private MemberListController tutorsCtrl;
-	private MemberListController participantsCtrl;
-	private MemberListController waitingCtrl;
-	private MemberListController selectedCtrl;
+	private AbstractMemberListController allMemberListCtrl;
+	private AbstractMemberListController ownersCtrl;
+	private AbstractMemberListController tutorsCtrl;
+	private AbstractMemberListController participantsCtrl;
+	private AbstractMemberListController waitingCtrl;
+	private AbstractMemberListController selectedCtrl;
+	private AbstractMemberListController searchCtrl;
 	private final Link importMemberLink, addMemberLink;
 	
 	private StepsMainRunController importMembersWizard;
@@ -232,13 +232,13 @@ public class MembersOverviewController extends BasicController implements Activa
 		System.out.println("Send mails: " + mailTemplate);
 	}
 	
-	private MemberListController updateAllMembers(UserRequest ureq) {
+	private AbstractMemberListController updateAllMembers(UserRequest ureq) {
 		if(allMemberListCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance("AllMembers", 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(true, true, true, true, true, false);
-			allMemberListCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams);
+			allMemberListCtrl = new MemberListWithOriginFilterController(ureq, bwControl, repoEntry, searchParams, null);
 			listenTo(allMemberListCtrl);
 		}
 		
@@ -248,13 +248,14 @@ public class MembersOverviewController extends BasicController implements Activa
 		return allMemberListCtrl;
 	}
 	
-	private MemberListController updateOwners(UserRequest ureq) {
+	private AbstractMemberListController updateOwners(UserRequest ureq) {
 		if(ownersCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance("Owners", 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(true, false, false, false, false, false);
-			ownersCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams);
+			String infos = translate("owners.infos");
+			ownersCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams, infos);
 			listenTo(ownersCtrl);
 		}
 		
@@ -264,13 +265,14 @@ public class MembersOverviewController extends BasicController implements Activa
 		return ownersCtrl;
 	}
 
-	private MemberListController updateTutors(UserRequest ureq) {
+	private AbstractMemberListController updateTutors(UserRequest ureq) {
 		if(tutorsCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance("Tutors", 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, true, false, true, false, false);
-			tutorsCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams);
+			String infos = translate("tutors.infos");
+			tutorsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, repoEntry, searchParams, infos);
 			listenTo(tutorsCtrl);
 		}
 		
@@ -280,13 +282,14 @@ public class MembersOverviewController extends BasicController implements Activa
 		return tutorsCtrl;
 	}
 	
-	private MemberListController updateParticipants(UserRequest ureq) {
+	private AbstractMemberListController updateParticipants(UserRequest ureq) {
 		if(participantsCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance("Tutors", 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, false, true, false, true, false);
-			participantsCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams);
+			String infos = translate("participants.infos");
+			participantsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, repoEntry, searchParams, infos);
 			listenTo(participantsCtrl);
 		}
 		
@@ -296,13 +299,14 @@ public class MembersOverviewController extends BasicController implements Activa
 		return participantsCtrl;
 	}
 	
-	private MemberListController updateWaitingList(UserRequest ureq) {
+	private AbstractMemberListController updateWaitingList(UserRequest ureq) {
 		if(waitingCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance("WaitingList", 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, false, false, false, false, true);
-			waitingCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams);
+			String infos = translate("waiting.infos");
+			waitingCtrl = new MemberListController(ureq, bwControl, repoEntry, searchParams, infos);
 			listenTo(waitingCtrl);
 		}
 		
@@ -312,7 +316,17 @@ public class MembersOverviewController extends BasicController implements Activa
 		return waitingCtrl;
 	}
 	
-	private void updateSearch(UserRequest ureq) {
-		mainVC.put("memberList", new Panel("empty"));
+	private AbstractMemberListController updateSearch(UserRequest ureq) {
+		if(searchCtrl == null) {
+			OLATResourceable ores = OresHelper.createOLATResourceableInstance("Search", 0l);
+			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
+			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
+			searchCtrl = new MemberSearchController(ureq, bwControl, repoEntry);
+			listenTo(searchCtrl);
+		}
+	
+		mainVC.put("membersCmp", searchCtrl.getInitialComponent());
+		addToHistory(ureq, searchCtrl);
+		return searchCtrl;
 	}
 }
diff --git a/src/main/java/org/olat/course/member/OriginFilterController.java b/src/main/java/org/olat/course/member/OriginFilterController.java
new file mode 100644
index 0000000000000000000000000000000000000000..59aea79b764d2d6a98151e6e595281d2d2ebfc67
--- /dev/null
+++ b/src/main/java/org/olat/course/member/OriginFilterController.java
@@ -0,0 +1,93 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.member;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OriginFilterController extends FormBasicController {
+	
+
+	private String[] originKeys = new String[]{"all", "repo", "group"};
+	
+	private SingleSelection originEl;
+	
+	public OriginFilterController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		String[] openValues = new String[originKeys.length];
+		for(int i=originKeys.length; i-->0; ) {
+			openValues[i] = translate("search." + originKeys[i]);
+		}
+		originEl = uifactory.addRadiosHorizontal("openBg", "search.origin.alt", formLayout, originKeys, openValues);
+		originEl.select("all", true);
+		originEl.addActionListener(this, FormEvent.ONCHANGE);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(originEl == source) {
+			SearchOriginParams e = doSearch();
+			fireEvent(ureq, e);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+	
+	private SearchOriginParams doSearch() {
+		SearchOriginParams params = new SearchOriginParams();
+		//origin
+		if(!originEl.isOneSelected() || originEl.isSelected(0)) {
+			params.setRepoOrigin(true);
+			params.setGroupOrigin(true);
+		} else if(originEl.isSelected(1)) {
+			params.setRepoOrigin(true);
+			params.setGroupOrigin(false);
+		} else if(originEl.isSelected(2)) {
+			params.setRepoOrigin(false);
+			params.setGroupOrigin(true);
+		}
+		return params;
+	}
+}
diff --git a/src/main/java/org/olat/course/member/SearchMembersParams.java b/src/main/java/org/olat/course/member/SearchMembersParams.java
index 348fbe4079f18f7bbdf5b14022a36bb04be67cf7..0367f27ea4c73b8152fc8f5e245082f1006f071a 100644
--- a/src/main/java/org/olat/course/member/SearchMembersParams.java
+++ b/src/main/java/org/olat/course/member/SearchMembersParams.java
@@ -19,11 +19,17 @@
  */
 package org.olat.course.member;
 
+import java.util.Map;
+
+import org.olat.core.gui.control.Event;
+
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class SearchMembersParams {
+public class SearchMembersParams extends Event {
+	private static final long serialVersionUID = -8842738563007496141L;
+	
 	private boolean repoOwners;
 	private boolean repoTutors;
 	private boolean repoParticipants;
@@ -31,12 +37,19 @@ public class SearchMembersParams {
 	private boolean groupParticipants;
 	private boolean groupWaitingList;
 	
+	private boolean repoOrigin = true;
+	private boolean groupOrigin = true;
+	
+	private String login;
+	private Map<String, String> userPropertiesSearch;
+	
 	public SearchMembersParams() {
-		//
+		super("search_members");
 	}
 	
 	public SearchMembersParams(boolean repoOwners, boolean repoTutors, boolean repoParticipants,
 			boolean groupTutors, boolean groupParticipants, boolean groupWaitingList) {
+		this();
 		this.repoOwners = repoOwners;
 		this.repoTutors = repoTutors;
 		this.repoParticipants = repoParticipants;
@@ -92,4 +105,36 @@ public class SearchMembersParams {
 	public void setGroupWaitingList(boolean groupWaitingList) {
 		this.groupWaitingList = groupWaitingList;
 	}
+
+	public boolean isRepoOrigin() {
+		return repoOrigin;
+	}
+
+	public void setRepoOrigin(boolean repoOrigin) {
+		this.repoOrigin = repoOrigin;
+	}
+
+	public boolean isGroupOrigin() {
+		return groupOrigin;
+	}
+
+	public void setGroupOrigin(boolean groupOrigin) {
+		this.groupOrigin = groupOrigin;
+	}
+
+	public String getLogin() {
+		return login;
+	}
+
+	public void setLogin(String login) {
+		this.login = login;
+	}
+
+	public Map<String, String> getUserPropertiesSearch() {
+		return userPropertiesSearch;
+	}
+
+	public void setUserPropertiesSearch(Map<String, String> userPropertiesSearch) {
+		this.userPropertiesSearch = userPropertiesSearch;
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/SearchOriginParams.java b/src/main/java/org/olat/course/member/SearchOriginParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ad01020f889efcbce53a4d0b61ef0fa3e58828d
--- /dev/null
+++ b/src/main/java/org/olat/course/member/SearchOriginParams.java
@@ -0,0 +1,53 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.member;
+
+import org.olat.core.gui.control.Event;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class SearchOriginParams extends Event {
+
+	private static final long serialVersionUID = -8878568908411612699L;
+	private boolean repoOrigin = true;
+	private boolean groupOrigin = true;
+
+	public SearchOriginParams() {
+		super("search_origin");
+	}
+	
+	public boolean isRepoOrigin() {
+		return repoOrigin;
+	}
+
+	public void setRepoOrigin(boolean repoOrigin) {
+		this.repoOrigin = repoOrigin;
+	}
+
+	public boolean isGroupOrigin() {
+		return groupOrigin;
+	}
+
+	public void setGroupOrigin(boolean groupOrigin) {
+		this.groupOrigin = groupOrigin;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_content/all_member_list.html b/src/main/java/org/olat/course/member/_content/all_member_list.html
index 963f2f3490aa8d45fd7e2b00515bb3ac61be60a9..df7e6fe736b62af8f77c16c497023921fad78249 100644
--- a/src/main/java/org/olat/course/member/_content/all_member_list.html
+++ b/src/main/java/org/olat/course/member/_content/all_member_list.html
@@ -1,3 +1,10 @@
+#if($infos)
+	<br/>
+	<div class="b_clearfix">
+		<p class="b_info">$infos</p>
+	</div>
+#end
+
 <div class="b_clearfix">
 	$r.render("memberList")
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html b/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html
new file mode 100644
index 0000000000000000000000000000000000000000..b37db7384fbf68a2f54a86e26598b76d98a4e3e6
--- /dev/null
+++ b/src/main/java/org/olat/course/member/_content/member_list_origin_filter.html
@@ -0,0 +1,13 @@
+#if($infos)
+	<br/>
+	<div class="b_clearfix">
+		<p class="b_info">$infos</p>
+	</div>
+#end
+<br/>
+<div class="b_clearfix" style="position:relative;">
+	<div class="o_buttons_box_right">
+		$r.render("originFilter")
+	</div>
+	$r.render("memberList")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_content/search_form.html b/src/main/java/org/olat/course/member/_content/search_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..90eb3abd9deb81a13c9ca22a65269bef958252be
--- /dev/null
+++ b/src/main/java/org/olat/course/member/_content/search_form.html
@@ -0,0 +1,14 @@
+<br/>
+<div class="b_clearfix">
+	<div class="b_c33l">
+		<div class="b_subcl">
+			$r.render("left_1")
+			$r.render("button_layout")
+		</div>
+	</div>
+	<div class="b_c66r">
+		<div class="b_subcr">	
+			$r.render("right_1")
+		</div>
+	</div>
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_content/search_member_list.html b/src/main/java/org/olat/course/member/_content/search_member_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..02a204d385dc031bdbb557698c03d60d134feafe
--- /dev/null
+++ b/src/main/java/org/olat/course/member/_content/search_member_list.html
@@ -0,0 +1,4 @@
+$r.render("searchForm")
+<div class="b_clearfix">
+	$r.render("memberList")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
index 639ce202ca25821ac709b6984aab1d2701506af6..8887f47b5d2ebd80a10dee6d60af537a16d8f1a0 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
@@ -9,9 +9,13 @@ menu.rights=Rechte
 menu.rights.alt=Rechte
 members.all=Alle
 owners=Besitzer
+owners.infos=Besitzer haben volle Autoren- und Administrationsrechte für diesen Kurs.
 tutors=Betreuer
+tutors.infos=Betreuer haben Zugang zum Coaching- und Bewertswerkzeug für Kursteilnehmer.<br/>Gruppenbetreuer haben Zugang zum Coaching- und bewertswerkzeug ihrer Gruppenteilnehmer.
 participants=Teilnehmer
+participants.infos=Teilnehmer haben Zugang zum Kurs.<br/>Gruppenteilnehmer haben Zugang zum Kurs und zu ihrer Gruppe.
 waitinglist=Warteliste
+waiting.infos=Personen auf der Gruppenwarteliste haben weder Zugang zum Kurs noch zu der Gruppe. Der Zugang wird erst freigegeben wenn genügend Platz vorhanden ist oder die Person von Hand umgeteilt wurde.
 search=Suche
 action=Aktion
 add.member=Mitglieder hinzufügen
@@ -24,10 +28,23 @@ assessment=Bewertungswerkzeug
 dialog.modal.bg.leave.text=Wollen Sie wirklich dieser Person {0} von dem Kurs und alle Gruppe entfernen?
 group.create=Gruppe erstellen
 group.add=Gruppe hinzufügen
-role.owner=Besitzer
-role.tutor=Betreuer
-role.participant=Teilnehmer
-role.waiting=Warteliste
+role.repo.owner=Besitzer
+role.repo.tutor=Betreuer
+role.group.tutor=Gruppenbetreuer
+role.repo.participant=Teilnehmer
+role.group.participant=Gruppenteilnehmer
+role.group.waiting=Warteliste
+search.roles=Rolle
+search.origin=Herkunft
+search.origin.alt=Anzeige
+search.owner=$\:role.repo.owner
+search.tutor=$\:role.repo.tutor
+search.attendee=$\:role.repo.participant
+search.waiting=$\:role.group.waiting
+search.all=alle Mitglieder
+search.repo=nur Kursmitglieder
+search.group=nur Gruppenmitglieder
+search.login=Benutzername
 table.header.edit=Bearbeiten
 table.header.remove=Entfernen
 table.header.firstName=Vorname
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties
index e3d51733d83701eb79a97dc2be16f7b01c9fabf1..73db484016434d92c3835e28b8678607a47dc919 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_en.properties
@@ -16,10 +16,12 @@ search=Search
 action=Action
 group.create=Create group
 group.add=Add group
-role.owner=Propriétaire
-role.tutor=Coach
-role.participant=Participant
-role.waiting=En attente
+role.repo.owner=Owner
+role.repo.tutor=Coach
+role.group.tutor=Coach
+role.repo.participant=Participant
+role.group.participant=Participant
+role.group.waiting=Waiting
 table.header.edit=Edit
 table.header.remove=Remove
 table.header.firstName=First name
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties
index 22778694452c309fcf36000a28c72273d714fdb2..c257bfe1bb4816e0538106f3f6a55e46dbfc5a0a 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_fr.properties
@@ -16,10 +16,12 @@ search=Recherche
 action=Action
 group.create=Cr\u00E9er un groupe
 group.add=Ajouter un groupe
-role.owner=Propri\u00E9taire
-role.tutor=Coach
-role.participant=Participant
-role.waiting=En attente
+role.repo.owner=Propri\u00E9taire
+role.repo.tutor=Coach
+role.group.tutor=Coach
+role.repo.participant=Participant
+role.group.participant=Participant
+role.group.waiting=En attente
 table.header.edit=Editer
 table.header.remove=Enlever
 table.header.firstName=Pr\u00E9nom
diff --git a/src/main/java/org/olat/course/nodes/co/CORunController.java b/src/main/java/org/olat/course/nodes/co/CORunController.java
index 68c7837cb76b8a0abc4a1c253787ffe324ffd64a..cd6f46ba8bc756aeacb79dab63b24ed93e2dfc42 100644
--- a/src/main/java/org/olat/course/nodes/co/CORunController.java
+++ b/src/main/java/org/olat/course/nodes/co/CORunController.java
@@ -121,11 +121,11 @@ public class CORunController extends BasicController {
 		if(groupKeys != null && StringHelper.containsNonWhitespace(grpNames)) {
 			groupKeys = businessGroupService.toGroupKeys(grpNames, cgm.getCourseResource());
 		}
-		if (coachesConfigured) {
+		if (coachesConfigured != null && coachesConfigured.booleanValue()) {
 			ContactList cl = retrieveCoachesFromGroups(groupKeys);
 			contactLists.push(cl);
 		}
-		if (partipsConfigured) {
+		if (partipsConfigured != null && partipsConfigured.booleanValue()) {
 			ContactList cl = retrieveParticipantsFromGroups(groupKeys);
 			contactLists.push(cl);
 		} 
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
index b5698a548652d8187bcb6157d51ed637216ac307..fc2e5cf76df34f2c59c7df21e9ea343236e6177b 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
@@ -1,7 +1,7 @@
 #Mon Mar 02 09:54:04 CET 2009
 create.form.title=Neue Arbeitsgruppe erstellen
 create.group=Gruppe erstellen
-create.group.description=Erzeugen Sie eine neue Gruppe mit der unten stehenden Schaltfläche. Als Besitzer dieser Gruppe können Sie danach die Gruppenwerkzeuge freischalten, Benutzer hinzufügen oder die Gruppe veröffentlichen.
+create.group.description=Erzeugen Sie eine neue Gruppe mit der unten stehenden Schaltfläche. Als Betreuer dieser Gruppe können Sie danach die Gruppenwerkzeuge freischalten, Benutzer hinzufügen oder die Gruppe veröffentlichen.
 copy.group=Kopieren
 dialog.modal.bg.delete.title=Gruppe l\u00F6schen?
 dialog.modal.bg.delete.text=Wollen Sie die Gruppe "{0}" wirklich l\u00F6schen?
@@ -27,7 +27,7 @@ menu.groups=Meine Gruppen
 menu.groups.alt=Arbeiten Sie mit Ihren Gruppen
 menu.opengroups=Ver\u00F6ffentlichte Gruppen
 menu.opengroups.alt=Arbeitsgruppen in die \u00F6ffentlich sind und an denen ich teilnehmen kann.
-msg.atleastone=Es muss mindestens ein Besitzer in der Arbeitsgruppe eingetragen sein.
+msg.atleastone=Es muss mindestens ein Betreuer in der Arbeitsgruppe eingetragen sein.
 msg.alleastone.editable.group=Sie m\u00FCssen mindestens eine Gruppe wählen, die Sie besitzen.
 right.header=Rechtegruppen
 right.intro=In dieser Liste finden Sie alle Rechtegruppen, an denen Sie teilnehmen. 
@@ -44,7 +44,7 @@ search.header=Gruppe
 search.intro=In Gruppe suchen
 search.generic=Suche
 search.attendee=Teilnehmer
-search.owner=Besitzer / Betreuer
+search.owner=Betreuer
 search.waiting=Warteliste
 search.public=Public group
 search.all=alle
@@ -57,7 +57,7 @@ search.headless=Orphans
 search.headless.check=Gruppe ohne Mitglieder und Ressourcen
 cif.displayname=Name
 cif.description=Beschreibung
-cif.owner=Besitzer
+cif.owner=Betreuer
 cif.id=ID
 cif.coursetitle=Kurstitel
 cif.error.allempty=Bitte f\u00FCllen Sie mindestens ein Formularfeld aus.
diff --git a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
index dc766058a2e7f476dc0566f93f2f68bdee20ea21..6717f3cbc7547da5b97dbf716d215252c5edf24a 100644
--- a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
+++ b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
@@ -182,6 +182,59 @@
 					</bean>
 				</entry>
 				
+				<entry key="org.olat.course.member.MemberSearchForm">
+					<bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext">
+						<property name="propertyHandlers">
+							<list>
+								<ref bean="userPropertyFirstName" />
+								<ref bean="userPropertyLastName" />
+								<ref bean="userPropertyEmail" />
+								<ref bean="userPropertyInstitutionalName" />
+								<ref bean="userPropertyInstitutionalUserIdentifier" />
+								<ref bean="userPropertyInstitutionalEmail" />
+							</list>
+						</property>
+						<property name="adminViewOnlyProperties">
+							<set>
+								<ref bean="userPropertyEmail" />
+								<ref bean="userPropertyInstitutionalName" />
+								<ref bean="userPropertyInstitutionalUserIdentifier" />
+								<ref bean="userPropertyInstitutionalEmail" />
+							</set>						
+						</property>
+					</bean>
+				</entry>
+				
+				<entry key="org.olat.course.member.MemberListController">
+					<bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext">
+						<property name="propertyHandlers">
+							<list>
+								<ref bean="userPropertyFirstName" />
+								<ref bean="userPropertyLastName" />
+								<ref bean="userPropertyEmail" />
+								<ref bean="userPropertyInstitutionalName" />
+								<ref bean="userPropertyInstitutionalUserIdentifier" />
+								<ref bean="userPropertyInstitutionalEmail" />
+							</list>
+						</property>
+						<property name="adminViewOnlyProperties">
+							<set>
+								<ref bean="userPropertyEmail" />
+								<ref bean="userPropertyInstitutionalName" />
+								<ref bean="userPropertyInstitutionalUserIdentifier" />
+								<ref bean="userPropertyInstitutionalEmail" />
+							</set>						
+						</property>
+						<property name="mandatoryProperties">
+							<set>
+								<ref bean="userPropertyFirstName" />
+								<ref bean="userPropertyLastName" />
+								<ref bean="userPropertyEmail" />
+							</set>
+						</property>
+					</bean>
+				</entry>
+				
 				<entry key="org.olat.admin.user.UsermanagerUserSearchForm">
 					<bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext">
 						<property name="propertyHandlers">
diff --git a/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java b/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java
index 7ecaa1d8de4f649e99aa29c791cd34adb0540380..d682ea1c4bf5636f33eac018cadbca14e9ad6a7a 100644
--- a/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java
+++ b/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java
@@ -20,15 +20,20 @@
 package org.olat.basesecurity;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
+import org.olat.core.id.UserConstants;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
+import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -41,6 +46,8 @@ public class BaseSecurityManagerTest extends OlatTestCase {
 	@Autowired
 	private DB dbInstance;
 	@Autowired
+	private UserManager userManager;
+	@Autowired
 	private BaseSecurity securityManager;
 
 	@Test
@@ -145,4 +152,90 @@ public class BaseSecurityManagerTest extends OlatTestCase {
 		Assert.assertTrue(identities.contains(id2));
 	}
 	
+	@Test
+	public void testGetIdentityByPowerSearch_IdentityKeys() {
+		String login = "pow-1-" + UUID.randomUUID().toString();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser(login);
+		dbInstance.commitAndCloseSession();
+		
+		SearchIdentityParams params = new SearchIdentityParams();
+		params.setIdentityKeys(Collections.singletonList(id.getKey()));
+		
+		List<Identity> ids = securityManager.getIdentitiesByPowerSearch(params);
+		Assert.assertNotNull(ids);
+		Assert.assertEquals(1, ids.size());
+		Assert.assertEquals(id, ids.get(0));
+	}
+	
+	@Test
+	public void testGetIdentityByPowerSearch_Login() {
+		String login = "pow-2-" + UUID.randomUUID().toString();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser(login);
+		dbInstance.commitAndCloseSession();
+		
+		SearchIdentityParams params = new SearchIdentityParams();
+		params.setLogin(login);
+		
+		List<Identity> ids = securityManager.getIdentitiesByPowerSearch(params);
+		Assert.assertNotNull(ids);
+		Assert.assertEquals(1, ids.size());
+		Assert.assertEquals(id, ids.get(0));
+	}
+	
+	@Test
+	public void testGetIdentityByPowerSearch_UserProperty() {
+		//create a user with a first name
+		String login = "pow-3-" + UUID.randomUUID().toString();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser(login);
+		String firstName = id.getUser().getProperty(UserConstants.FIRSTNAME, null);
+		dbInstance.commitAndCloseSession();
+		
+		SearchIdentityParams params = new SearchIdentityParams();
+		Map<String,String> props = new HashMap<String,String>();
+		props.put(UserConstants.FIRSTNAME, firstName);
+		params.setUserProperties(props);
+		
+		List<Identity> ids = securityManager.getIdentitiesByPowerSearch(params);
+		Assert.assertNotNull(ids);
+		Assert.assertEquals(1, ids.size());
+		Assert.assertEquals(id, ids.get(0));
+	}
+	
+	@Test
+	public void testGetIdentityByPowerSearch_LoginIdentityKeys() {
+		String login = "pow-4-" + UUID.randomUUID().toString();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser(login);
+		dbInstance.commitAndCloseSession();
+		
+		SearchIdentityParams params = new SearchIdentityParams();
+		params.setLogin(login);
+		params.setIdentityKeys(Collections.singletonList(id.getKey()));
+		
+		List<Identity> ids = securityManager.getIdentitiesByPowerSearch(params);
+		Assert.assertNotNull(ids);
+		Assert.assertEquals(1, ids.size());
+		Assert.assertEquals(id, ids.get(0));
+	}
+	
+	@Test
+	public void testGetIdentityByPowerSearch_LoginIdentityKeysProperty() {
+		String login = "pow-5-" + UUID.randomUUID().toString();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser(login);
+		dbInstance.commitAndCloseSession();
+		
+		SearchIdentityParams params = new SearchIdentityParams();
+		params.setLogin(login);
+		Map<String,String> props = new HashMap<String,String>();
+		props.put(UserConstants.FIRSTNAME, id.getUser().getProperty(UserConstants.FIRSTNAME, null));
+		props.put(UserConstants.LASTNAME, id.getUser().getProperty(UserConstants.LASTNAME, null));
+		params.setUserProperties(props);
+		params.setIdentityKeys(Collections.singletonList(id.getKey()));
+		
+		List<Identity> ids = securityManager.getIdentitiesByPowerSearch(params);
+		Assert.assertNotNull(ids);
+		Assert.assertEquals(1, ids.size());
+		Assert.assertEquals(id, ids.get(0));
+	}
+	
+	
 }