diff --git a/src/main/java/org/olat/admin/user/tools/UserToolCategory.java b/src/main/java/org/olat/admin/user/tools/UserToolCategory.java
index 1dd168483f6a33992d0b29285e6fbd6432fd5424..d12a5d7436750d696ba374a5416b561581484403 100644
--- a/src/main/java/org/olat/admin/user/tools/UserToolCategory.java
+++ b/src/main/java/org/olat/admin/user/tools/UserToolCategory.java
@@ -1,5 +1,30 @@
+/**
+ * <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.admin.user.tools;
 
+/**
+ * 
+ * Initial date: 28.10.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
 public enum UserToolCategory {
 	search,
 	personal,
diff --git a/src/main/java/org/olat/admin/user/tools/UserToolsModule.java b/src/main/java/org/olat/admin/user/tools/UserToolsModule.java
index dfc698d28d756911205db9c773736566f78cdbed..ae2c823ed5deca5d089cd8cf683cfb30dbc95443 100644
--- a/src/main/java/org/olat/admin/user/tools/UserToolsModule.java
+++ b/src/main/java/org/olat/admin/user/tools/UserToolsModule.java
@@ -29,8 +29,10 @@ import org.olat.core.extensions.ExtManager;
 import org.olat.core.extensions.Extension;
 import org.olat.core.extensions.ExtensionElement;
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.WindowManager;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.prefs.Preferences;
 import org.olat.home.HomeMainController;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -76,6 +78,39 @@ public class UserToolsModule extends AbstractSpringModule {
 		init();
 	}
 	
+	public String getUserTools(Preferences prefs) {
+		String selectedToolV2s = (String)prefs.get(WindowManager.class, "user-tools-v2");
+		if(!StringHelper.containsNonWhitespace(selectedToolV2s)) {
+			String selectedTools = (String)prefs.get(WindowManager.class, "user-tools");
+			if(StringHelper.containsNonWhitespace(selectedTools)) {
+				//upgrade
+				
+				StringBuilder selectedToolSb = new StringBuilder(selectedTools);
+				String[] newPresets = new String[]{
+						"org.olat.home.HomeMainController:org.olat.gui.control.PrintUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.gui.control.HelpUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.instantMessaging.ui.ImpressumMainController"
+				};
+				
+				for(String newPreset:newPresets) {
+					if(selectedToolSb.indexOf(newPreset) < 0) {
+						if(selectedToolSb.length() > 0) selectedToolSb.append(",");
+						selectedToolSb.append(newPreset);
+					}
+				}
+				prefs.put(WindowManager.class, "user-tools-v2", selectedToolSb.toString());
+				prefs.save();
+				selectedToolV2s = selectedToolSb.toString();
+			}
+		}
+		return selectedToolV2s;
+	}
+	
+	public void setUserTools(Preferences prefs, String settings) {
+		prefs.put(WindowManager.class, "user-tools-v2", settings);
+		prefs.save();
+	}
+	
 	public List<UserToolExtension> getUserToolExtensions(UserRequest ureq) {
 		List<UserToolExtension> tools = new ArrayList<>();
 		if(!isUserToolsDisabled()) {
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index f4dc7b9a63d89f1fe5c0b954ad1fcf5df69a1b53..d4842207400798eb1d3ce24dfe033978d1c74a90 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -358,7 +358,6 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	 */
 	@Override
 	public Roles getRoles(Identity identity) {
-		
 		boolean isGuestOnly = false;
 		boolean isInvitee = false;
 
@@ -382,9 +381,9 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	public List<String> getRolesAsString(Identity identity) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select ngroup.groupName from ").append(NamedGroupImpl.class.getName()).append(" as ngroup ")
-		  .append(" inner join ngroup.securityGroup sgi ")
 		  .append(" where exists (")
-		  .append("   select sgmsi from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi where sgmsi.identity.key=:identityKey and sgmsi.securityGroup=sgi")
+		  .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()
diff --git a/src/main/java/org/olat/course/member/MembersOverviewController.java b/src/main/java/org/olat/course/member/MembersOverviewController.java
index 0382a56d327d440aa64b63bdda78a9485ae35fbb..92f6bd6baabf7703b2729c17715be2c90c4c197e 100644
--- a/src/main/java/org/olat/course/member/MembersOverviewController.java
+++ b/src/main/java/org/olat/course/member/MembersOverviewController.java
@@ -267,8 +267,8 @@ public class MembersOverviewController extends BasicController implements Activa
 		Step start = new ImportMember_1b_ChooseMemberStep(ureq, repoEntry, null);
 		StepRunnerCallback finish = new StepRunnerCallback() {
 			@Override
-			public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
-				addMembers(ureq, runContext);
+			public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
+				addMembers(uureq, runContext);
 				return StepsMainRunController.DONE_MODIFIED;
 			}
 		};
@@ -285,8 +285,8 @@ public class MembersOverviewController extends BasicController implements Activa
 		Step start = new ImportMember_1a_LoginListStep(ureq, repoEntry, null);
 		StepRunnerCallback finish = new StepRunnerCallback() {
 			@Override
-			public Step execute(UserRequest ureq, WindowControl wControl, StepsRunContext runContext) {
-				addMembers(ureq, runContext);
+			public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
+				addMembers(uureq, runContext);
 				if(runContext.containsKey("notFounds")) {
 					showWarning("user.notfound", runContext.get("notFounds").toString());
 				}
diff --git a/src/main/java/org/olat/group/BusinessGroup.java b/src/main/java/org/olat/group/BusinessGroup.java
index 83b1688f5b3be6c1ebcaa8f466c8a22ddee2ba4b..878b94587cefbab1ca21aa3c01d2ae15a75d3a00 100644
--- a/src/main/java/org/olat/group/BusinessGroup.java
+++ b/src/main/java/org/olat/group/BusinessGroup.java
@@ -144,6 +144,10 @@ public interface BusinessGroup extends BusinessGroupShort, Persistable, CreateIn
 	public boolean isDownloadMembersLists();
 
 	public void setDownloadMembersLists(boolean downloadMembersLists);
+	
+	public boolean isAllowToLeave();
+	
+	public void setAllowToLeave(boolean allow);
 
 	/**
 	 * @return the maximal number of participants
diff --git a/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml b/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
index 24b508e92c083c9ab0c3f2413b2fdfb83964b155..aa5ad79eaca56414561de157fdb11bea4aad1342 100644
--- a/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
+++ b/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
@@ -39,6 +39,7 @@
 		<property name="waitingListVisibleIntern" column="waitingintern" unique="false" not-null="true" type="boolean"/>
 		<property name="waitingListVisiblePublic" column="waitingpublic" unique="false" not-null="true" type="boolean"/>
 		<property name="downloadMembersLists" column="downloadmembers" unique="false" not-null="true" type="boolean"/>
+		<property name="allowToLeave" column="allowtoleave" unique="false" not-null="true" type="boolean"/>
 			 		
 		<property name="name" type="string" column="groupname" unique="false" length="255" index="gp_name_idx"/>	
 		<property name="description" type="string" column="descr" length="16777210" not-null="false"/>
diff --git a/src/main/java/org/olat/group/BusinessGroupImpl.java b/src/main/java/org/olat/group/BusinessGroupImpl.java
index 93b70379b1899991df5e5c29b3aad51fdd7ff5ea..4b0b1040f37c3999153461b1b161ceaac575283c 100644
--- a/src/main/java/org/olat/group/BusinessGroupImpl.java
+++ b/src/main/java/org/olat/group/BusinessGroupImpl.java
@@ -69,6 +69,7 @@ public class BusinessGroupImpl extends PersistentObject implements BusinessGroup
 	private boolean participantsVisiblePublic;
 	private boolean waitingListVisiblePublic;
 	private boolean downloadMembersLists;
+	private boolean allowToLeave;
 
 	/**
 	 * constructs an unitialised BusinessGroup, use setXXX for setting attributes
@@ -205,6 +206,16 @@ public class BusinessGroupImpl extends PersistentObject implements BusinessGroup
 		this.downloadMembersLists = visible;
 	}
 
+	@Override
+	public boolean isAllowToLeave() {
+		return allowToLeave;
+	}
+
+	@Override
+	public void setAllowToLeave(boolean allow) {
+		this.allowToLeave = allow;
+	}
+
 	public OLATResource getResource() {
 		return resource;
 	}
diff --git a/src/main/java/org/olat/group/BusinessGroupModule.java b/src/main/java/org/olat/group/BusinessGroupModule.java
index f1e63c278bce2bcec24d464c6624db64e0228f6e..95d27f3c85284551f42c0d54c063449e99c0c2db 100644
--- a/src/main/java/org/olat/group/BusinessGroupModule.java
+++ b/src/main/java/org/olat/group/BusinessGroupModule.java
@@ -20,13 +20,16 @@
 package org.olat.group;
 
 import org.olat.NewControllerFactory;
-import org.olat.core.configuration.AbstractOLATModule;
-import org.olat.core.configuration.PersistedProperties;
+import org.olat.core.configuration.AbstractSpringModule;
 import org.olat.core.id.Roles;
 import org.olat.core.id.context.SiteContextEntryControllerCreator;
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.group.site.GroupsSite;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
 
 /**
  * Description:<br>
@@ -37,7 +40,8 @@ import org.olat.group.site.GroupsSite;
  * 
  * @author gnaegi
  */
-public class BusinessGroupModule extends AbstractOLATModule {
+@Service("businessGroupModule")
+public class BusinessGroupModule extends AbstractSpringModule {
 
 	public static String ORES_TYPE_GROUP = OresHelper.calculateTypeName(BusinessGroup.class);
 	
@@ -62,39 +66,61 @@ public class BusinessGroupModule extends AbstractOLATModule {
 	private static final String ACCEPT_MEMBERSHIP_GROUPMANAGERS = "acceptMembershipForGroupmanagers";
 	private static final String ACCEPT_MEMBERSHIP_ADMINISTRATORS = "acceptMembershipForAdministrators";
 	
+	private static final String ALLOW_LEAVING_GROUP_BY_LEARNERS = "allowLeavingGroupCreatedByLearners";
+	private static final String ALLOW_LEAVING_GROUP_BY_AUTHORS = "allowLeavingGroupCreatedByAuthors";
+	private static final String ALLOW_LEAVING_GROUP_OVERRIDE = "allowLeavingGroupOverride";
+	
 	private static final String GROUP_MGR_LINK_COURSE_ALLOWED = "groupManagersAllowedToLinkCourses";
 	private static final String RESOURCE_MGR_LINK_GROUP_ALLOWED = "resourceManagersAllowedToLinkGroups";
 	
 	private static final String MANAGED_GROUPS_ENABLED = "managedBusinessGroups";
 	
-
+	@Value("${group.user.create:true}")
 	private boolean userAllowedCreate;
+	@Value("${group.author.create}")
 	private boolean authorAllowedCreate;
+	@Value("${group.userlist.download.default.allowed}")
 	private boolean userListDownloadDefaultAllowed;
+	@Value("${group.card.contact}")
 	private String contactBusinessCard;
 	
+	@Value("${group.mandatory.enrolment.email.users}")
 	private String mandatoryEnrolmentEmailForUsers;
+	@Value("${group.mandatory.enrolment.email.authors}")
 	private String mandatoryEnrolmentEmailForAuthors;
+	@Value("${group.mandatory.enrolment.email.usermanagers}")
 	private String mandatoryEnrolmentEmailForUsermanagers;
+	@Value("${group.mandatory.enrolment.email.groupmanagers}")
 	private String mandatoryEnrolmentEmailForGroupmanagers;
+	@Value("${group.mandatory.enrolment.email.administrators}")
 	private String mandatoryEnrolmentEmailForAdministrators;
-	
+
+	@Value("${group.accept.membership.users}")
 	private String acceptMembershipForUsers;
+	@Value("${group.accept.membership.authors}")
 	private String acceptMembershipForAuthors;
+	@Value("${group.accept.membership.usermanagers}")
 	private String acceptMembershipForUsermanagers;
+	@Value("${group.accept.membership.groupmanagers}")
 	private String acceptMembershipForGroupmanagers;
+	@Value("${group.accept.membership.administrators}")
 	private String acceptMembershipForAdministrators;
 	
+	@Value("${group.leaving.group.created.by.learners:true}")
+	private boolean allowLeavingGroupCreatedByLearners;
+	@Value("${group.leaving.group.created.by.authors:true}")
+	private boolean allowLeavingGroupCreatedByAuthors;
+	@Value("${group.leaving.group.override:true}")
+	private boolean allowLeavingGroupOverride;
+
 	private boolean groupManagersAllowedToLinkCourses;
 	private boolean resourceManagersAllowedToLinkGroups;
-	
+	@Value("${group.managed}")
 	private boolean managedBusinessGroups;
 
-	/**
-	 * [used by spring]
-	 */
-	private BusinessGroupModule() {
-		//
+	@Autowired
+	public BusinessGroupModule(CoordinatorManager coordinatorManager) {
+		super(coordinatorManager);
 	}
 
 	/**
@@ -113,34 +139,6 @@ public class BusinessGroupModule extends AbstractOLATModule {
 		updateProperties();
 	}
 
-	/**
-	 * @see org.olat.core.configuration.AbstractOLATModule#initDefaultProperties()
-	 */
-	@Override
-	protected void initDefaultProperties() {
-		userAllowedCreate = getBooleanConfigParameter(USER_ALLOW_CREATE_BG, true);
-		authorAllowedCreate = getBooleanConfigParameter(AUTHOR_ALLOW_CREATE_BG, true);
-		contactBusinessCard = getStringConfigParameter(CONTACT_BUSINESS_CARD, CONTACT_BUSINESS_CARD_NEVER, true);
-		userListDownloadDefaultAllowed = getBooleanConfigParameter(USER_LIST_DOWNLOAD, true);
-		
-		mandatoryEnrolmentEmailForUsers = getStringConfigParameter(MANDATORY_ENROLMENT_EMAIL_USERS, "false", true);
-		mandatoryEnrolmentEmailForAuthors = getStringConfigParameter(MANDATORY_ENROLMENT_EMAIL_AUTHORS, "false", true);
-		mandatoryEnrolmentEmailForUsermanagers = getStringConfigParameter(MANDATORY_ENROLMENT_EMAIL_USERMANAGERS, "false", true);
-		mandatoryEnrolmentEmailForGroupmanagers = getStringConfigParameter(MANDATORY_ENROLMENT_EMAIL_GROUPMANAGERS, "false", true);
-		mandatoryEnrolmentEmailForAdministrators = getStringConfigParameter(MANDATORY_ENROLMENT_EMAIL_ADMINISTRATORS, "false", true);
-		
-		acceptMembershipForUsers = getStringConfigParameter(ACCEPT_MEMBERSHIP_USERS, "false", true);
-		acceptMembershipForAuthors = getStringConfigParameter(ACCEPT_MEMBERSHIP_AUTHORS, "false", true);
-		acceptMembershipForUsermanagers = getStringConfigParameter(ACCEPT_MEMBERSHIP_USERMANAGERS, "false", true);
-		acceptMembershipForGroupmanagers = getStringConfigParameter(ACCEPT_MEMBERSHIP_GROUPMANAGERS, "false", true);
-		acceptMembershipForAdministrators = getStringConfigParameter(ACCEPT_MEMBERSHIP_ADMINISTRATORS, "false", true);
-		
-		groupManagersAllowedToLinkCourses = getBooleanConfigParameter(GROUP_MGR_LINK_COURSE_ALLOWED, false);
-		resourceManagersAllowedToLinkGroups = getBooleanConfigParameter(RESOURCE_MGR_LINK_GROUP_ALLOWED, false);
-		
-		managedBusinessGroups = getBooleanConfigParameter(MANAGED_GROUPS_ENABLED, false);
-	}
-
 	@Override
 	protected void initFromChangedProperties() {
 		updateProperties();
@@ -218,17 +216,25 @@ public class BusinessGroupModule extends AbstractOLATModule {
 			resourceManagersAllowedToLinkGroups = "true".equals(linkGroupAllowed);
 		}
 		
+		String allowLeavingIfCreatedByLearners = getStringPropertyValue(ALLOW_LEAVING_GROUP_BY_LEARNERS, true);
+		if(StringHelper.containsNonWhitespace(allowLeavingIfCreatedByLearners)) {
+			allowLeavingGroupCreatedByLearners = "true".equals(allowLeavingIfCreatedByLearners);
+		}
+		String allowLeavingIfCreatedByAuthors = getStringPropertyValue(ALLOW_LEAVING_GROUP_BY_AUTHORS, true);
+		if(StringHelper.containsNonWhitespace(allowLeavingIfCreatedByAuthors)) {
+			allowLeavingGroupCreatedByAuthors = "true".equals(allowLeavingIfCreatedByAuthors);
+		}
+		String allowLeavingOverride = getStringPropertyValue(ALLOW_LEAVING_GROUP_OVERRIDE, true);
+		if(StringHelper.containsNonWhitespace(allowLeavingOverride)) {
+			allowLeavingGroupOverride = "true".equals(allowLeavingOverride);
+		}
+		
 		String managedGroups = getStringPropertyValue(MANAGED_GROUPS_ENABLED, true);
 		if(StringHelper.containsNonWhitespace(managedGroups)) {
 			managedBusinessGroups = "true".equals(managedGroups);
 		}
 	}
-	
-	@Override
-	public void setPersistedProperties(PersistedProperties persistedProperties) {
-		this.moduleConfigProperties = persistedProperties;
-	}
-	
+
 	public boolean isAllowedCreate(Roles roles) {
 		if(roles.isOLATAdmin() || roles.isGroupManager()
 				|| (roles.isAuthor() && isAuthorAllowedCreate())
@@ -406,6 +412,33 @@ public class BusinessGroupModule extends AbstractOLATModule {
 		setStringProperty(RESOURCE_MGR_LINK_GROUP_ALLOWED, Boolean.toString(enabled), true);
 	}
 
+	public boolean isAllowLeavingGroupCreatedByLearners() {
+		return allowLeavingGroupCreatedByLearners;
+	}
+
+	public void setAllowLeavingGroupCreatedByLearners(boolean allow) {
+		this.allowLeavingGroupCreatedByLearners = allow;
+		setStringProperty(ALLOW_LEAVING_GROUP_BY_LEARNERS, Boolean.toString(allow), true);
+	}
+
+	public boolean isAllowLeavingGroupCreatedByAuthors() {
+		return allowLeavingGroupCreatedByAuthors;
+	}
+
+	public void setAllowLeavingGroupCreatedByAuthors(boolean allow) {
+		this.allowLeavingGroupCreatedByAuthors = allow;
+		setStringProperty(ALLOW_LEAVING_GROUP_BY_AUTHORS, Boolean.toString(allow), true);
+	}
+
+	public boolean isAllowLeavingGroupOverride() {
+		return allowLeavingGroupOverride;
+	}
+
+	public void setAllowLeavingGroupOverride(boolean allow) {
+		this.allowLeavingGroupOverride = allow;
+		setStringProperty(ALLOW_LEAVING_GROUP_OVERRIDE, Boolean.toString(allow), true);
+	}
+
 	public boolean isManagedBusinessGroups() {
 		return managedBusinessGroups;
 	}
diff --git a/src/main/java/org/olat/group/BusinessGroupService.java b/src/main/java/org/olat/group/BusinessGroupService.java
index 6c87806a5ee8f3c48e10acacb895c9ace449886c..2eb49b61e936b5001697466daa6f3294fcb3e88d 100644
--- a/src/main/java/org/olat/group/BusinessGroupService.java
+++ b/src/main/java/org/olat/group/BusinessGroupService.java
@@ -36,6 +36,7 @@ import org.olat.group.model.BGRepositoryEntryRelation;
 import org.olat.group.model.BusinessGroupEnvironment;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.model.EnrollState;
+import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.repository.RepositoryEntry;
@@ -119,6 +120,8 @@ public interface BusinessGroupService {
 			boolean ownersPublis, boolean participantsPublic, boolean waitingListPublic,
 			boolean download);
 	
+	public BusinessGroup updateAllowToLeaveBusinessGroup(BusinessGroup group, boolean allowLeaving);
+	
 	/**
 	 * Delete a business group from the persistence store
 	 * @param group
@@ -409,6 +412,9 @@ public interface BusinessGroupService {
 	
 	public void cancelPendingParticipation(Identity ureqIdentity, ResourceReservation reservation);
 	
+	
+	public LeaveOption isAllowToLeaveBusinessGroup(Identity identity, BusinessGroup group);
+	
 	/**
 	 * Remove a list of users from a group as participant and does all the magic that needs
 	 * to be done:
diff --git a/src/main/java/org/olat/group/_spring/businessGroupContext.xml b/src/main/java/org/olat/group/_spring/businessGroupContext.xml
index 46fcc3c6fad886ca1f7389017e5c3308e55d6fec..db4d8ee22dcd8d238e3afec793c1b4619b40ba8e 100644
--- a/src/main/java/org/olat/group/_spring/businessGroupContext.xml
+++ b/src/main/java/org/olat/group/_spring/businessGroupContext.xml
@@ -8,47 +8,7 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context.xsd">
 
-	<context:component-scan base-package="org.olat.group.manager,org.olat.group.area,org.olat.group.right" />
-
-	<bean id="businessGroupModule" class="org.olat.group.BusinessGroupModule" init-method="init">
-		<property name="persistedProperties">
-	  		<bean class="org.olat.core.configuration.PersistedProperties" scope="prototype" init-method="init" destroy-method="destroy" 
-	  				depends-on="coordinatorManager,org.olat.core.util.WebappHelper">
-	    		<constructor-arg index="0" ref="coordinatorManager"/>
-	    		<constructor-arg index="1" ref="businessGroupModule" />
-	  		</bean>
-		</property>
-	</bean>
-	
-	<!-- default configuration -->
-	<bean  class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
-		<property name="targetObject" ref="businessGroupModule" />
-		<property name="targetMethod" value="init" />
-		<property name="arguments">
-			<value>
-				user.allowed.create=${group.user.create}
-				author.allowed.create=${group.author.create}
-				<!-- Show the contact form in the business group card.
-				     Values are: never,always,groupconfig -->
-				contact.business.card=${group.card.contact}
-				userlist.download.default.allowed=${group.userlist.download.default.allowed}
-
-				mandatoryEnrolmentEmailForUsers=${group.mandatory.enrolment.email.users}
-				mandatoryEnrolmentEmailForAuthors=${group.mandatory.enrolment.email.authors}
-				mandatoryEnrolmentEmailForUsermanagers=${group.mandatory.enrolment.email.usermanagers}
-				mandatoryEnrolmentEmailForGroupmanagers=${group.mandatory.enrolment.email.groupmanagers}
-				mandatoryEnrolmentEmailForAdministrators=${group.mandatory.enrolment.email.administrators}
-
-				acceptMembershipForUsers=${group.accept.membership.users}
-				acceptMembershipForAuthors=${group.accept.membership.authors}
-				acceptMembershipForUsermanagers=${group.accept.membership.usermanagers}
-				acceptMembershipForGroupmanagers=${group.accept.membership.groupmanagers}
-				acceptMembershipForAdministrators=${group.accept.membership.administrators}
-				
-				managedBusinessGroups=${group.managed}
-			</value>
-		</property>
-	</bean>
+	<context:component-scan base-package="org.olat.group" />
 	
 	<!-- Login interceptor -->
 	<bean id="reservation.AfterLogin.Injection" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
index d2b68ec92ced6043ddfea471889ff36d967696e4..3560cea0024f811560af588411e4de8d2c02793b 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
@@ -41,10 +41,12 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.commons.services.mark.impl.MarkImpl;
 import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
 import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupImpl;
 import org.olat.group.BusinessGroupMembership;
+import org.olat.group.BusinessGroupModule;
 import org.olat.group.BusinessGroupOrder;
 import org.olat.group.BusinessGroupShort;
 import org.olat.group.BusinessGroupView;
@@ -76,11 +78,13 @@ public class BusinessGroupDAO {
 	@Autowired
 	private GroupDAO groupDao;
 	@Autowired
-	private BusinessGroupRelationDAO businessGroupRelationDao;
-	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
 	private OLATResourceManager olatResourceManager;
+	@Autowired
+	private BusinessGroupModule businessGroupModule;
+	@Autowired
+	private BusinessGroupRelationDAO businessGroupRelationDao;
 	
 	public BusinessGroup createAndPersist(Identity creator, String name, String description,
 			Integer minParticipants, Integer maxParticipants, boolean waitingListEnabled, boolean autoCloseRanksEnabled,
@@ -118,6 +122,17 @@ public class BusinessGroupDAO {
 		businessgroup.setWaitingListVisiblePublic(false);
 		businessgroup.setDownloadMembersLists(false);
 		
+		if(creator == null) {
+			businessgroup.setAllowToLeave(businessGroupModule.isAllowLeavingGroupCreatedByAuthors());
+		} else {
+			Roles roles = securityManager.getRoles(creator);
+			if(roles.isAuthor()) {
+				businessgroup.setAllowToLeave(businessGroupModule.isAllowLeavingGroupCreatedByAuthors());
+			} else {
+				businessgroup.setAllowToLeave(businessGroupModule.isAllowLeavingGroupCreatedByLearners());
+			}
+		}
+		
 		businessgroup.setWaitingListEnabled(waitingListEnabled);
 		businessgroup.setAutoCloseRanksEnabled(autoCloseRanksEnabled);
 
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java
index e7159c4454a5b2cf9c62c4950d0683f743e84923..1aaa48a646a8a417cfd1fd57771759f8d3f466e4 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java
@@ -27,9 +27,12 @@ import java.util.List;
 
 import javax.persistence.TypedQuery;
 
+import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.Group;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.IdentityRef;
+import org.olat.basesecurity.NamedGroupImpl;
+import org.olat.basesecurity.SecurityGroupMembershipImpl;
 import org.olat.basesecurity.manager.GroupDAO;
 import org.olat.basesecurity.model.GroupMembershipImpl;
 import org.olat.core.commons.persistence.DB;
@@ -135,6 +138,29 @@ public class BusinessGroupRelationDAO {
 		return count == null ? 0 : count.intValue();
 	}
 	
+	/**
+	 * Return the number of coaches with author rights.
+	 * @param group
+	 * @return
+	 */
+	public int countAuthors(BusinessGroup group) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select count(membership) from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		  .append(" inner join bgroup.baseGroup as baseGroup")
+		  .append(" inner join baseGroup.members as membership")
+		  .append(" where bgroup.key=:businessGroupKey and membership.role='").append(GroupRoles.coach.name()).append("'")
+		  .append(" and exists (")
+		  .append("   select sgmsi from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi, ").append(NamedGroupImpl.class.getName()).append(" as ngroup ")
+		  .append("     where sgmsi.identity=membership.identity and sgmsi.securityGroup=ngroup.securityGroup")
+		  .append("     and ngroup.groupName in ('").append(Constants.GROUP_AUTHORS).append("')")
+		  .append(" )");
+	
+		Number count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
+				.setParameter("businessGroupKey", group.getKey())
+				.getSingleResult();
+		return count == null ? 0 : count.intValue();
+	}
+	
 	/**
 	 * Match the list of roles with the list of specfified roles
 	 * @param identity
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
index df2c6e629739638179cb286b40e02697c1e3c317..ae5585e2ce85006e9baee65e176c23cc23e90364 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
@@ -42,6 +42,7 @@ import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.Group;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.IdentityRef;
+import org.olat.basesecurity.SecurityGroup;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.collaboration.CollaborationToolsFactory;
 import org.olat.core.CoreSpringFactory;
@@ -58,6 +59,7 @@ import org.olat.core.logging.activity.ActionType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.async.ProgressDelegate;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailContext;
 import org.olat.core.util.mail.MailContextImpl;
@@ -92,6 +94,7 @@ import org.olat.group.model.BusinessGroupMembershipViewImpl;
 import org.olat.group.model.BusinessGroupMembershipsChanges;
 import org.olat.group.model.EnrollState;
 import org.olat.group.model.IdentityGroupKey;
+import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.group.right.BGRightManager;
@@ -104,6 +107,7 @@ import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryEntryRelationType;
 import org.olat.repository.RepositoryEntryShort;
 import org.olat.repository.RepositoryManager;
+import org.olat.repository.RepositoryService;
 import org.olat.repository.manager.RepositoryEntryRelationDAO;
 import org.olat.repository.model.RepositoryEntryToGroupRelation;
 import org.olat.repository.model.SearchRepositoryEntryParameters;
@@ -133,6 +137,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	@Autowired
 	private BusinessGroupDAO businessGroupDAO;
 	@Autowired
+	private RepositoryService repositoryService;
+	@Autowired
 	private RepositoryManager repositoryManager;
 	@Autowired
 	private PropertyManager propertyManager;
@@ -307,6 +313,20 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		return mergedGroup;
 	}
 
+	@Override
+	public BusinessGroup updateAllowToLeaveBusinessGroup(BusinessGroup group, boolean allow) {
+		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey());
+		BusinessGroup mergedGroup = null;
+		if(reloadedBusinessGroup != null) {
+			reloadedBusinessGroup.setAllowToLeave(allow);
+			mergedGroup = businessGroupDAO.merge(reloadedBusinessGroup);
+			//prevent lazy loading issues
+			mergedGroup.getBaseGroup().getKey();
+		}
+		dbInstance.commit();
+		return mergedGroup;
+	}
+
 	@Override
 	public BusinessGroup setLastUsageFor(final Identity identity, final BusinessGroup group) {
 		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey());
@@ -995,6 +1015,84 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		}
 	}
 	
+	@Override
+	public LeaveOption isAllowToLeaveBusinessGroup(Identity identity, BusinessGroup group) {
+		LeaveOption opt;
+		if(groupModule.isAllowLeavingGroupOverride()) {
+			if(group.isAllowToLeave()) {
+				opt = new LeaveOption();
+			} else {
+				ContactList list = getAdminContactList(group);
+				opt = new LeaveOption(false, list);
+			}
+		} else if(groupModule.isAllowLeavingGroupCreatedByAuthors() && groupModule.isAllowLeavingGroupCreatedByLearners()) {
+			opt = new LeaveOption();
+		} else if(!groupModule.isAllowLeavingGroupCreatedByAuthors() && !groupModule.isAllowLeavingGroupCreatedByLearners()) {
+			ContactList list = getAdminContactList(group);
+			opt = new LeaveOption(false, list);
+		} else {
+			int numOfCoaches = countMembers(group, GroupRoles.coach.name());
+			if(numOfCoaches == 0) {
+				int numOfResources = businessGroupRelationDAO.countResources(group);
+				if(numOfResources > 0) {
+					//author group
+					if(groupModule.isAllowLeavingGroupCreatedByAuthors()) {
+						opt = new LeaveOption();
+					} else {
+						ContactList list = getAdminContactList(group);
+						opt = new LeaveOption(false, list);
+					}
+
+				//learner group
+				} else if(groupModule.isAllowLeavingGroupCreatedByLearners()) {
+					opt = new LeaveOption();
+				} else {
+					ContactList list = getAdminContactList(group);
+					opt = new LeaveOption(false, list);
+				}
+			} else {
+				int numOfAuthors = businessGroupRelationDAO.countAuthors(group);
+				if(numOfAuthors > 0) {
+					if(groupModule.isAllowLeavingGroupCreatedByAuthors()) {
+						opt = new LeaveOption();
+					} else {
+						ContactList list = getAdminContactList(group);
+						opt = new LeaveOption(false, list);
+					}
+				} else if(groupModule.isAllowLeavingGroupCreatedByLearners()) {
+					opt = new LeaveOption();
+				} else {
+					ContactList list = getAdminContactList(group);
+					opt = new LeaveOption(false, list);
+				}	
+			}
+		}
+		return opt;
+	}
+	
+	public ContactList getAdminContactList(BusinessGroup group) {
+		ContactList list = new ContactList("Contact");
+		List<Identity> coaches = getMembers(group, GroupRoles.coach.name());
+		if(coaches.isEmpty()) {
+			Collection<BusinessGroup> groups = Collections.singletonList(group);
+			List<RepositoryEntry> entries = businessGroupRelationDAO.findRepositoryEntries(groups, 0, -1);
+			for(RepositoryEntry re:entries) {
+				coaches.addAll(repositoryService.getMembers(re, GroupRoles.coach.name()));
+			}
+			
+			if(coaches.isEmpty()) {
+				//get system administrators
+				SecurityGroup adminSecGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ADMIN);
+				List<Identity> admins = securityManager.getIdentitiesByPowerSearch(null, null, false, new SecurityGroup[]{ adminSecGroup },
+						null, null, null, null, null, null, Identity.STATUS_VISIBLE_LIMIT);
+				coaches.addAll(admins);
+			}
+		}
+		
+		list.addAllIdentites(coaches);
+		return list;
+	}
+
 	@Override
 	public void removeParticipants(Identity ureqIdentity, List<Identity> identities, BusinessGroup group, MailPackage mailing) {
 		group = businessGroupDAO.loadForUpdate(group.getKey());
@@ -1219,6 +1317,9 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 				response.getAddedIdentities().add(identity);
 				// notification mail is handled in controller
 			} else {
+				if (businessGroupRelationDAO.hasRole(identity, currBusinessGroup, GroupRoles.waiting.name()) ) {
+					removeFromWaitingList(ureqIdentity, identity, currBusinessGroup, mailing, events);
+				}
 				response.getIdentitiesAlreadyInGroup().add(identity);
 			}
 		}
diff --git a/src/main/java/org/olat/group/model/LeaveOption.java b/src/main/java/org/olat/group/model/LeaveOption.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebe3b6f7b6cf1797fb39f5ad26731aea306642f2
--- /dev/null
+++ b/src/main/java/org/olat/group/model/LeaveOption.java
@@ -0,0 +1,52 @@
+/**
+ * <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.group.model;
+
+import org.olat.core.util.mail.ContactList;
+
+/**
+ * 
+ * Initial date: 31.10.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class LeaveOption {
+	
+	private final boolean allowToLeave;
+	private final ContactList contacts;
+	
+	public LeaveOption() {
+		 this(true, null);
+	}
+	
+	public LeaveOption(boolean allowToLeave, ContactList contacts) {
+		this.allowToLeave = allowToLeave;
+		this.contacts = contacts;
+		 
+	}
+
+	public boolean isAllowToLeave() {
+		return allowToLeave;
+	}
+
+	public ContactList getContacts() {
+		return contacts;
+	}
+}
diff --git a/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java b/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java
index 8a1e136df547f699584d50c93396443fbf5db87f..5421835659fbd5f5877e1b820592732d6dd28c4f 100644
--- a/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java
+++ b/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java
@@ -78,11 +78,11 @@ public class SearchBusinessGroupParams {
 		this.tools = tools;
 	}
 	
-	public void addTools(String... tools) {
+	public void addTools(String... toolsToAdd) {
 		if(this.tools == null) {
 			this.tools = new ArrayList<String>();
 		}
-		for(String tool:tools) {
+		for(String tool:toolsToAdd) {
 			this.tools.add(tool);
 		}
 	}
diff --git a/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java b/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java
index ba0466ab2ef462eb5e16fb876b9e2dc9fb127db6..64eadf3db388730bbee42f0fe83ce8e3924cd29a 100644
--- a/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java
+++ b/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java
@@ -55,6 +55,7 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 	private MultipleSelectionElement membershipEl;
 	private MultipleSelectionElement assignCoursesEl;
 	private MultipleSelectionElement assignGroupsEl;
+	private MultipleSelectionElement allowLeavingGroupsEl;
 
 	private Panel mainPopPanel;
 	private CloseableModalController cmc;
@@ -68,6 +69,10 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 			"users","authors", "usermanagers", "groupmanagers", "administrators"
 	};
 	private String[] assignKeys = new String[]{"granted"};
+	private String[] allowLeavingKeys = new String[]{
+			"groupMadeByLearners", "groupMadeByAuthors", "groupOverride"
+	};
+	
 	
 	public BusinessGroupModuleAdminController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "bg_admin");
@@ -133,7 +138,18 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 		membershipEl.select("groupmanagers", "true".equals(module.getAcceptMembershipForGroupmanagers()));
 		membershipEl.select("administrators", "true".equals(module.getAcceptMembershipForAdministrators()));
 		membershipEl.addActionListener(FormEvent.ONCHANGE);
-
+		
+		String[] allowLeavingValues = new String[]{
+				translate("leaving.group.learners"),
+				translate("leaving.group.authors"),
+				translate("leaving.group.override"),
+		};
+		allowLeavingGroupsEl = uifactory.addCheckboxesVertical("leaving.group", privacyOptionsContainer, allowLeavingKeys, allowLeavingValues, 1);
+		allowLeavingGroupsEl.select("groupMadeByLearners", module.isAllowLeavingGroupCreatedByLearners());
+		allowLeavingGroupsEl.select("groupMadeByAuthors", module.isAllowLeavingGroupCreatedByAuthors());
+		allowLeavingGroupsEl.select("groupOverride", module.isAllowLeavingGroupOverride());
+		allowLeavingGroupsEl.addActionListener(FormEvent.ONCHANGE);
+				
 		FormLayoutContainer dedupCont = FormLayoutContainer.createDefaultFormLayout("dedup", getTranslator());
 		formLayout.add(dedupCont);
 		dedupLink = uifactory.addFormLink("dedup.members", dedupCont, Link.BUTTON);
@@ -169,8 +185,6 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 		dedupCtrl = null;
 		cmc = null;
 	}
-	
-	
 
 	@Override
 	public void setMax(float max) {
@@ -220,6 +234,11 @@ public class BusinessGroupModuleAdminController extends FormBasicController impl
 			module.setMandatoryEnrolmentEmailForUsermanagers(enrolmentSelectedKeys.contains("usermanagers") ? "true" : "false");
 			module.setMandatoryEnrolmentEmailForGroupmanagers(enrolmentSelectedKeys.contains("groupmanagers") ? "true" : "false");
 			module.setMandatoryEnrolmentEmailForAdministrators(enrolmentSelectedKeys.contains("administrators") ? "true" : "false");
+		} else if(source == allowLeavingGroupsEl) {
+			Collection<String> leavingSelectedKeys = allowLeavingGroupsEl.getSelectedKeys();
+			module.setAllowLeavingGroupCreatedByLearners(leavingSelectedKeys.contains("groupMadeByLearners"));
+			module.setAllowLeavingGroupCreatedByAuthors(leavingSelectedKeys.contains("groupMadeByAuthors"));
+			module.setAllowLeavingGroupOverride(leavingSelectedKeys.contains("groupOverride"));
 		} else if(assignCoursesEl == source) {
 			module.setGroupManagersAllowedToLinkCourses(assignCoursesEl.isSelected(0));
 		} else if(assignGroupsEl == source) {
diff --git a/src/main/java/org/olat/group/ui/BusinessGroupTableModelWithMaxSize.java b/src/main/java/org/olat/group/ui/BusinessGroupTableModelWithMaxSize.java
index fd0df7c334f99fb53d5d4e9c09161ee4deaad7db..1e35c34fa733d57ebea89f700dc94eadb0aed857 100644
--- a/src/main/java/org/olat/group/ui/BusinessGroupTableModelWithMaxSize.java
+++ b/src/main/java/org/olat/group/ui/BusinessGroupTableModelWithMaxSize.java
@@ -187,12 +187,12 @@ public class BusinessGroupTableModelWithMaxSize extends DefaultTableDataModel<Bu
 	/**
 	 * Check if an identity is in certain security-group.
 	 * @param businessGroup
-	 * @param identity
+	 * @param ident
 	 * @return true: Found identity in PartipiciantGroup or WaitingGroup.
 	 */
-	private boolean isEnrolledIn(BusinessGroup businessGroup, Identity identity) {
-		if (businessGroupService.hasRoles(identity, businessGroup, GroupRoles.participant.name())
-				|| businessGroupService.hasRoles(identity, businessGroup, GroupRoles.waiting.name())) {
+	private boolean isEnrolledIn(BusinessGroup businessGroup, Identity ident) {
+		if (businessGroupService.hasRoles(ident, businessGroup, GroupRoles.participant.name())
+				|| businessGroupService.hasRoles(ident, businessGroup, GroupRoles.waiting.name())) {
 			return true;
 		} 
 		return false;
@@ -200,13 +200,13 @@ public class BusinessGroupTableModelWithMaxSize extends DefaultTableDataModel<Bu
 	
 	/**
 	 * Check if an identity is in any security-group.
-	 * @param identity
+	 * @param ident
 	 * @return true: Found identity in any security-group of this table model.
 	 */		
-	private boolean isEnrolledInAnyGroup(Identity identity) {
+	private boolean isEnrolledInAnyGroup(Identity ident) {
 		// loop over all business-groups
 		for (BusinessGroup businessGroup:objects) {
-			if (isEnrolledIn(businessGroup, identity) ) {
+			if (isEnrolledIn(businessGroup, ident) ) {
 				return true;
 			}
 		}
diff --git a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties
index 76b4188fd880e99543087e4f83e863e75b296c34..0aefb7956460f0ed015556217ee42193f607a566 100644
--- a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties
@@ -71,6 +71,10 @@ groupsPortlet.no_member=Sie wurden aus dieser Gruppe ausgetragen oder die Gruppe
 groupsPortlet.nogroups=Sie sind in keiner Gruppe
 groupsPortlet.showAll=Alle anzeigen
 groupsPortlet.title=Meine Gruppen
+leaving.group=Members can leave group
+leaving.group.learners=Allow group exit by members of groups created by learners
+leaving.group.authors=Allow group exit by members of groups created by authors
+leaving.group.override=Allow group exit configuration override by author users
 mandatory.enrolment=E-Mail Benachrichtigung erzwungen bei Einladung durch
 mandatory.membership=Best\u00E4tigung Mitgliedschaft erforderlich bei Einladung durch
 membership.administrators=$\:enrolment.email.administrators
diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
index 738504dff40b2ae92a21739896c482f612a149c6..04512361064bb6164426999f62620060c18a447b 100644
--- a/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
+++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupMembersController.java
@@ -59,6 +59,7 @@ public class BusinessGroupMembersController extends BasicController {
 	private final VelocityContainer mainVC;
 
 	private final DisplayMemberSwitchForm dmsForm;
+	private final MembershipConfigurationForm configForm;
 	private MemberListController membersController;
 	private final Link importMemberLink, addMemberLink;
 	private StepsMainRunController importMembersWizard;
@@ -88,6 +89,12 @@ public class BusinessGroupMembersController extends BasicController {
 		dmsForm.setDisplayMembers(businessGroup);
 		mainVC.put("displayMembers", dmsForm.getInitialComponent());
 		
+		configForm = new MembershipConfigurationForm (ureq, getWindowControl());
+		configForm.setEnabled(!BusinessGroupManagedFlag.isManaged(businessGroup, BusinessGroupManagedFlag.membersmanagement));
+		listenTo(configForm);
+		configForm.setMembershipConfiguration(businessGroup);
+		mainVC.put("configMembers", configForm.getInitialComponent());
+		
 		boolean managed = BusinessGroupManagedFlag.isManaged(businessGroup, BusinessGroupManagedFlag.membersmanagement);
 		SearchMembersParams searchParams = new SearchMembersParams(false, false, false, true, true, true, true);
 		membersController = new MemberListController(ureq, getWindowControl(), businessGroup, searchParams);
@@ -127,8 +134,8 @@ public class BusinessGroupMembersController extends BasicController {
 		}
 	}
 	
-	protected void updateBusinessGroup(BusinessGroup businessGroup) {
-		this.businessGroup = businessGroup;
+	protected void updateBusinessGroup(BusinessGroup bGroup) {
+		this.businessGroup = bGroup;
 		
 		boolean hasWaitingList = businessGroup.getWaitingListEnabled().booleanValue();	
 		Boolean waitingFlag = (Boolean)mainVC.getContext().get("hasWaitingGrp");
@@ -162,6 +169,16 @@ public class BusinessGroupMembersController extends BasicController {
 				ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_CONFIGURATION_CHANGED, getClass());
 				fireEvent(ureq, event);
 			}
+		} else if (source == configForm) {
+			if(event == Event.CHANGED_EVENT) {
+				boolean allow = configForm.isAllowToLeaveBusinessGroup();
+				businessGroup = businessGroupService.updateAllowToLeaveBusinessGroup(businessGroup, allow);
+				// notify current active users of this business group
+				BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.CONFIGURATION_MODIFIED_EVENT, businessGroup, null);
+				// do loggin
+				ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_CONFIGURATION_CHANGED, getClass());
+				fireEvent(ureq, event);
+			}
 		} else if(source == importMembersWizard) {
 			if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
 				getWindowControl().pop();
diff --git a/src/main/java/org/olat/group/ui/edit/MembershipConfigurationForm.java b/src/main/java/org/olat/group/ui/edit/MembershipConfigurationForm.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f56f5f4cf6a5c7f8f1cebd89dbee1a11269f5af
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/edit/MembershipConfigurationForm.java
@@ -0,0 +1,107 @@
+/**
+ * <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.group.ui.edit;
+
+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.SelectionElement;
+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.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Roles;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupModule;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 31.10.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MembershipConfigurationForm extends FormBasicController {
+
+	private SelectionElement allowToLeaveEl;
+	
+	@Autowired
+	private BusinessGroupModule businessGroupModule;
+
+	/**
+	 * @param name
+	 * @param transl
+	 * @param hasPartips
+	 * @param hasOwners
+	 */
+	public MembershipConfigurationForm(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, LAYOUT_DEFAULT_6_6);
+		initForm(ureq);
+	}
+	
+	public boolean isAllowToLeaveBusinessGroup() {
+		return allowToLeaveEl.isSelected(0);
+	}
+	
+	public void setMembershipConfiguration(BusinessGroup group) {
+		if(allowToLeaveEl.isEnabled()) {
+			allowToLeaveEl.select("xx", group.isAllowToLeave());
+		}
+	}
+
+	public void setEnabled(boolean enabled) {
+		allowToLeaveEl.setEnabled(enabled);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+	
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(allowToLeaveEl == source) {
+			fireEvent (ureq, Event.CHANGED_EVENT);
+		}
+	}
+	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		allowToLeaveEl = uifactory.addCheckboxesHorizontal("allow.leaving", "allow.leaving.group", formLayout, new String[]{"xx"}, new String[]{""});
+		allowToLeaveEl.addActionListener(FormEvent.ONCLICK);
+		if(businessGroupModule.isAllowLeavingGroupOverride()) {
+			allowToLeaveEl.setEnabled(true);
+		} else {
+			allowToLeaveEl.setEnabled(false);
+			Roles roles = ureq.getUserSession().getRoles();
+			if(roles.isAuthor()) {
+				allowToLeaveEl.select("xx", businessGroupModule.isAllowLeavingGroupCreatedByAuthors());
+			} else {
+				allowToLeaveEl.select("xx", businessGroupModule.isAllowLeavingGroupCreatedByLearners());
+			}
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/edit/_chelp/grp-leaving.html b/src/main/java/org/olat/group/ui/edit/_chelp/grp-leaving.html
new file mode 100644
index 0000000000000000000000000000000000000000..d27dc220d23f994fdf196bd171eb22915749f8bb
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/edit/_chelp/grp-leaving.html
@@ -0,0 +1 @@
+<p>[Placeholder help]</p>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/edit/_content/tab_bgGrpMngmnt.html b/src/main/java/org/olat/group/ui/edit/_content/tab_bgGrpMngmnt.html
index a62ac66784f866d62fc41d3af2dd290c8a4e4ca5..24e84eb2e9e8e08b223ff87732d1771ba1e3a8fa 100644
--- a/src/main/java/org/olat/group/ui/edit/_content/tab_bgGrpMngmnt.html
+++ b/src/main/java/org/olat/group/ui/edit/_content/tab_bgGrpMngmnt.html
@@ -4,6 +4,12 @@
   		$r.translate("fieldset.legend.displaymembers")</legend>
   	$r.render("displayMembers")
 </fieldset>
+<fieldset>
+  	<legend>
+  		$r.contextHelpWithWrapper("org.olat.group.ui.edit","grp-leaving.html","help.hover.allowLeaving")
+  		$r.translate("fieldset.legend.allow.leaving")</legend>
+  	$r.render("configMembers")
+</fieldset>
 <fieldset>
 	<legend>
 		$r.contextHelpWithWrapper("org.olat.group.ui.edit","grp-memberOwner.html","help.hover.bgGrpMngmntOwner")
diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
index cdfcaf89f08b4c71e26fb9d3663e45bde1390c8d..5fa0629031af8b3517edf0a40dbf22a98664c021 100644
--- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
@@ -1,4 +1,5 @@
 #Mon Mar 02 09:54:04 CET 2009
+allow.leaving.group=Teilnehmer können Gruppe austreten
 areachoice.no.areas.admin=Es wurde kein Lernbereich gefunden. Bitte erstellen Sie im Gruppenmanagement einen Lernbereich.
 areachoice.no.areas.owner=Es wurde kein Lernbereich gefunden. Lernbereiche k\u00F6nnen nur von Personen mit Berechtigung f\u00FCr das gesamte Gruppenmanagement erstellt werden.
 chelp.area1=Sofern im Kurs Lerngruppen erstellt worden sind, erscheinen diese im Tab.
@@ -20,6 +21,7 @@ chelp.desc.learn9=Sofern Sie die Anzahl Teilnehmer beschr\u00E4nkt haben, k\u00F
 chelp.grp-assign.title=Gruppe: Rechte zuweisen
 chelp.grp-Area-select-learn.title=Lernbereiche: Lerngruppen zuweisen
 chelp.grp-des.title=$org.olat.group.ui\:LearningGroup: Beschreibung
+chelp.grp-leaving.title=Teilnehmer Konfiguration
 chelp.grp-member.title=$org.olat.group.ui\:LearningGroup: Mitglieder
 chelp.grp-memberOwner.title=$org.olat.group.ui\:LearningGroup: $org.olat.group.ui\:fieldset.legend.groupowners
 chelp.grp-memberParticipants.title=$org.olat.group.ui\:LearningGroup: Teilnehmer
@@ -57,6 +59,7 @@ chelp.tools.learn10=Sie k\u00F6nnen der $org.olat.group.ui\:LearningGroup ein eP
 chelp.tools.learn13=Sie können der Gruppe einen privaten Chatraum zur Verfügung stellen.
 chelp.tools.quota=Der verf\u00FCgbare Speicherplatz betr\u00E4gt 10 MB.
 chelp.tools.title=Konfiguration kollaborativer Werkzeuge
+help.hover.allowLeaving=Hile zur Konfiguration den Teilnehmer
 help.hover.bgArea=Hilfe zur Zuweisung von Lernbereichen zu Gruppe
 help.hover.bgCollabTools=Hilfe zu den kollaborativen Werkzeugen einer Gruppe
 help.hover.bgDetail=Hilfe zur Beschreibung einer Gruppe
@@ -77,6 +80,7 @@ chkBox.open.downloadList=Benutzer d
 cmd.addresource=Kurs hinzuf\u00FCgen
 error.message.locked=Diese Gruppe wird im Moment vom Benutzer {0} ({1}) ver\u00E4ndert und ist daher gesperrt. Bitte versuchen Sie es sp\u00E4ter noch einmal.
 error.msg.send.no.rcps=$org.olat.modules.co\:error.msg.send.no.rcps
+fieldset.legend.allow.leaving=Mitglieder Konfiguration
 fieldset.legend.areas=Zugewiesene Lernbereiche
 fieldset.legend.collabtools=Kollaborative Werkzeuge
 fieldset.legend.details=Details
diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties
index 5844699260ebadd96aa721af2a7c1203a1ecf2e6..d2cdd88c65e68f21d5a8a84f7025e08fac71e705 100644
--- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties
@@ -1,5 +1,6 @@
 #Thu Aug 08 08:49:27 CEST 2013
 add.member=$org.olat.group.ui.main\:add.member
+allow.leaving.group=Members can leave the group
 areachoice.no.areas.admin=No learning areas found. Please create a learning area within your group management.
 areachoice.no.areas.owner=No learning areas found. New learning areas can only be created by users who have access to the entire group management.
 assessment=$org.olat.group.ui.main\:assessment
@@ -22,6 +23,7 @@ chelp.desc.learn9=If you want to limit the number of participants you can nevert
 chelp.grp-Area-select-learn.title=Learning areas\: assign groups
 chelp.grp-assign.title=Group\: assign rights
 chelp.grp-des.title=Group\: description
+chelp.grp-leaving.title=Membership configuration
 chelp.grp-member.title=Group\: members
 chelp.grp-memberOwner.title=Group\: coaches
 chelp.grp-memberParticipants.title=Group\: participants
@@ -74,6 +76,7 @@ edit.member=$org.olat.group.ui.main\:edit.member
 edit.member.groups=$org.olat.group.ui.main\:edit.member.groups
 error.message.locked=This group is being edited by user {0} ({1}) and therefore locked. Please try again later.
 error.msg.send.no.rcps=$org.olat.modules.co\:error.msg.send.no.rcps
+fieldset.legend.allow.leaving=Membership configuration
 fieldset.legend.areas=Assigned learning areas
 fieldset.legend.collabtools=Collaborative tools
 fieldset.legend.details=Details
@@ -93,6 +96,7 @@ group.edit.tab.members=Members
 group.edit.tab.resources=Courses
 group.edit.tab.rights=Rights
 group.edit.title=Edit group <i>{0}</i>
+help.hover.allowLeaving=Help to configure membership
 help.hover.bgArea=Help to assign learning areas to groups
 help.hover.bgCollabTools=Help to use collaborative tools of groups
 help.hover.bgDetail=Help to describe a group
diff --git a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
index f7775b785210c7bffd4496fc7abc9e05f92e72a6..c6612d7117e950e37cf784fd004348c8242507f8 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
@@ -66,11 +66,14 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Roles;
+import org.olat.core.id.UserConstants;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.mail.ContactList;
+import org.olat.core.util.mail.ContactMessage;
 import org.olat.core.util.mail.MailHelper;
 import org.olat.core.util.mail.MailPackage;
 import org.olat.core.util.mail.MailTemplate;
@@ -90,6 +93,7 @@ import org.olat.group.manager.BusinessGroupMailing;
 import org.olat.group.manager.BusinessGroupMailing.MailType;
 import org.olat.group.model.BGRepositoryEntryRelation;
 import org.olat.group.model.BusinessGroupSelectionEvent;
+import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.group.right.BGRightManager;
@@ -104,6 +108,7 @@ import org.olat.group.ui.wizard.BGMailNotificationEditController;
 import org.olat.group.ui.wizard.BGMergeStep;
 import org.olat.group.ui.wizard.BGUserMailTemplate;
 import org.olat.group.ui.wizard.BGUserManagementController;
+import org.olat.modules.co.ContactFormController;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryEntryShort;
@@ -142,6 +147,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	protected FormLink createButton, deleteButton, duplicateButton,
 		configButton, emailButton, usersButton, mergeButton, selectButton;
 	
+	private ContactFormController contactCtrl;
 	private NewBGController groupCreateController;
 	private BGUserManagementController userManagementController;
 	private BGMailNotificationEditController userManagementSendMailController;
@@ -352,9 +358,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 				} else if(TABLE_ACTION_ACCESS.equals(cmd)) {
 					doAccess(ureq, businessGroup);
 				} else if(TABLE_ACTION_LEAVE.equals(cmd)) {
-					String groupName = StringHelper.escapeHtml(businessGroup.getName());
-					leaveDialogBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.leave.text", groupName), leaveDialogBox);
-					leaveDialogBox.setUserObject(businessGroup);
+					doConfirmLeaving(ureq, businessGroup);
 				}
 			}
 		} else if(source == tableEl) {
@@ -378,9 +382,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 				} else if(TABLE_ACTION_EDIT.equals(cmd)) {
 					doEdit(ureq, businessGroup);
 				} else if(TABLE_ACTION_LEAVE.equals(cmd)) {
-					String groupName = StringHelper.escapeHtml(businessGroup.getName());
-					leaveDialogBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.leave.text", groupName), leaveDialogBox);
-					leaveDialogBox.setUserObject(businessGroup);
+					doConfirmLeaving(ureq, businessGroup);
 				} else if (TABLE_ACTION_ACCESS.equals(cmd)) {
 					doAccess(ureq, businessGroup);
 				} else if (TABLE_ACTION_SELECT.equals(cmd)) {
@@ -479,6 +481,9 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 			if(event instanceof SearchEvent) {
 				doSearch(ureq, (SearchEvent)event);
 			}
+		} else if(source == contactCtrl) {
+			cmc.deactivate();
+			cleanUpPopups();
 		} else if (source == cmc) {
 			cleanUpPopups();
 		}
@@ -495,11 +500,13 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 */
 	protected void cleanUpPopups() {
 		removeAsListenerAndDispose(cmc);
+		removeAsListenerAndDispose(contactCtrl);
 		removeAsListenerAndDispose(deleteDialogBox);
 		removeAsListenerAndDispose(groupCreateController);
 		removeAsListenerAndDispose(businessGroupWizard);
 		removeAsListenerAndDispose(leaveDialogBox);
 		cmc = null;
+		contactCtrl = null;
 		leaveDialogBox = null;
 		deleteDialogBox = null;
 		groupCreateController = null;
@@ -536,6 +543,47 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 		NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
 	}
 	
+	private void doConfirmLeaving(UserRequest ureq, BusinessGroup businessGroup) {
+		if (businessGroupService.hasRoles(getIdentity(), businessGroup, GroupRoles.coach.name())
+				|| businessGroupService.hasRoles(getIdentity(), businessGroup, GroupRoles.waiting.name()) ) {
+			doOpenConfirmLeavingDialog(ureq, businessGroup);
+		} else {
+			LeaveOption option = businessGroupService.isAllowToLeaveBusinessGroup(getIdentity(), businessGroup);
+			if(option.isAllowToLeave()) {
+				doOpenConfirmLeavingDialog(ureq, businessGroup);
+			} else {
+				doAskToLeaveGroup(ureq, businessGroup, option.getContacts());
+			}
+		}	
+	}
+	
+	private void doOpenConfirmLeavingDialog(UserRequest ureq, BusinessGroup businessGroup) {
+		String groupName = StringHelper.escapeHtml(businessGroup.getName());
+		leaveDialogBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.leave.text", groupName), leaveDialogBox);
+		leaveDialogBox.setUserObject(businessGroup);
+	}
+	
+	private void doAskToLeaveGroup(UserRequest ureq, BusinessGroup businessGroup, ContactList contacts) {
+		String[] args = new String[]{
+				businessGroup.getName(),
+				businessGroup.getKey().toString(),
+				"",//courses
+				getIdentity().getUser().getProperty(UserConstants.FIRSTNAME, getLocale()),
+				getIdentity().getUser().getProperty(UserConstants.LASTNAME, getLocale())
+		};
+		ContactMessage msg = new ContactMessage(getIdentity());
+		msg.setSubject(translate("request.leaving.subject", args));
+		msg.setBodyText(translate("request.leaving.body", args));
+		msg.addEmailTo(contacts);
+		
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, true, msg);
+		listenTo(contactCtrl);
+		cmc = new CloseableModalController(getWindowControl(), "close", contactCtrl.getInitialComponent(),
+				true, translate("dialog.modal.bg.asktoleave.title"));
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
 	/**
 	 * Removes user from the group as owner and participant. If
 	 * no other owner are found the user won't be removed from the owner group
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index a036ba4606574efde2be71a932553177223cf5bd..33e39333f92b6f586b539905fd201953961829a3 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -525,6 +525,38 @@ public abstract class AbstractMemberListController extends BasicController imple
 			List<Identity> identitiesToGraduate = securityManager.loadIdentityByKeys(identityKeys);
 			businessGroupService.moveIdentityFromWaitingListToParticipant(getIdentity(), identitiesToGraduate,
 					businessGroup, null);
+		} else {
+			Map<Long, BusinessGroup> groupsMap = new HashMap<>();
+			Map<BusinessGroup, List<Identity>> graduatesMap = new HashMap<>();
+			for(MemberView member:members) {
+				List<BusinessGroupShort> groups = member.getGroups();
+				if(groups != null && groups.size() > 0) {
+					Identity memberIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
+					for(BusinessGroupShort group:groups) {
+						if(businessGroupService.hasRoles(memberIdentity, group, GroupRoles.waiting.name())) {
+							BusinessGroup fullGroup = groupsMap.get(group.getKey());
+							if(fullGroup == null) {
+								fullGroup = businessGroupService.loadBusinessGroup(group.getKey());
+								groupsMap.put(group.getKey(), fullGroup);
+							}
+							
+							List<Identity> identitiesToGraduate = graduatesMap.get(fullGroup);
+							if(identitiesToGraduate == null) {
+								 identitiesToGraduate = new ArrayList<>();
+								 graduatesMap.put(fullGroup, identitiesToGraduate);
+							}
+							identitiesToGraduate.add(memberIdentity);
+						}
+					}
+				}
+			}
+			
+			for(Map.Entry<BusinessGroup, List<Identity>> entry:graduatesMap.entrySet()) {
+				BusinessGroup fullGroup = entry.getKey();
+				List<Identity> identitiesToGraduate = entry.getValue();
+				businessGroupService.moveIdentityFromWaitingListToParticipant(getIdentity(), identitiesToGraduate,
+						fullGroup, null);
+			}
 		}
 		reloadModel();
 	}
diff --git a/src/main/java/org/olat/group/ui/main/BGRoleCellRenderer.java b/src/main/java/org/olat/group/ui/main/BGRoleCellRenderer.java
index 97fa9de26a1ffc6a5cf7e3bc8b4f26a1ca26f570..b28f5db756c321326f5977ae5d3d5c53c581533e 100644
--- a/src/main/java/org/olat/group/ui/main/BGRoleCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/BGRoleCellRenderer.java
@@ -38,10 +38,10 @@ import org.olat.group.model.BGMembership;
  */
 public class BGRoleCellRenderer implements CustomCellRenderer, FlexiCellRenderer {
 	
-	private final Translator translator;
+	private final Translator trans;
 	
 	public BGRoleCellRenderer(Locale locale) {
-		translator = Util.createPackageTranslator(BGRoleCellRenderer.class, locale);
+		trans = Util.createPackageTranslator(BGRoleCellRenderer.class, locale);
 	}
 
 	@Override
@@ -62,22 +62,22 @@ public class BGRoleCellRenderer implements CustomCellRenderer, FlexiCellRenderer
 			boolean and = false;
 			if(membership.isOwner()) {
 				and = and(sb, and);
-				sb.append(translator.translate("owned.groups"));
+				sb.append(trans.translate("owned.groups"));
 			}
 			if(membership.isParticipant()) {
 				and = and(sb, and);
-				sb.append(translator.translate("search.attendee"));
+				sb.append(trans.translate("search.attendee"));
 			}
 			if(membership.isWaiting()) {
 				and = and(sb, and);
-				sb.append(translator.translate("search.waiting"));
+				sb.append(trans.translate("search.waiting"));
 			}
 		} else if (val instanceof BGMembership) {
 			BGMembership membership = (BGMembership)val;
 			switch(membership) {
-				case owner: sb.append(translator.translate("owned.groups")); break;
-				case participant: sb.append(translator.translate("search.attendee")); break;
-				case waiting: sb.append(translator.translate("search.waiting")); break;
+				case owner: sb.append(trans.translate("owned.groups")); break;
+				case participant: sb.append(trans.translate("search.attendee")); break;
+				case waiting: sb.append(trans.translate("search.waiting")); break;
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/group/ui/main/EditMembershipController.java b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
index 1fba9b5f90d755f4df2285f3b35c0b5cc7099969..9010e1792891545193d8dd83950e5c6f87900736 100644
--- a/src/main/java/org/olat/group/ui/main/EditMembershipController.java
+++ b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
@@ -29,12 +29,14 @@ import java.util.UUID;
 import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.EscapeMode;
+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.FlexiTableElement;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement.Layout;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 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.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.components.form.flexible.impl.elements.MultipleSelectionElementImpl;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
@@ -157,7 +159,7 @@ public class EditMembershipController extends FormBasicController {
 		loadModel(member);
 	}
 	
-	private void loadModel(Identity member) {
+	private void loadModel(Identity memberToLoad) {
 		RepositoryEntryRef resource = null;
 		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
 		if(repoEntry == null) {
@@ -168,7 +170,7 @@ public class EditMembershipController extends FormBasicController {
 		List<BusinessGroupView> groups = businessGroupService.findBusinessGroupViews(params, resource, 0, -1);
 	
 		boolean defaultMembership = false;
-		if(member == null) {
+		if(memberToLoad == null) {
 			if(repoEntry != null && groups.isEmpty()) {
 				boolean managed = RepositoryEntryManagedFlag.isManaged(repoEntry, RepositoryEntryManagedFlag.membersmanagement);
 				if(!managed) {
@@ -183,13 +185,13 @@ public class EditMembershipController extends FormBasicController {
 		}
 
 		List<Long> businessGroupKeys = PersistenceHelper.toKeys(groups);
-		groupMemberships = member == null ?
-				Collections.<BusinessGroupMembership>emptyList() : businessGroupService.getBusinessGroupMembership(businessGroupKeys, member);
+		groupMemberships = memberToLoad == null ?
+				Collections.<BusinessGroupMembership>emptyList() : businessGroupService.getBusinessGroupMembership(businessGroupKeys, memberToLoad);
 		List<MemberOption> options = new ArrayList<MemberOption>();
 		for(BusinessGroupView group:groups) {
 			boolean managed = BusinessGroupManagedFlag.isManaged(group.getManagedFlags(), BusinessGroupManagedFlag.membersmanagement);
 			MemberOption option = new MemberOption(group);
-			BGPermission bgPermission = PermissionHelper.getPermission(group.getKey(), member, groupMemberships);
+			BGPermission bgPermission = PermissionHelper.getPermission(group.getKey(), memberToLoad, groupMemberships);
 			option.setTutor(createSelection(bgPermission.isTutor(), !managed));
 			option.setParticipant(createSelection(bgPermission.isParticipant() || defaultMembership, !managed));
 			boolean waitingListEnable = !managed && group.getWaitingListEnabled() != null && group.getWaitingListEnabled().booleanValue();
@@ -203,6 +205,7 @@ public class EditMembershipController extends FormBasicController {
 	private MultipleSelectionElement createSelection(boolean selected, boolean enabled) {
 		String name = "cb" + UUID.randomUUID().toString().replace("-", "");
 		MultipleSelectionElement selection = new MultipleSelectionElementImpl(name, Layout.horizontal);
+		selection.addActionListener(FormEvent.ONCHANGE);
 		selection.setKeysAndValues(keys, values);
 		flc.add(name, selection);
 		selection.select(keys[0], selected);
@@ -286,6 +289,30 @@ public class EditMembershipController extends FormBasicController {
 		fireEvent(ureq, Event.CANCELLED_EVENT);
 	}
 
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source instanceof MultipleSelectionElement) {
+			MultipleSelectionElement selectEl = (MultipleSelectionElement)source;
+			if(selectEl.isSelected(0)) {
+				for(MemberOption option:tableDataModel.getObjects()) {
+					if(option.getWaiting() == selectEl) {
+						if(option.getParticipant().isSelected(0)) {
+							option.getParticipant().select(keys[0], false);
+						}
+						if(option.getTutor().isSelected(0)) {
+							option.getTutor().select(keys[0], false);
+						}
+					} else if(option.getParticipant() == selectEl || option.getTutor() == selectEl) {
+						if(option.getWaiting() != null && option.getWaiting().isSelected(0)) {
+							option.getWaiting().select(keys[0], false);
+						}
+					}
+				}
+			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
 	public void collectRepoChanges(MemberPermissionChangeEvent e) {
 		if(repoEntry == null) return;
 		
diff --git a/src/main/java/org/olat/group/ui/main/MemberPermissionChangeEvent.java b/src/main/java/org/olat/group/ui/main/MemberPermissionChangeEvent.java
index d7d7107a5f07856538194ce7778730e9e8c25245..4afaf50497be8035b3fe132445053ba5954397dd 100644
--- a/src/main/java/org/olat/group/ui/main/MemberPermissionChangeEvent.java
+++ b/src/main/java/org/olat/group/ui/main/MemberPermissionChangeEvent.java
@@ -83,15 +83,15 @@ public class MemberPermissionChangeEvent extends RepositoryEntryPermissionChange
 		if(members == null || members.isEmpty()) {
 			return Collections.emptyList();
 		}
-		List<BusinessGroupMembershipChange> groupChanges = getGroupChanges();
-		if(groupChanges == null || groupChanges.isEmpty()) {
+		List<BusinessGroupMembershipChange> grChanges = getGroupChanges();
+		if(grChanges == null || grChanges.isEmpty()) {
 			return Collections.emptyList();
 		}
 		
 		List<BusinessGroupMembershipChange> allModifications = new ArrayList<BusinessGroupMembershipChange>();
-		for(BusinessGroupMembershipChange groupChange:groupChanges) {
+		for(BusinessGroupMembershipChange grChange:grChanges) {
 			for(Identity member:members) {
-				allModifications.add(new BusinessGroupMembershipChange(member, groupChange));
+				allModifications.add(new BusinessGroupMembershipChange(member, grChange));
 			}
 		}
 		return allModifications;
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 b998a3a44b2bb08e1131dd9310c8185ee73734b8..c62240ca6338edcfbe02e4b9bbb8085fe4aa8d2f 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
@@ -17,6 +17,7 @@ dialog.modal.bg.mail.text=Wollen Sie die Mitglieder per Mail benachrichtigen?
 dialog.modal.bg.leave.text=Wenn Sie die Gruppe "{0}" verlassen, haben Sie keinen Zugang mehr.<br/> Wollen Sie die Gruppe wirklich verlassen?
 dialog.modal.bg.remove.text=Wollen Sie wirklich "{0}" aus dieser Gruppe entfernen?
 dialog.modal.bg.send.mail=Wollen Sie die betroffene(n) Person(en) per E-mail benachrichtigen?
+dialog.modal.bg.asktoleave.title=Anfrage Gruppe zu verlassen
 remove.send.mail=Benachrichtigung
 remove.send.mail.label=E-mail versenden
 error.atleastone=Es muss mindestens einen Besitzer im Kurs geben.
@@ -30,7 +31,8 @@ index.header=Gruppen
 index.intro=In der untenstehenden Liste finden Sie alle Gruppen, an denen Sie teilnehmen. 
 index.table.nogroup=Sie sind in keiner Gruppe eingetragen.
 info.group.deleted=Die Gruppe wurde gel\u00F6scht.
-
+request.leaving.subject=Anfrage Gruppe "{0}" mit ID "{1}" zu verlassen
+request.leaving.body=Sehr geehrter Gruppenbetreuer<br /><br />Ich m\u00F6chte dieser Gruppe verlasse<br /><br />Mit freundliche Grüsse<br />{3} {4}<br />\Gruppename: {0}<br />Gruppe ID:{1}<br />Gruppekurse: {2}
 menu.group.admin=Gruppenverwaltung
 menu.group.admin.alt=Gruppenverwaltung
 menu.index=Gruppen
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
index e790f71b81620c96817e5efea4ed7ead6321ffd4..be71c65f79cf9bb6700974757b408adb3917e80d 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
@@ -36,6 +36,7 @@ dialog.modal.bg.leave.text=If you leave the group "{0}" you will no longer have
 dialog.modal.bg.mail.text=Do you want to inform the members of this group by email?
 dialog.modal.bg.remove.text=Do you really want to remove these persons "{0}" from the group?
 dialog.modal.bg.send.mail=Would you like to notify the respective members?
+dialog.modal.bg.asktoleave.title=Group leaving request
 edit.member=Edit membership
 edit.members=Edit
 edit.member.groups=Group memberships
@@ -90,6 +91,8 @@ owned.groups=Coach
 owned.groups.2=Coached
 pending.reservations=<h4>Accept group and course memberships</h4>You have been invited to the following groups and courses. For each listed groups and courses select the button "$\:accept" or "$\:reject" and finally save your choice with the button "$org.olat.core\:ok". You can safely skip this question now using the button "$org.olat.core\:cancel" and answer them on your next login.
 reject=Reject
+request.leaving.subject=Request to leave group "{0}" (ID {1})
+request.leaving.body=Dear group coach<br /><br />Please remove me from this group.<br /><br />Best regards<br />{3} {4}<br /><br />Group name: {0}<br />Group ID: {1}<br />Group used in course: {2}
 remove.send.mail=Notification
 remove.send.mail.label=Send E-mail
 reservation.coach=as coach
diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
index 7856827eb64d0ca41ebc36d0d3097d955b0c6f0a..00ad6ecfce18d401cb1361a04a2cb830bc4e9424 100644
--- a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
+++ b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
@@ -310,8 +310,6 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		Object wildcard = ureq.getUserSession().getEntry("wild_card_" + businessGroup.getKey());
 		if(wildcard == null) {
 			//check managed
-			//fxdiff VCRP-1,2: access control of resources
-			ACService acService = CoreSpringFactory.getImpl(ACService.class);
 			AccessResult acResult = acService.isAccessible(businessGroup, getIdentity(), false);
 			if(acResult.isAccessible()) {
 				needActivation = false;
diff --git a/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java b/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java
index f44b48d9a20f90f7712b5bb5f23be7f9d17f22ca..48fa728960a6815ff71b9063399fa684fb32d119 100644
--- a/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java
+++ b/src/main/java/org/olat/group/ui/wizard/BGMailTemplateController.java
@@ -96,17 +96,17 @@ public class BGMailTemplateController extends FormBasicController {
 
 	/**
 	 * Update the given templates with the values entered in the form
-	 * @param template 
+	 * @param mailTemplate 
 	 */
-	public void updateTemplateFromForm(MailTemplate template) {
+	public void updateTemplateFromForm(MailTemplate mailTemplate) {
 		if(subjectElem != null) {
-			template.setSubjectTemplate(subjectElem.getValue());
+			mailTemplate.setSubjectTemplate(subjectElem.getValue());
 		}
 		if(bodyElem != null) {
-			template.setBodyTemplate(bodyElem.getValue());
+			mailTemplate.setBodyTemplate(bodyElem.getValue());
 		}
 		if(ccSender != null) {
-			template.setCpfrom(ccSender.isSelected(0));
+			mailTemplate.setCpfrom(ccSender.isSelected(0));
 		}
 	}
 
diff --git a/src/main/java/org/olat/gui/control/OlatTopNavController.java b/src/main/java/org/olat/gui/control/OlatTopNavController.java
index a3cf622d8c6c49fe946d70019dd99608d32c10f6..d7e99327bc1d7c5063f1f3be2d3e8b5ca1b8721d 100644
--- a/src/main/java/org/olat/gui/control/OlatTopNavController.java
+++ b/src/main/java/org/olat/gui/control/OlatTopNavController.java
@@ -30,7 +30,6 @@ import org.olat.admin.user.tools.UserToolsModule;
 import org.olat.core.dispatcher.DispatcherModule;
 import org.olat.core.extensions.ExtManager;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.WindowManager;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
@@ -121,7 +120,7 @@ public class OlatTopNavController extends BasicController {
 		List<Tool> toolSetLinksName = new ArrayList<Tool>();
 		
 		Preferences prefs = ureq.getUserSession().getGuiPreferences();
-		String selectedTools = (String)prefs.get(WindowManager.class, "user-tools");
+		String selectedTools = userToolsModule.getUserTools(prefs);
 		if(!StringHelper.containsNonWhitespace(selectedTools)) {
 			selectedTools = userToolsModule.getDefaultPresetOfUserTools();
 		}
diff --git a/src/main/java/org/olat/gui/control/UserToolsMenuController.java b/src/main/java/org/olat/gui/control/UserToolsMenuController.java
index 731dd94574f4341fac2bc695a1fe500dd907af6f..61e48d9f253e36b0ad79823e3eebc997e74d6161 100644
--- a/src/main/java/org/olat/gui/control/UserToolsMenuController.java
+++ b/src/main/java/org/olat/gui/control/UserToolsMenuController.java
@@ -1,3 +1,22 @@
+/**
+ * <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.gui.control;
 
 import java.util.ArrayList;
@@ -11,7 +30,6 @@ import org.olat.admin.user.tools.UserToolExtension;
 import org.olat.admin.user.tools.UserToolsModule;
 import org.olat.basesecurity.AuthHelper;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.WindowManager;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Disposable;
@@ -60,7 +78,7 @@ public class UserToolsMenuController extends BasicController  {
 		List<String> systemLinksName = new ArrayList<String>();
 		
 		Preferences prefs = ureq.getUserSession().getGuiPreferences();
-		String selectedTools = (String)prefs.get(WindowManager.class, "user-tools");
+		String selectedTools = userToolsModule.getUserTools(prefs);
 		if(!StringHelper.containsNonWhitespace(selectedTools)) {
 			selectedTools = userToolsModule.getDefaultPresetOfUserTools();
 		}
diff --git a/src/main/java/org/olat/gui/control/_content/menu.html b/src/main/java/org/olat/gui/control/_content/menu.html
index 844aa364400604d1e1c71dd2341825ca102b0c80..1a1856dce9c99193dd15a0edb29762995e3efc50 100644
--- a/src/main/java/org/olat/gui/control/_content/menu.html
+++ b/src/main/java/org/olat/gui/control/_content/menu.html
@@ -3,19 +3,25 @@
 	#foreach($search in $searchs)
 	 	<li>$r.render($search)</li>
 	#end
-	<li role="presentation" class="dropdown-header">$r.translate("topnav.my.menu.tools")</li>
-	#foreach($personalTool in $personalTools)
-	 	<li>$r.render($personalTool)</li>
+	#if($personalTools.size() > 0)
+		<li role="presentation" class="dropdown-header">$r.translate("topnav.my.menu.tools")</li>
+		#foreach($personalTool in $personalTools)
+		 	<li>$r.render($personalTool)</li>
+		#end
 	#end
-	<li role="presentation" class="divider"></li>
-	<li role="presentation" class="dropdown-header">$r.translate("topnav.my.menu.configurations")</li>
-	#foreach($config in $configs)
-	 	<li>$r.render($config)</li>
+	#if($configs.size() > 0)
+		<li role="presentation" class="divider"></li>
+		<li role="presentation" class="dropdown-header">$r.translate("topnav.my.menu.configurations")</li>
+		#foreach($config in $configs)
+		 	<li>$r.render($config)</li>
+		#end
 	#end
-	<li role="presentation" class="divider"></li>
-	<li role="presentation" class="dropdown-header">$r.translate("topnav.my.menu.systems")</li>
-	#foreach($system in $systems)
-	 	<li>$r.render($system)</li>
+	#if($systems.size() > 0)
+		<li role="presentation" class="divider"></li>
+		<li role="presentation" class="dropdown-header">$r.translate("topnav.my.menu.systems")</li>
+		#foreach($system in $systems)
+		 	<li>$r.render($system)</li>
+		#end
 	#end
 	<li role="presentation" class="divider"></li>
 	<li>
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_10_1_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_10_1_0.java
new file mode 100644
index 0000000000000000000000000000000000000000..362b86f9207a4c17c76a51ccca9ac146bce2992f
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_10_1_0.java
@@ -0,0 +1,134 @@
+/**
+ * <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.upgrade;
+
+import org.olat.admin.user.tools.UserToolsModule;
+import org.olat.core.commons.persistence.DB;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 27.02.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class OLATUpgrade_10_1_0 extends OLATUpgrade {
+	
+	private static final String TASK_USER_TOOLS = "Upgrade user tools";
+	private static final String VERSION = "OLAT_10.1.0";
+
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private UserToolsModule userToolsModule;
+
+	
+	public OLATUpgrade_10_1_0() {
+		super();
+	}
+
+	@Override
+	public String getVersion() {
+		return VERSION;
+	}
+	
+	@Override
+	public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) {
+		return false;
+	}
+
+	@Override
+	public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) {
+		UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION);
+		if (uhd == null) {
+			// has never been called, initialize
+			uhd = new UpgradeHistoryData();
+		} else if (uhd.isInstallationComplete()) {
+			return false;
+		}
+		
+		boolean allOk = true;
+		allOk &= upgradeUserTools(upgradeManager, uhd);
+
+		
+		uhd.setInstallationComplete(allOk);
+		upgradeManager.setUpgradesHistory(uhd, VERSION);
+		if(allOk) {
+			log.audit("Finished OLATUpgrade_10_1_0 successfully!");
+		} else {
+			log.audit("OLATUpgrade_10_1_0 not finished, try to restart OpenOLAT!");
+		}
+		return allOk;
+	}
+	
+	/**
+	 * Add the static tools to the configurable ones.
+	 * 
+	 * @param upgradeManager
+	 * @param uhd
+	 * @return
+	 */
+	private boolean upgradeUserTools(UpgradeManager upgradeManager, UpgradeHistoryData uhd) {
+		if (!uhd.getBooleanDataValue(TASK_USER_TOOLS)) {
+			try {
+				String tools = userToolsModule.getAvailableUserTools();
+				StringBuilder toolsSb = new StringBuilder(tools);
+				String[] defaultUserTools = new String[]{
+						"org.olat.home.HomeMainController:org.olat.gui.control.PrintUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.gui.control.SearchUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.gui.control.HelpUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.instantMessaging.ui.ImpressumMainController",
+						"org.olat.home.HomeMainController:org.olat.instantMessaging.ui.InstantMessagingMainController"
+				};
+				
+				for(String defaultUserTool:defaultUserTools) {
+					if(toolsSb.indexOf(defaultUserTool) < 0) {
+						if(toolsSb.length() > 0) toolsSb.append(",");
+						toolsSb.append(defaultUserTool);
+					}
+				}
+				userToolsModule.setAvailableUserTools(toolsSb.toString());
+
+				String defPreset = userToolsModule.getDefaultPresetOfUserTools();
+				StringBuilder defPresetSb = new StringBuilder(defPreset);
+				String[] defaultPresets = new String[]{
+						"org.olat.home.HomeMainController:org.olat.gui.control.PrintUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.gui.control.HelpUserToolExtension",
+						"org.olat.home.HomeMainController:org.olat.instantMessaging.ui.ImpressumMainController"
+				};
+				
+				for(String defaultPreset:defaultPresets) {
+					if(defPresetSb.indexOf(defaultPreset) < 0) {
+						if(defPresetSb.length() > 0) defPresetSb.append(",");
+						defPresetSb.append(defaultPreset);
+					}
+				}
+				userToolsModule.setDefaultPresetOfUserTools(defPresetSb.toString());
+
+				uhd.setBooleanDataValue(TASK_USER_TOOLS, false);
+				upgradeManager.setUpgradesHistory(uhd, VERSION);
+			} catch (Exception e) {
+				log.error("", e);
+				return false;
+			}
+		}
+		return true;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
index 6aca92e0cdaa7b9bada90639c955bb86137224c3..1114906de85ac21ecc55ee7871e39ad9c992a788 100644
--- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
@@ -42,6 +42,7 @@
 				<bean id="upgrade_9_4_0" class="org.olat.upgrade.OLATUpgrade_9_4_0"/>
 				<bean id="upgrade_10_0_0" class="org.olat.upgrade.OLATUpgrade_10_0_0"/>
 				<bean id="upgrade_10_0_3" class="org.olat.upgrade.OLATUpgrade_10_0_3"/>
+				<bean id="upgrade_10_1_0" class="org.olat.upgrade.OLATUpgrade_10_1_0"/>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml b/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml
index 32b2b041886bfb473c49f1472f02a37c491dc28d..c70d328087f0559069522a448ca35f1f912923f7 100644
--- a/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml
+++ b/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.hbm.xml
@@ -39,6 +39,7 @@
 		<property name="waitingListVisibleIntern" column="waitingintern" unique="false" not-null="true" type="boolean"/>
 		<property name="waitingListVisiblePublic" column="waitingpublic" unique="false" not-null="true" type="boolean"/>
 		<property name="downloadMembersLists" column="downloadmembers" unique="false" not-null="true" type="boolean"/>
+		<property name="allowToLeave" column="allowtoleave" unique="false" not-null="true" type="boolean"/>
 			 		
 		<property name="name" type="string" column="groupname" unique="false" length="255" index="gp_name_idx"/>	
 		<property name="description" type="string" column="descr" length="16777210" not-null="false"/>
diff --git a/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.java b/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.java
index 5cd15c4c03b1ec3553bea1cb2c292e30f48ecd53..2df40f3c479a31384beef2c7f4d06650f8e7d447 100644
--- a/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.java
+++ b/src/main/java/org/olat/upgrade/model/BusinessGroupUpgrade.java
@@ -76,6 +76,7 @@ public class BusinessGroupUpgrade extends PersistentObject implements BusinessGr
 	private boolean participantsVisiblePublic;
 	private boolean waitingListVisiblePublic;
 	private boolean downloadMembersLists;
+	private boolean allowToLeave;
 
 	/**
 	 * constructs an unitialised BusinessGroup, use setXXX for setting attributes
@@ -209,6 +210,14 @@ public class BusinessGroupUpgrade extends PersistentObject implements BusinessGr
 		this.downloadMembersLists = visible;
 	}
 
+	public boolean isAllowToLeave() {
+		return allowToLeave;
+	}
+
+	public void setAllowToLeave(boolean allow) {
+		this.allowToLeave = allow;
+	}
+
 	public OLATResource getResource() {
 		return resource;
 	}
diff --git a/src/main/java/org/olat/user/ToolsPrefsController.java b/src/main/java/org/olat/user/ToolsPrefsController.java
index dedb09eabf4029aab7381a587fd1d739dd53321f..efe020d08d0f04fb11e85bbc035383614dced28e 100644
--- a/src/main/java/org/olat/user/ToolsPrefsController.java
+++ b/src/main/java/org/olat/user/ToolsPrefsController.java
@@ -28,7 +28,6 @@ import org.olat.admin.user.tools.UserToolExtension;
 import org.olat.admin.user.tools.UserToolsModule;
 import org.olat.core.extensions.ExtManager;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.WindowManager;
 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;
@@ -153,7 +152,7 @@ public class ToolsPrefsController extends FormBasicController {
 	}
 
 	private void initPresetElementUserData() {
-		String selectedTools = (String)prefs.get(WindowManager.class, "user-tools");
+		String selectedTools = userToolsModule.getUserTools(prefs);
 		if(!StringHelper.containsNonWhitespace(selectedTools)) {
 			// use presets when user has not yet any values
 			selectedTools = userToolsModule.getDefaultPresetOfUserTools();
@@ -184,7 +183,6 @@ public class ToolsPrefsController extends FormBasicController {
 		} else {
 			sb.append("none");
 		}
-		prefs.put(WindowManager.class, "user-tools", sb.toString());
-		prefs.save();
+		userToolsModule.setUserTools(prefs, sb.toString());
 	}
 }
diff --git a/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql
index 637bca792d972384a509e26ef3ce47973d68e1a5..19e86cc3ca10add3d0015bfa224d57642e8d8e66 100644
--- a/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql
+++ b/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql
@@ -30,6 +30,9 @@ create index cer_archived_resource_idx on o_cer_certificate (c_archived_resource
 create index cer_uuid_idx on o_cer_certificate (c_uuid);
 
 
+alter table o_gp_business add column allowtoleave boolean default 1;
+
+
 drop view o_qp_item_shared_v;
 drop view o_qp_item_pool_v;
 drop view o_qp_item_author_v;
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 69a7702c136c19e0619d2dfd9b96388915b9312b..1fd3d14d3d80b4d3be0b77100dc6770922cc78e3 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -78,6 +78,7 @@ create table if not exists o_gp_business (
    participantspublic bit not null default 0,
    waitingpublic bit not null default 0,
    downloadmembers bit not null default 0,
+   allowtoleave bit not null default 1,
    fk_resource bigint unique,
    fk_group_id bigint unique,
    primary key (group_id)
diff --git a/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql
index 86f0942f793d7cdb2f2db4828bd4dffd9a647049..c420ed598d37495eb79c08fa5590811bb54debf0 100644
--- a/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql
+++ b/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql
@@ -1,3 +1,38 @@
+create table o_cer_template (
+   id number(20) not null,
+   creationdate date not null,
+   lastmodified date not null,
+   c_name varchar2(256 char) not null,
+   c_path varchar2(1024 char) not null,
+   c_public number default 0 not null,
+   primary key (id)
+);
+
+create table o_cer_certificate (
+   id number(20) not null,
+   creationdate date not null,
+   lastmodified date not null,
+   c_uuid varchar2(36 char) not null,
+   c_name varchar2(256 char) not null,
+   c_path varchar2(1024 char) not null,
+   c_last number default 1 not null,
+   c_archived_resource_id number(20) not null,
+   fk_olatresource number(20),
+   fk_identity number(20) not null,
+   primary key (id)
+);
+
+alter table o_cer_certificate add constraint cer_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
+create index cer_identity_idx on o_cer_certificate (fk_identity);
+alter table o_cer_certificate add constraint cer_to_resource_idx foreign key (fk_olatresource) references o_olatresource (resource_id);
+create index cer_resource_idx on o_cer_certificate (fk_olatresource);
+create index cer_archived_resource_idx on o_cer_certificate (c_archived_resource_id);
+create index cer_uuid_idx on o_cer_certificate (c_uuid);
+
+
+alter table o_gp_business add allowtoleave number default 1 not null;
+
+
 drop view o_qp_item_shared_v;
 drop view o_qp_item_pool_v;
 drop view o_qp_item_author_v;
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index fef80cd1c40ed1146eb6a3c601dcc5c5824dde7d..6c02e56268757b7e7dcc57417926235ba8e5fe88 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -83,6 +83,7 @@ CREATE TABLE o_gp_business (
   participantspublic number default 0 not null,
   waitingpublic number default 0 not null,
   downloadmembers number default 0 not null,
+  allowtoleave number default 1 not null,
   fk_resource number(20),
   fk_group_id number(20),
   CONSTRAINT u_o_gp_business03 UNIQUE (fk_resource),
@@ -1093,6 +1094,30 @@ create table o_as_user_course_infos (
    primary key (id)
 );
 
+create table o_cer_template (
+   id number(20) not null,
+   creationdate date not null,
+   lastmodified date not null,
+   c_name varchar2(256 char) not null,
+   c_path varchar2(1024 char) not null,
+   c_public number default 0 not null,
+   primary key (id)
+);
+
+create table o_cer_certificate (
+   id number(20) not null,
+   creationdate date not null,
+   lastmodified date not null,
+   c_uuid varchar2(36 char) not null,
+   c_name varchar2(256 char) not null,
+   c_path varchar2(1024 char) not null,
+   c_last number default 1 not null,
+   c_archived_resource_id number(20) not null,
+   fk_olatresource number(20),
+   fk_identity number(20) not null,
+   primary key (id)
+);
+
 create table o_im_message (
    id number(20) not null,
    creationdate date,
@@ -2185,6 +2210,14 @@ create index idx_lti_outcome_ident_id_idx on o_lti_outcome (fk_identity_id);
 alter table o_lti_outcome add constraint idx_lti_outcome_rsrc_id foreign key (fk_resource_id) references o_olatresource(resource_id);
 create index idx_lti_outcome_rsrc_id_idx on o_lti_outcome (fk_resource_id);
 
+--certificates
+alter table o_cer_certificate add constraint cer_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
+create index cer_identity_idx on o_cer_certificate (fk_identity);
+alter table o_cer_certificate add constraint cer_to_resource_idx foreign key (fk_olatresource) references o_olatresource (resource_id);
+create index cer_resource_idx on o_cer_certificate (fk_olatresource);
+create index cer_archived_resource_idx on o_cer_certificate (c_archived_resource_id);
+create index cer_uuid_idx on o_cer_certificate (c_uuid);
+
 
 insert into o_stat_lastupdated (until_datetime, lastupdated) values (to_date('1999-01-01', 'YYYY-mm-dd'), to_date('1999-01-01', 'YYYY-mm-dd'));
 insert into hibernate_unique_key values ( 0 );
diff --git a/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql
index 3fb3ab11fd1a2a81e4c4f93cd9b16d7fc26e69fa..1c5827722188f511389b7e0909d7f898491f1825 100644
--- a/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql
+++ b/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql
@@ -30,6 +30,9 @@ create index cer_archived_resource_idx on o_cer_certificate (c_archived_resource
 create index cer_uuid_idx on o_cer_certificate (c_uuid);
 
 
+alter table o_gp_business add column allowtoleave bool not null default true;
+
+
 drop view o_qp_item_shared_v;
 drop view o_qp_item_pool_v;
 drop view o_qp_item_author_v;
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 5479d5704d144b2ffd64c20e0b11383c4acb81e0..daca63302befb76cbb9dd473eac1ae629cb28a26 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -76,6 +76,7 @@ create table o_gp_business (
    participantspublic bool not null default false,
    waitingpublic bool not null default false,
    downloadmembers bool not null default false,
+   allowtoleave bool not null default true,
    fk_resource int8 unique,
    fk_group_id int8 unique,
    primary key (group_id)
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 1821bde5127d4ea11acbe2c5d78809591d19145c..e78a0e233c5459ed0caeab0c20d4fcbbf45a83d0 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -248,6 +248,13 @@ group.accept.membership.usermanagers=false
 group.accept.membership.groupmanagers=false
 group.accept.membership.administrators=false
 
+# Allow leaving groups created by learners
+group.leaving.group.created.by.learners=true
+# Allow leaving groups created by authors
+group.leaving.group.created.by.authors=true
+# Allow configuration of this settoing on a per-groupe base
+group.leaving.group.override=true
+
 #enable managed groups
 group.managed=false
 group.managed.values=true,false
diff --git a/src/test/java/org/olat/group/test/BGRightManagerTest.java b/src/test/java/org/olat/group/test/BGRightManagerTest.java
index e9c2b7d53384187c22183d0828bfd0c226ceff16..5c0b005eae2104f9b048df3ceb3754621a22fdf2 100644
--- a/src/test/java/org/olat/group/test/BGRightManagerTest.java
+++ b/src/test/java/org/olat/group/test/BGRightManagerTest.java
@@ -194,15 +194,15 @@ public class BGRightManagerTest extends OlatTestCase {
 	@Test
 	public void hasBGRightWithResource_tutor_participant() {
 		//create 2 rights for the three identities
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("tp-rights-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("tp-rights-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("tp-rights-" + UUID.randomUUID().toString());
+		Identity identity1 = JunitTestHelper.createAndPersistIdentityAsUser("tp-rights-" + UUID.randomUUID().toString());
+		Identity identity2 = JunitTestHelper.createAndPersistIdentityAsUser("tp-rights-" + UUID.randomUUID().toString());
+		Identity identity3 = JunitTestHelper.createAndPersistIdentityAsUser("tp-rights-" + UUID.randomUUID().toString());
 		RepositoryEntry resource =  JunitTestHelper.createAndPersistRepositoryEntry();
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "tpBGRight", null, -1, -1, false, false, resource);
-		businessGroupRelationDao.addRole(id1, group, GroupRoles.participant.name());
-	    businessGroupRelationDao.addRole(id2, group, GroupRoles.coach.name());
-		businessGroupRelationDao.addRole(id2, group, GroupRoles.participant.name());
-	    businessGroupRelationDao.addRole(id3, group, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(identity1, group, GroupRoles.participant.name());
+	    businessGroupRelationDao.addRole(identity2, group, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(identity2, group, GroupRoles.participant.name());
+	    businessGroupRelationDao.addRole(identity3, group, GroupRoles.coach.name());
 		rightManager.addBGRight("bgr.right1", group, resource.getOlatResource(), BGRightsRole.tutor);
 		rightManager.addBGRight("bgr.right2", group, resource.getOlatResource(), BGRightsRole.participant);
 		dbInstance.commitAndCloseSession();
@@ -216,14 +216,14 @@ public class BGRightManagerTest extends OlatTestCase {
 		Assert.assertEquals("bgr.right2", participantRights.get(0));
 		
 		//id1 -> right2
-		Assert.assertFalse(rightManager.hasBGRight("bgr.right1", id1, resource.getOlatResource()));
-		Assert.assertTrue(rightManager.hasBGRight("bgr.right2", id1, resource.getOlatResource()));
+		Assert.assertFalse(rightManager.hasBGRight("bgr.right1", identity1, resource.getOlatResource()));
+		Assert.assertTrue(rightManager.hasBGRight("bgr.right2", identity1, resource.getOlatResource()));
 		//id2 -> right1 and right2
-		Assert.assertTrue(rightManager.hasBGRight("bgr.right1", id2, resource.getOlatResource()));
-		Assert.assertTrue(rightManager.hasBGRight("bgr.right2", id2, resource.getOlatResource()));
+		Assert.assertTrue(rightManager.hasBGRight("bgr.right1", identity2, resource.getOlatResource()));
+		Assert.assertTrue(rightManager.hasBGRight("bgr.right2", identity2, resource.getOlatResource()));
 		//id3 -> right2
-		Assert.assertTrue(rightManager.hasBGRight("bgr.right1", id3, resource.getOlatResource()));
-		Assert.assertFalse(rightManager.hasBGRight("bgr.right2", id3, resource.getOlatResource()));
+		Assert.assertTrue(rightManager.hasBGRight("bgr.right1", identity3, resource.getOlatResource()));
+		Assert.assertFalse(rightManager.hasBGRight("bgr.right2", identity3, resource.getOlatResource()));
 	}
 	
 	@Test
diff --git a/src/test/java/org/olat/group/test/BusinessGroupRelationDAOTest.java b/src/test/java/org/olat/group/test/BusinessGroupRelationDAOTest.java
index fdcdefcab720cffde314608a9030f987e260f950..b17ff247e7717fff87628af41678c3d88ff739e9 100644
--- a/src/test/java/org/olat/group/test/BusinessGroupRelationDAOTest.java
+++ b/src/test/java/org/olat/group/test/BusinessGroupRelationDAOTest.java
@@ -506,6 +506,19 @@ public class BusinessGroupRelationDAOTest extends OlatTestCase {
 		Assert.assertTrue(participant6.contains(part4));
 	}
 	
+	@Test
+	public void countAuthors() {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("auth-" + UUID.randomUUID().toString());
+		Identity test = JunitTestHelper.createAndPersistIdentityAsRndUser("not-auth");
+		BusinessGroup group = businessGroupDao.createAndPersist(null, "rel-repo", "rel-repo-desc", 0, 10, true, false, false, false, false);
+		businessGroupRelationDao.addRole(author, group, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(test, group, GroupRoles.coach.name());
+		dbInstance.commitAndCloseSession();
+		
+		int numOfAuthors = businessGroupRelationDao.countAuthors(group);
+		Assert.assertEquals(1, numOfAuthors);
+	}
+	
 	@Test
 	public void loadForUpdate() {
 		BusinessGroup group = businessGroupDao.createAndPersist(null, "rel-repo", "rel-repo-desc", 0, 10, true, false, false, false, false);
diff --git a/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java b/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java
index 8a8fd4b18c1341e01cbad32565e27b3cb2cc4e5d..4a3e2d89cdd7bcf64d9c7176b4d061642cc4a982 100644
--- a/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java
+++ b/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java
@@ -24,12 +24,14 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
 import junit.framework.Assert;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.olat.basesecurity.BaseSecurity;
@@ -43,11 +45,14 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.id.User;
+import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.MailPackage;
 import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupModule;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.manager.BusinessGroupRelationDAO;
 import org.olat.group.model.BusinessGroupMembershipChange;
+import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.repository.RepositoryEntry;
@@ -82,6 +87,8 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	@Autowired
 	private BusinessGroupRelationDAO businessGroupRelationDao;
 	@Autowired
+	private BusinessGroupModule businessGroupModule;
+	@Autowired
 	private BusinessGroupService businessGroupService;
 	
 	// Identities for tests
@@ -173,6 +180,13 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 			initialize = true;
 	}
 	
+	@After
+	public void resetBusinessGroupModule() {
+		businessGroupModule.setAllowLeavingGroupCreatedByAuthors(true);
+		businessGroupModule.setAllowLeavingGroupCreatedByLearners(true);
+		businessGroupModule.setAllowLeavingGroupOverride(true);
+	}
+	
 	@Test
 	public void should_service_present() {
 		Assert.assertNotNull(businessGroupService);
@@ -252,24 +266,24 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	@Test
 	public void testUpdateBusinessGroupAndAutoRank_v1() {
 		//create a group with 1 participant and 2 users in waiting list
-		Identity id0 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-0-" + UUID.randomUUID().toString());
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-3-" + UUID.randomUUID().toString());
-		Identity id4 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-4-" + UUID.randomUUID().toString());
+		Identity ident0 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-0-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-3-" + UUID.randomUUID().toString());
+		Identity ident4 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-4-" + UUID.randomUUID().toString());
 
 		RepositoryEntry resource =  JunitTestHelper.createAndPersistRepositoryEntry();
-		BusinessGroup group = businessGroupService.createBusinessGroup(id0, "auto-1", "auto-1-desc", new Integer(0), new Integer(1), true, true, resource);
+		BusinessGroup group = businessGroupService.createBusinessGroup(ident0, "auto-1", "auto-1-desc", new Integer(0), new Integer(1), true, true, resource);
 		Assert.assertNotNull(group);
 
-		businessGroupRelationDao.addRole(id1, group, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id2, group, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id3, group, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id4, group, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident1, group, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident2, group, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident3, group, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident4, group, GroupRoles.waiting.name());
 		dbInstance.commitAndCloseSession();
 
 		//update max participants
-		BusinessGroup updateGroup = businessGroupService.updateBusinessGroup(id0, group, "auto-1", "auto-1-desc", null, null, new Integer(0), new Integer(3));
+		BusinessGroup updateGroup = businessGroupService.updateBusinessGroup(ident0, group, "auto-1", "auto-1-desc", null, null, new Integer(0), new Integer(3));
 		Assert.assertNotNull(updateGroup);
 		dbInstance.commitAndCloseSession();
 		
@@ -277,7 +291,7 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		List<Identity> participants = businessGroupRelationDao.getMembers(group, GroupRoles.participant.name());
 		Assert.assertNotNull(participants);
 		Assert.assertEquals(3, participants.size());
-		Assert.assertTrue(participants.contains(id1));
+		Assert.assertTrue(participants.contains(ident1));
 		
 		List<Identity> waitingList = businessGroupRelationDao.getMembers(group, GroupRoles.waiting.name());
 		Assert.assertNotNull(waitingList);
@@ -287,24 +301,24 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	@Test
 	public void testUpdateBusinessGroupAndAutoRank_v2() {
 		//create a group with 1 participant and 2 users in waiting list
-		Identity id0 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-0-" + UUID.randomUUID().toString());
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-3-" + UUID.randomUUID().toString());
-		Identity id4 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-4-" + UUID.randomUUID().toString());
+		Identity ident0 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-0-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-3-" + UUID.randomUUID().toString());
+		Identity ident4 = JunitTestHelper.createAndPersistIdentityAsUser("grp-auto-4-" + UUID.randomUUID().toString());
 
 		RepositoryEntry resource =  JunitTestHelper.createAndPersistRepositoryEntry();
-		BusinessGroup group = businessGroupService.createBusinessGroup(id0, "auto-1", "auto-1-desc", new Integer(0), new Integer(1), false, false, resource);
+		BusinessGroup group = businessGroupService.createBusinessGroup(ident0, "auto-1", "auto-1-desc", new Integer(0), new Integer(1), false, false, resource);
 		Assert.assertNotNull(group);
 
-		businessGroupRelationDao.addRole(id1, group, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id2, group, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id3, group, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id4, group, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident1, group, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident2, group, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident3, group, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident4, group, GroupRoles.waiting.name());
 		dbInstance.commitAndCloseSession();
 
 		//update max participants
-		BusinessGroup updateGroup = businessGroupService.updateBusinessGroup(id0, group, "auto-1", "auto-1-desc", new Integer(0), new Integer(3), Boolean.TRUE, Boolean.TRUE);
+		BusinessGroup updateGroup = businessGroupService.updateBusinessGroup(ident0, group, "auto-1", "auto-1-desc", new Integer(0), new Integer(3), Boolean.TRUE, Boolean.TRUE);
 		Assert.assertNotNull(updateGroup);
 		dbInstance.commitAndCloseSession();
 		
@@ -312,7 +326,7 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		List<Identity> participants = businessGroupRelationDao.getMembers(group, GroupRoles.participant.name());
 		Assert.assertNotNull(participants);
 		Assert.assertEquals(3, participants.size());
-		Assert.assertTrue(participants.contains(id1));
+		Assert.assertTrue(participants.contains(ident1));
 		
 		List<Identity> waitingList = businessGroupRelationDao.getMembers(group, GroupRoles.waiting.name());
 		Assert.assertNotNull(waitingList);
@@ -352,24 +366,24 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	@Test
 	public void mergeGroups() {
 		//create some identities
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("merge-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("merge-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("merge-3-" + UUID.randomUUID().toString());
-		Identity id4 = JunitTestHelper.createAndPersistIdentityAsUser("merge-4-" + UUID.randomUUID().toString());
-		Identity id5 = JunitTestHelper.createAndPersistIdentityAsUser("merge-5-" + UUID.randomUUID().toString());
-		Identity id6 = JunitTestHelper.createAndPersistIdentityAsUser("merge-6-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("merge-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("merge-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("merge-3-" + UUID.randomUUID().toString());
+		Identity ident4 = JunitTestHelper.createAndPersistIdentityAsUser("merge-4-" + UUID.randomUUID().toString());
+		Identity ident5 = JunitTestHelper.createAndPersistIdentityAsUser("merge-5-" + UUID.randomUUID().toString());
+		Identity ident6 = JunitTestHelper.createAndPersistIdentityAsUser("merge-6-" + UUID.randomUUID().toString());
 		//create groups and memberships
 		BusinessGroup g1 = businessGroupService.createBusinessGroup(null, "old-1", null, 0, 10, false, false, null);
-		businessGroupRelationDao.addRole(id1, g1, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id2, g1, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id3, g1, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(ident1, g1, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident2, g1, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident3, g1, GroupRoles.coach.name());
 		BusinessGroup g2 = businessGroupService.createBusinessGroup(null, "old-2", null, 0, 10, false, false, null);
-		businessGroupRelationDao.addRole(id2, g2, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id4, g2, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id5, g2, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id6, g2, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(ident2, g2, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident4, g2, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident5, g2, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident6, g2, GroupRoles.coach.name());
 		BusinessGroup g3 = businessGroupService.createBusinessGroup(null, "target", null, 0, 10, false, false, null);
-		businessGroupRelationDao.addRole(id1, g3, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident1, g3, GroupRoles.participant.name());
 		dbInstance.commitAndCloseSession();
 		
 		//merge
@@ -386,18 +400,18 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		List<Identity> owners = businessGroupRelationDao.getMembers(mergedGroup, GroupRoles.coach.name());
 		Assert.assertNotNull(owners);
 		Assert.assertEquals(2, owners.size());
-		Assert.assertTrue(owners.contains(id3));
-		Assert.assertTrue(owners.contains(id6));
+		Assert.assertTrue(owners.contains(ident3));
+		Assert.assertTrue(owners.contains(ident6));
 		List<Identity> participants = businessGroupRelationDao.getMembers(mergedGroup, GroupRoles.participant.name());
 		Assert.assertNotNull(participants);
 		Assert.assertEquals(3, participants.size());
-		Assert.assertTrue(participants.contains(id1));
-		Assert.assertTrue(participants.contains(id2));
-		Assert.assertTrue(participants.contains(id5));
+		Assert.assertTrue(participants.contains(ident1));
+		Assert.assertTrue(participants.contains(ident2));
+		Assert.assertTrue(participants.contains(ident5));
 		List<Identity> waitingList = businessGroupRelationDao.getMembers(mergedGroup, GroupRoles.waiting.name());
 		Assert.assertNotNull(waitingList);
 		Assert.assertEquals(1, waitingList.size());
-		Assert.assertTrue(waitingList.contains(id4));
+		Assert.assertTrue(waitingList.contains(ident4));
 	}
 
 	/**
@@ -454,24 +468,24 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	throws Exception {
 		//add 2 identities in waiting group and 1 in as participant
 		Identity admin = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-0-" + UUID.randomUUID().toString());
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-3-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-3-" + UUID.randomUUID().toString());
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-1", "move-desc", 0, 10, true, false, null);
-		businessGroupService.addToWaitingList(admin, Collections.singletonList(id1), group, null);
-		businessGroupService.addToWaitingList(admin, Collections.singletonList(id2), group, null);
-		businessGroupService.addParticipants(admin, JunitTestHelper.getAdminRoles(), Collections.singletonList(id3), group, null);
+		businessGroupService.addToWaitingList(admin, Collections.singletonList(ident1), group, null);
+		businessGroupService.addToWaitingList(admin, Collections.singletonList(ident2), group, null);
+		businessGroupService.addParticipants(admin, JunitTestHelper.getAdminRoles(), Collections.singletonList(ident3), group, null);
 		
 		dbInstance.commitAndCloseSession();
 		
 		//move id1 from waiting-list to participant
-		List<Identity> identities = Collections.singletonList(id1);
+		List<Identity> identities = Collections.singletonList(ident1);
 		businessGroupService.moveIdentityFromWaitingListToParticipant(admin, identities, group, null);
 		//check position of 'id2'
-		int pos = businessGroupService.getPositionInWaitingListFor(id2, group);
+		int pos = businessGroupService.getPositionInWaitingListFor(ident2, group);
 		Assert.assertEquals("pos must be 1, bit is=" + pos, 1, pos);
 		//check if 'id3' is in participant-list
-		boolean negatifCheck = businessGroupService.isIdentityInBusinessGroup(id3, group);
+		boolean negatifCheck = businessGroupService.isIdentityInBusinessGroup(ident3, group);
 		assertTrue("Identity is not in participant-list", negatifCheck);
 	}
 	
@@ -481,29 +495,29 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	@Test
 	public void testAddToWaitingListAndFireEventAndCheckPosition() throws Exception {
 		//add 2 identities in waiting group and 1 in as participant
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-3-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-3-" + UUID.randomUUID().toString());
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-1", "move-desc", 0, 10, true, false, null);
 		//add id1
-		businessGroupService.addToWaitingList(id1, Collections.singletonList(id1), group, null);
+		businessGroupService.addToWaitingList(ident1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
 		//add id2
-		businessGroupService.addToWaitingList(id2, Collections.singletonList(id2), group, null);
+		businessGroupService.addToWaitingList(ident2, Collections.singletonList(ident2), group, null);
 		dbInstance.commitAndCloseSession();
 		//add id3
-		businessGroupService.addToWaitingList(id3, Collections.singletonList(id3), group, null);
+		businessGroupService.addToWaitingList(ident3, Collections.singletonList(ident3), group, null);
 		dbInstance.commitAndCloseSession();
 		
 
 		// Check position of 'id1'
-		int pos1 = businessGroupService.getPositionInWaitingListFor(id1, group);
+		int pos1 = businessGroupService.getPositionInWaitingListFor(ident1, group);
 		Assert.assertEquals("pos must be 1, bit is=" + pos1, 1, pos1);
 		// Check position of 'id2'
-		int pos2 = businessGroupService.getPositionInWaitingListFor(id2, group);
+		int pos2 = businessGroupService.getPositionInWaitingListFor(ident2, group);
 		Assert.assertEquals("pos must be 2, bit is=" + pos2, 2, pos2);
 		// Check position of 'id3'
-		int pos3 = businessGroupService.getPositionInWaitingListFor(id3, group);
+		int pos3 = businessGroupService.getPositionInWaitingListFor(ident3, group);
 		Assert.assertEquals("pos must be 3, bit is=" + pos3, 3, pos3);
 	}
 	
@@ -514,49 +528,49 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 	@Test
 	public void testRemoveFromWaitingListAndFireEvent() throws Exception {
 		//add 3 identities in waiting group
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-3-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-3-" + UUID.randomUUID().toString());
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-3", "move-desc", 0, 10, true, false, null);
-		businessGroupService.addToWaitingList(id1, Collections.singletonList(id1), group, null);
-		businessGroupService.addToWaitingList(id2, Collections.singletonList(id2), group, null);
-		businessGroupService.addToWaitingList(id3, Collections.singletonList(id3), group, null);
+		businessGroupService.addToWaitingList(ident1, Collections.singletonList(ident1), group, null);
+		businessGroupService.addToWaitingList(ident2, Collections.singletonList(ident2), group, null);
+		businessGroupService.addToWaitingList(ident3, Collections.singletonList(ident3), group, null);
 		dbInstance.commitAndCloseSession();
 		
 		//remove id2
-		businessGroupService.removeFromWaitingList(wg1, Collections.singletonList(id2), group, null);
+		businessGroupService.removeFromWaitingList(wg1, Collections.singletonList(ident2), group, null);
 		dbInstance.commitAndCloseSession();
 		
 		//check position of 'id1'
-		int pos1 = businessGroupService.getPositionInWaitingListFor(id1, group);
+		int pos1 = businessGroupService.getPositionInWaitingListFor(ident1, group);
 		Assert.assertEquals("pos must be 1, bit is=" + pos1, 1, pos1);
 		//check position of 'id3'
-		int pos3 = businessGroupService.getPositionInWaitingListFor(id3, group);
+		int pos3 = businessGroupService.getPositionInWaitingListFor(ident3, group);
 		Assert.assertEquals("pos must be 2, bit is=" + pos3, 2, pos3);
 		//check position of id2
-		int pos2 = businessGroupService.getPositionInWaitingListFor(id2, group);
+		int pos2 = businessGroupService.getPositionInWaitingListFor(ident2, group);
 		Assert.assertEquals("pos must be -1, not in list bit is=" + pos2, -1, pos2);
 	}
 	
 	@Test
 	public void testRemoveMembers() {
 		Identity admin = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-0-" + UUID.randomUUID().toString());
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-2-" + UUID.randomUUID().toString());
-		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-3-" + UUID.randomUUID().toString());
-		Identity id4 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-4-" + UUID.randomUUID().toString());
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-2-" + UUID.randomUUID().toString());
+		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-3-" + UUID.randomUUID().toString());
+		Identity ident4 = JunitTestHelper.createAndPersistIdentityAsUser("rm-w3-4-" + UUID.randomUUID().toString());
 		RepositoryEntry resource =  JunitTestHelper.createAndPersistRepositoryEntry();
-		BusinessGroup group1 = businessGroupService.createBusinessGroup(id1, "move-bg-3", "move-desc", 0, 10, true, false, resource);
-		BusinessGroup group2 = businessGroupService.createBusinessGroup(id2, "move-bg-3", "move-desc", 0, 10, true, false, resource);
-		BusinessGroup group3 = businessGroupService.createBusinessGroup(id3, "move-bg-3", "move-desc", 0, 10, true, false, resource);
-
-		businessGroupRelationDao.addRole(id2, group1, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id3, group1, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id3, group2, GroupRoles.waiting.name());
-		businessGroupRelationDao.addRole(id2, group2, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id1, group3, GroupRoles.coach.name());
-		businessGroupRelationDao.addRole(id2, group3, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(id4, group3, GroupRoles.waiting.name());
+		BusinessGroup group1 = businessGroupService.createBusinessGroup(ident1, "move-bg-3", "move-desc", 0, 10, true, false, resource);
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(ident2, "move-bg-3", "move-desc", 0, 10, true, false, resource);
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(ident3, "move-bg-3", "move-desc", 0, 10, true, false, resource);
+
+		businessGroupRelationDao.addRole(ident2, group1, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident3, group1, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident3, group2, GroupRoles.waiting.name());
+		businessGroupRelationDao.addRole(ident2, group2, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident1, group3, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(ident2, group3, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(ident4, group3, GroupRoles.waiting.name());
 		dbInstance.commitAndCloseSession();
 		//this groups and relations have been created
 		//group1: id1, id2, id3
@@ -566,8 +580,8 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		
 		//-> remove id1, id3 from the resource
 		List<Identity> identitiesToRemove = new ArrayList<Identity>();
-		identitiesToRemove.add(id1);
-		identitiesToRemove.add(id3);
+		identitiesToRemove.add(ident1);
+		identitiesToRemove.add(ident3);
 		businessGroupService.removeMembers(admin, identitiesToRemove, resource.getOlatResource(), null);
 		dbInstance.commitAndCloseSession();
 
@@ -581,17 +595,17 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		List<Identity> waitingGroup1 = businessGroupRelationDao.getMembers(group1, GroupRoles.waiting.name());
 		Assert.assertNotNull(waitingGroup1);
 		Assert.assertEquals(1, waitingGroup1.size());
-		Assert.assertEquals(id2, waitingGroup1.get(0));
+		Assert.assertEquals(ident2, waitingGroup1.get(0));
 		
 		//check in group2 id2 as owner and participant
 		List<Identity> ownerGroup2 = businessGroupService.getMembers(group2, GroupRoles.coach.name());
 		Assert.assertNotNull(ownerGroup2);
 		Assert.assertEquals(1, ownerGroup2.size());
-		Assert.assertEquals(id2, ownerGroup2.get(0));
+		Assert.assertEquals(ident2, ownerGroup2.get(0));
 		List<Identity> participantGroup2 = businessGroupRelationDao.getMembers(group2, GroupRoles.participant.name());
 		Assert.assertNotNull(participantGroup2);
 		Assert.assertEquals(1, participantGroup2.size());
-		Assert.assertEquals(id2, participantGroup2.get(0));
+		Assert.assertEquals(ident2, participantGroup2.get(0));
 		List<Identity> waitingGroup2 = businessGroupRelationDao.getMembers(group2, GroupRoles.waiting.name());
 		Assert.assertNotNull(waitingGroup2);
 		Assert.assertTrue(waitingGroup2.isEmpty());
@@ -603,57 +617,57 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		List<Identity> participantGroup3 = businessGroupRelationDao.getMembers(group3, GroupRoles.participant.name());
 		Assert.assertNotNull(participantGroup3);
 		Assert.assertEquals(1, participantGroup3.size());
-		Assert.assertEquals(id2, participantGroup3.get(0));
+		Assert.assertEquals(ident2, participantGroup3.get(0));
 		List<Identity> waitingGroup3 = businessGroupRelationDao.getMembers(group3, GroupRoles.waiting.name());
 		Assert.assertNotNull(waitingGroup3);
 		Assert.assertEquals(1, waitingGroup3.size());
-		Assert.assertEquals(id4, waitingGroup3.get(0));
+		Assert.assertEquals(ident4, waitingGroup3.get(0));
 	}
 	
 	@Test
 	public void testMoveRegisteredIdentityFromWaitingToParticipant() throws Exception {
 		//add 1 identity as participant
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w4-1-" + UUID.randomUUID().toString());
-		Roles rolesId1 = securityManager.getRoles(id1);
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w4-1-" + UUID.randomUUID().toString());
+		Roles rolesId1 = securityManager.getRoles(ident1);
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-4", "move-desc", 0, 10, true, false, null);
-		businessGroupService.addParticipants(id1, rolesId1, Collections.singletonList(id1), group, null);
+		businessGroupService.addParticipants(ident1, rolesId1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
 
 		//add a user to waiting-list which is already in participant-list 
-		businessGroupService.addToWaitingList(id1, Collections.singletonList(id1), group, null);
+		businessGroupService.addToWaitingList(ident1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
 		//try to move this user => user will be removed from waiting-list
-		businessGroupService.moveIdentityFromWaitingListToParticipant(id1, Collections.singletonList(id1), group, null);
+		businessGroupService.moveIdentityFromWaitingListToParticipant(ident1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
 
 		//check position of 'id1'
-		int pos = businessGroupService.getPositionInWaitingListFor(id1, group);
+		int pos = businessGroupService.getPositionInWaitingListFor(ident1, group);
 		Assert.assertEquals("pos must be -1, bit is=" + pos, -1, pos);
 		//check if 'id1' is still in participant-list
-		boolean member = businessGroupService.isIdentityInBusinessGroup(id1, group);
+		boolean member = businessGroupService.isIdentityInBusinessGroup(ident1, group);
 		Assert.assertTrue("Identity is not in participant-list", member);
 	}
 	
 	@Test
 	public void testAutoTransferFromWaitingListToParticipants() {
 		//add 1 identity as participant, 1 in waiting list
-		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w5-1-" + UUID.randomUUID().toString());
-		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w5-2-" + UUID.randomUUID().toString());;
-		Roles rolesId1 = securityManager.getRoles(id1);
+		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w5-1-" + UUID.randomUUID().toString());
+		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w5-2-" + UUID.randomUUID().toString());;
+		Roles rolesId1 = securityManager.getRoles(ident1);
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-5", "move-desc", 0, 1, true, true, null);
-		businessGroupService.addParticipants(id1, rolesId1, Collections.singletonList(id1), group, null);
-		businessGroupService.addToWaitingList(id2, Collections.singletonList(id2), group, null);
+		businessGroupService.addParticipants(ident1, rolesId1, Collections.singletonList(ident1), group, null);
+		businessGroupService.addToWaitingList(ident2, Collections.singletonList(ident2), group, null);
 		dbInstance.commitAndCloseSession();
 
 		//add a user to waiting-list which is already in participant-list 
-		businessGroupService.removeParticipants(id1, Collections.singletonList(id1), group, null);
+		businessGroupService.removeParticipants(ident1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
 
 		//check position of 'id2'
-		int pos = businessGroupService.getPositionInWaitingListFor(id2, group);
+		int pos = businessGroupService.getPositionInWaitingListFor(ident2, group);
 		Assert.assertEquals("pos must be -1, bit is=" + pos, -1, pos);
 		//check if 'id1' is still in participant-list
-		boolean member = businessGroupService.isIdentityInBusinessGroup(id2, group);
+		boolean member = businessGroupService.isIdentityInBusinessGroup(ident2, group);
 		Assert.assertTrue("Identity is in participant-list", member);
 	}
 
@@ -941,4 +955,186 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		Assert.assertNotNull(reservations);
 		Assert.assertTrue(reservations.isEmpty());
 	}
+	
+	/**
+	 * Test the default settings. Participants are allowed to leave business groups.
+	 */
+	@Test
+	public void allowToLeavingBusinessGroup_defaultSettings() {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("leave-auth-1-" + UUID.randomUUID().toString());
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-bg-1-");
+		BusinessGroup group = businessGroupService.createBusinessGroup(author, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, group, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+
+		LeaveOption optionToLeave = businessGroupService.isAllowToLeaveBusinessGroup(participant, group);
+		Assert.assertNotNull(optionToLeave);
+		Assert.assertTrue(optionToLeave.isAllowToLeave());
+	}
+	
+	/**
+	 * Test the default settings but the author set the business group to "leaving not allowed".
+	 */
+	@Test
+	public void allowToLeavingBusinessGroup_defaultSettings_groupOverride() {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("leave-auth-2-" + UUID.randomUUID().toString());
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-bg-2-");
+		BusinessGroup group = businessGroupService.createBusinessGroup(author, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, group, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//set to not allowed to leave
+		group = businessGroupService.updateAllowToLeaveBusinessGroup(group, false);
+		dbInstance.commitAndCloseSession();
+
+		LeaveOption optionToLeave = businessGroupService.isAllowToLeaveBusinessGroup(participant, group);
+		Assert.assertNotNull(optionToLeave);
+		Assert.assertFalse(optionToLeave.isAllowToLeave());
+		
+		ContactList contacts = optionToLeave.getContacts();
+		Assert.assertNotNull(contacts);
+		Collection<Identity> contactList = contacts.getIdentiEmails().values();
+		Assert.assertNotNull(contactList);
+		Assert.assertEquals(1, contactList.size());
+		Assert.assertTrue(contactList.contains(author));
+	}
+	
+	/**
+	 * Override of allow is forbidden system-wide. If a group have the settings not "not allowed to leave",
+	 * the setting must be ignored and the participants allowed to leave the group.
+	 */
+	@Test
+	public void allowToLeavingBusinessGroup_overrideForbidden() {
+		businessGroupModule.setAllowLeavingGroupOverride(false);
+
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("leave-auth-3-" + UUID.randomUUID().toString());
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-bg-3-");
+		BusinessGroup group = businessGroupService.createBusinessGroup(author, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, group, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//set to not allowed to leave
+		group = businessGroupService.updateAllowToLeaveBusinessGroup(group, false);
+		dbInstance.commitAndCloseSession();
+
+		LeaveOption optionToLeave = businessGroupService.isAllowToLeaveBusinessGroup(participant, group);
+		Assert.assertNotNull(optionToLeave);
+		Assert.assertTrue(optionToLeave.isAllowToLeave());
+	}
+	
+	/**
+	 * Override of allow is forbidden system-wide. If a group have the settings not "not allowed to leave",
+	 * the setting must be ignored for learners group but not for authors group.
+	 */
+	@Test
+	public void allowToLeavingBusinessGroup_overrideForbidden_notAllowForAuthorsGroups_butForLearnersGroup() {
+		businessGroupModule.setAllowLeavingGroupOverride(false);
+		businessGroupModule.setAllowLeavingGroupCreatedByAuthors(false);
+		businessGroupModule.setAllowLeavingGroupCreatedByLearners(true);
+		
+		//authors group
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("leave-auth-4-" + UUID.randomUUID().toString());
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-bg-4-");
+		BusinessGroup authorsGroup = businessGroupService.createBusinessGroup(author, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, authorsGroup, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//set to not allowed to leave
+		authorsGroup = businessGroupService.updateAllowToLeaveBusinessGroup(authorsGroup, false);
+		dbInstance.commitAndCloseSession();
+
+		//check the authors group leaving option
+		LeaveOption optionToLeaveAuthorsGroup = businessGroupService.isAllowToLeaveBusinessGroup(participant, authorsGroup);
+		Assert.assertNotNull(optionToLeaveAuthorsGroup);
+		Assert.assertFalse(optionToLeaveAuthorsGroup.isAllowToLeave());
+		
+		//learners group
+		Identity learner = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-learn-4-" + UUID.randomUUID().toString());
+		BusinessGroup learnersGroup = businessGroupService.createBusinessGroup(learner, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, learnersGroup, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+
+		//set to not allowed to leave
+		learnersGroup = businessGroupService.updateAllowToLeaveBusinessGroup(learnersGroup, false);
+		dbInstance.commitAndCloseSession();
+		
+		//check the learners group leaving option
+		LeaveOption optionToLeaveLearnersGroup = businessGroupService.isAllowToLeaveBusinessGroup(participant, learnersGroup);
+		Assert.assertNotNull(optionToLeaveLearnersGroup);
+		Assert.assertTrue(optionToLeaveLearnersGroup.isAllowToLeave());
+	}
+	
+	/**
+	 * Override of allow is forbidden system-wide. If a group have the settings not "not allowed to leave",
+	 * the setting must be ignored for learners group but not for authors group.
+	 */
+	@Test
+	public void allowToLeavingBusinessGroup_overrideForbidden_notAllowForAuthorsAndLearnersGroups() {
+		businessGroupModule.setAllowLeavingGroupOverride(false);
+		businessGroupModule.setAllowLeavingGroupCreatedByAuthors(false);
+		businessGroupModule.setAllowLeavingGroupCreatedByLearners(false);
+		
+		//authors group
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("leave-auth-5-" + UUID.randomUUID().toString());
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-bg-5-");
+		BusinessGroup authorsGroup = businessGroupService.createBusinessGroup(author, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, authorsGroup, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//set to not allowed to leave
+		authorsGroup = businessGroupService.updateAllowToLeaveBusinessGroup(authorsGroup, false);
+		dbInstance.commitAndCloseSession();
+
+		//check the authors group leaving option
+		LeaveOption optionToLeaveAuthorsGroup = businessGroupService.isAllowToLeaveBusinessGroup(participant, authorsGroup);
+		Assert.assertNotNull(optionToLeaveAuthorsGroup);
+		Assert.assertFalse(optionToLeaveAuthorsGroup.isAllowToLeave());
+		
+		//learners group
+		Identity learner = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-learn-5-" + UUID.randomUUID().toString());
+		BusinessGroup learnersGroup = businessGroupService.createBusinessGroup(learner, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, null);
+		businessGroupRelationDao.addRole(participant, learnersGroup, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+
+		//set to not allowed to leave
+		learnersGroup = businessGroupService.updateAllowToLeaveBusinessGroup(learnersGroup, false);
+		dbInstance.commitAndCloseSession();
+		
+		//check the learners group leaving option
+		LeaveOption optionToLeaveLearnersGroup = businessGroupService.isAllowToLeaveBusinessGroup(participant, learnersGroup);
+		Assert.assertNotNull(optionToLeaveLearnersGroup);
+		Assert.assertFalse(optionToLeaveLearnersGroup.isAllowToLeave());
+	}
+	
+	/**
+	 * 
+	 */
+	@Test
+	public void allowToLeavingBusinessGroup_withCourse() {
+		//authors group
+		RepositoryEntry resource = JunitTestHelper.createAndPersistRepositoryEntry();
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("leave-bg-5-");
+		BusinessGroup group = businessGroupService.createBusinessGroup(null, "Leaving group", "But you cannot leave :-(", new Integer(0), new Integer(2), false, false, resource);
+		businessGroupRelationDao.addRole(participant, group, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//set to not allowed to leave
+		group = businessGroupService.updateAllowToLeaveBusinessGroup(group, false);
+		dbInstance.commitAndCloseSession();
+
+		//check the authors group leaving option
+		LeaveOption optionToLeave = businessGroupService.isAllowToLeaveBusinessGroup(participant, group);
+		Assert.assertNotNull(optionToLeave);
+		Assert.assertFalse(optionToLeave.isAllowToLeave());
+		ContactList contacts = optionToLeave.getContacts();
+		Collection<Identity> contactList = contacts.getIdentiEmails().values();
+		Assert.assertNotNull(contactList);
+		Assert.assertFalse(contactList.isEmpty());
+		
+		for(Identity contact:contactList) {
+			Roles roles = securityManager.getRoles(contact);
+			Assert.assertNotNull(roles);
+			Assert.assertTrue(roles.isOLATAdmin());
+		}
+	}
 }
\ No newline at end of file