diff --git a/gms-ui/src/components/MembersPanel.vue b/gms-ui/src/components/MembersPanel.vue
index 34af9ce145a42062404fd6dfcea7f10aeb933fce..335d23d85902ddb77901d0f295cae69c601b499d 100644
--- a/gms-ui/src/components/MembersPanel.vue
+++ b/gms-ui/src/components/MembersPanel.vue
@@ -1,5 +1,5 @@
 <template>
-<b-tab title="Members" v-if="model.permission === 'ADMIN' || model.permission === 'MANAGE_MEMBERS' || model.permission === 'VIEW_MEMBERS'">
+<b-tab title="Members" :title-link-class="{ 'd-none': (model.permission === 'TRAVERSE') }">
   <div v-if="model.membersPanel !== null">
     <b-list-group v-for="member in model.membersPanel.items" id="members-list" v-bind:key="member.memberId">
       <b-list-group-item href="#" @click.prevent="openUser(member)">
diff --git a/gms-ui/src/components/PermissionsPanel.vue b/gms-ui/src/components/PermissionsPanel.vue
index 8a30a8c42b294b8032896872e8bffdc28e2be30a..c6631b857c27be3925217b1628d9e9f33099e448 100644
--- a/gms-ui/src/components/PermissionsPanel.vue
+++ b/gms-ui/src/components/PermissionsPanel.vue
@@ -1,5 +1,5 @@
 <template>
-<b-tab title="Permissions" v-if="model.permission === 'ADMIN'">
+<b-tab title="Permissions" :title-link-class="{ 'd-none': (model.permission !== 'ADMIN') }">
   <div v-if="model.permissionsPanel !== null">
     <table class="table b-table table-striped table-hover">
       <thead>
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java
index 792e2d521e5e141437181aad7b7ce5cfa2b7b51f..f31966fc7c63369f672c1a745c4c310c9eae9691 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/MembersController.java
@@ -4,7 +4,6 @@ import it.inaf.ia2.gms.manager.MembershipManager;
 import it.inaf.ia2.gms.manager.PermissionsManager;
 import it.inaf.ia2.gms.model.request.AddMemberRequest;
 import it.inaf.ia2.gms.model.response.PaginatedData;
-import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.model.RapUser;
 import it.inaf.ia2.gms.model.request.PaginatedModelRequest;
 import it.inaf.ia2.gms.model.request.RemoveMemberRequest;
@@ -52,16 +51,7 @@ public class MembersController {
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
 
         membershipManager.addMember(group, request.getUserId());
-
-        Permission currentUserPermission = permissionsManager.getCurrentUserPermission(group);
-
-        if (currentUserPermission == Permission.MANAGE_MEMBERS) {
-            // Automatically assign the VIEW_MEMBERS permission ("Add collaborator" feature)
-            permissionsManager.addPermission(group, request.getUserId(), Permission.VIEW_MEMBERS);
-        } else if (request.getPermission() != null) {
-            // Admin users can specify a permission
-            permissionsManager.addPermission(group, request.getUserId(), request.getPermission());
-        }
+        permissionsManager.addPermission(group, request.getUserId(), request.getPermission());
 
         return new ResponseEntity<>(getMembersPanel(group, request), HttpStatus.CREATED);
     }
@@ -73,20 +63,7 @@ public class MembersController {
 
         membershipManager.removeMember(group, request.getUserId());
 
-        Permission currentUserPermission = permissionsManager.getCurrentUserPermission(group);
-
-        // For users having the MANAGE_MEMBERS permission, the VIEW_MEMBERS permission
-        // is automatically assigned when they add a member ("Add collaborator" feature).
-        // We want to keep also the reverse behavior.
-        // If the member permission is not VIEW_MEMBERS that means that it has been
-        // changed by an ADMIN user, so we don't remove it.
-        boolean removeCollaborator = currentUserPermission == Permission.MANAGE_MEMBERS
-                && permissionsManager.getUserPermission(group, request.getUserId()) == Permission.VIEW_MEMBERS;
-
-        // ADMIN users can choose if delete also the permission or not.
-        boolean adminRemovePermission = currentUserPermission == Permission.ADMIN && request.isRemoveAlsoPermission();
-
-        if (removeCollaborator || adminRemovePermission) {
+        if (request.isRemoveAlsoPermission()) {
             permissionsManager.removePermission(group, request.getUserId());
         }
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java
index 238797c65ab6282fa6d11917dec90a31b298a50b..1a22842e280843cc7782167080beae1457ca57a6 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java
@@ -15,6 +15,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -72,15 +73,18 @@ public class PermissionsManager extends UserAwareComponent {
         return null;
     }
 
-    public Permission getUserPermission(GroupEntity group, String userId) {
-        verifyUserCanManagePermissions(group);
-        List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, userId);
-        return PermissionUtils.getGroupPermission(group, permissions).orElse(null);
-    }
-
     public PermissionEntity addPermission(GroupEntity group, String userId, Permission permission) {
-        verifyUserCanManagePermissions(group);
-        return permissionsService.addPermission(group, userId, permission);
+
+        Permission currentUserPermission = getCurrentUserPermission(group);
+
+        if (currentUserPermission == Permission.MANAGE_MEMBERS && permission == Permission.VIEW_MEMBERS) {
+            // Automatically assign the VIEW_MEMBERS permission ("Add collaborator" feature)
+            return permissionsService.addPermission(group, userId, Permission.VIEW_MEMBERS);
+        } else if (currentUserPermission == Permission.ADMIN) {
+            // Admin users can specify a permission
+            return permissionsService.addPermission(group, userId, permission);
+        }
+        throw unauthorizedExceptionSupplier(group).get();
     }
 
     public PermissionEntity updatePermission(GroupEntity group, String userId, Permission permission) {
@@ -89,18 +93,49 @@ public class PermissionsManager extends UserAwareComponent {
     }
 
     public void removePermission(GroupEntity group, String userId) {
-        verifyUserCanManagePermissions(group);
-        permissionsService.removePermission(group, userId);
+
+        Permission currentUserPermission = getCurrentUserPermission(group);
+
+        // For users having the MANAGE_MEMBERS permission, the VIEW_MEMBERS permission
+        // is automatically assigned when they add a member ("Add collaborator" feature).
+        // We want to keep also the reverse behavior.
+        if (currentUserPermission == Permission.MANAGE_MEMBERS) {
+            if (getUserPermission(group, userId, false) == Permission.VIEW_MEMBERS) {
+                permissionsService.removePermission(group, userId);
+            }
+            // If the member permission is not VIEW_MEMBERS that means that it has been
+            // changed by an ADMIN user, so we don't remove it.
+        } else if (currentUserPermission == Permission.ADMIN) {
+            permissionsService.removePermission(group, userId);
+        } else {
+            throw unauthorizedExceptionSupplier(group).get();
+        }
+    }
+
+    public Permission getUserPermission(GroupEntity group, String userId) {
+        return getUserPermission(group, userId, true);
+    }
+
+    private Permission getUserPermission(GroupEntity group, String userId, boolean verify) {
+        if (verify) {
+            verifyUserCanManagePermissions(group);
+        }
+        List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, userId);
+        return PermissionUtils.getGroupPermission(group, permissions).orElse(null);
     }
 
     private void verifyUserCanManagePermissions(GroupEntity group) {
         Permission permission = getCurrentUserPermission(group);
         if (permission != Permission.ADMIN) {
-            loggingDAO.logAction("Unauthorized attempt to manage permissions");
-            throw new UnauthorizedException("Only admin users can handle permissions");
+            throw unauthorizedExceptionSupplier(group).get();
         }
     }
 
+    private Supplier<UnauthorizedException> unauthorizedExceptionSupplier(GroupEntity group) {
+        loggingDAO.logAction("Unauthorized attempt to manage permissions [group_id=" + group.getId() + "]");
+        return () -> new UnauthorizedException("You don't have the privileges for managing the requested permission");
+    }
+
     public List<PermissionEntity> getCurrentUserPermissions(GroupEntity group) {
         return permissionsService.findUserPermissions(group, getCurrentUserId());
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/request/AddMemberRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/request/AddMemberRequest.java
index 14d24eda556cb6a3624c51de867e51bbd7117493..d514da063eaa0c2dc3e60ff70c7272679577f511 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/request/AddMemberRequest.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/request/AddMemberRequest.java
@@ -1,14 +1,11 @@
 package it.inaf.ia2.gms.model.request;
 
 import it.inaf.ia2.gms.model.Permission;
+import javax.validation.constraints.NotNull;
 
 public class AddMemberRequest extends MemberRequest {
 
-    /**
-     * When adding a member it is possible to assign also a permission. This
-     * field can be null (in that case the user is member of the group but
-     * he/she can't do nothing (not even seeing him/her group membership).
-     */
+    @NotNull
     private Permission permission;
 
     public Permission getPermission() {
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
index fdf853c33e1ddba6b17e6e99a19716c6c784e110..be3de511601ad8e360b5f297749f2fba681f4d83 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/MembersControllerTest.java
@@ -1,7 +1,6 @@
 package it.inaf.ia2.gms.controller;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-import it.inaf.ia2.gms.authn.SessionData;
 import it.inaf.ia2.gms.manager.MembershipManager;
 import it.inaf.ia2.gms.manager.PermissionsManager;
 import it.inaf.ia2.gms.model.request.AddMemberRequest;
@@ -57,7 +56,6 @@ public class MembersControllerTest {
         group.setPath("parent_id.group_id");
 
         when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
-        when(permissionsManager.getCurrentUserPermission(eq(group))).thenReturn(Permission.ADMIN);
     }
 
     @Test
@@ -68,10 +66,11 @@ public class MembersControllerTest {
         request.setUserId("user_id");
         request.setPaginatorPage(1);
         request.setPaginatorPageSize(10);
+        request.setPermission(Permission.VIEW_MEMBERS);
 
         mockMvc.perform(post("/member")
                 .content(mapper.writeValueAsString(request))
-                .contentType(MediaType.APPLICATION_JSON_UTF8))
+                .contentType(MediaType.APPLICATION_JSON_VALUE))
                 .andExpect(status().isCreated())
                 .andExpect(jsonPath("$.currentPage", is(1)));
 
diff --git a/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerIntegrationTest.java
index e5508ee7a2a6fd9d19bf7ebe34a0178095f54c88..9a25bc6eaf540ce6f9465fdfe44374f014eb56cd 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerIntegrationTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerIntegrationTest.java
@@ -1,7 +1,6 @@
 package it.inaf.ia2.gms.manager;
 
 import it.inaf.ia2.gms.DataSourceConfig;
-import it.inaf.ia2.gms.authn.RapPrincipal;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.model.RapUser;
 import it.inaf.ia2.gms.model.UserPermission;
@@ -13,9 +12,7 @@ import it.inaf.ia2.gms.persistence.model.PermissionEntity;
 import it.inaf.ia2.gms.rap.RapClient;
 import it.inaf.ia2.gms.service.PermissionsService;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
 import javax.sql.DataSource;
 import static org.junit.Assert.assertEquals;
diff --git a/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerTest.java b/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1459f0e72206a3ad52e69b11d7331b09b37c0b4
--- /dev/null
+++ b/gms/src/test/java/it/inaf/ia2/gms/manager/PermissionsManagerTest.java
@@ -0,0 +1,155 @@
+package it.inaf.ia2.gms.manager;
+
+import it.inaf.ia2.gms.exception.UnauthorizedException;
+import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.persistence.LoggingDAO;
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.persistence.model.PermissionEntity;
+import it.inaf.ia2.gms.service.PermissionsService;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PermissionsManagerTest {
+
+    private static final String USER_ID = "USER_ID";
+    private static final String TARGET_USER_ID = "TARGET_USER_ID";
+
+    @Mock
+    private PermissionsService permissionsService;
+    @Mock
+    private HttpServletRequest request;
+    @Mock
+    private LoggingDAO loggingDAO;
+
+    @InjectMocks
+    private PermissionsManager permissionsManager;
+
+    @Before
+    public void setUp() {
+        UserAwareComponentTestUtil.setUser(permissionsManager, USER_ID);
+    }
+
+    @Test
+    public void addPermissionFromManager() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.MANAGE_MEMBERS));
+
+        permissionsManager.addPermission(group, TARGET_USER_ID, Permission.VIEW_MEMBERS);
+
+        verify(permissionsService, times(1)).addPermission(eq(group), eq(TARGET_USER_ID), eq(Permission.VIEW_MEMBERS));
+    }
+
+    @Test
+    public void addPermissionFromAdmin() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.ADMIN));
+
+        permissionsManager.addPermission(group, TARGET_USER_ID, Permission.MANAGE_MEMBERS);
+
+        verify(permissionsService, times(1)).addPermission(eq(group), eq(TARGET_USER_ID), eq(Permission.MANAGE_MEMBERS));
+    }
+
+    @Test(expected = UnauthorizedException.class)
+    public void addPermissionFromUnauthorized() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(new ArrayList<>());
+
+        permissionsManager.addPermission(group, TARGET_USER_ID, Permission.MANAGE_MEMBERS);
+    }
+
+    @Test
+    public void removePermissionFromManager() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.MANAGE_MEMBERS));
+
+        when(permissionsService.findUserPermissions(eq(group), eq(TARGET_USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.VIEW_MEMBERS));
+
+        permissionsManager.removePermission(group, TARGET_USER_ID);
+
+        verify(permissionsService, times(1)).removePermission(eq(group), eq(TARGET_USER_ID));
+    }
+
+    @Test
+    public void removePermissionFromManagerAddedByAdmin() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.MANAGE_MEMBERS));
+
+        when(permissionsService.findUserPermissions(eq(group), eq(TARGET_USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.MANAGE_MEMBERS));
+
+        permissionsManager.removePermission(group, TARGET_USER_ID);
+
+        verify(permissionsService, never()).removePermission(any(), any());
+    }
+
+    @Test
+    public void removePermissionFromAdmin() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.ADMIN));
+
+        permissionsManager.removePermission(group, TARGET_USER_ID);
+
+        verify(permissionsService, times(1)).removePermission(eq(group), eq(TARGET_USER_ID));
+    }
+
+    @Test(expected = UnauthorizedException.class)
+    public void removePermissionFromUnauthorized() {
+
+        GroupEntity group = getGroup();
+
+        when(permissionsService.findUserPermissions(eq(group), eq(USER_ID)))
+                .thenReturn(getUserPermissions(group, Permission.VIEW_MEMBERS));
+
+        permissionsManager.removePermission(group, TARGET_USER_ID);
+    }
+
+    private List<PermissionEntity> getUserPermissions(GroupEntity group, Permission permission) {
+        PermissionEntity entity = new PermissionEntity();
+        entity.setPermission(permission);
+        entity.setGroupId(group.getId());
+        entity.setGroupPath(group.getPath());
+        entity.setUserId(USER_ID);
+        return Collections.singletonList(entity);
+    }
+
+    private GroupEntity getGroup() {
+        GroupEntity group = new GroupEntity();
+        group.setId("group_id");
+        group.setPath("parent_id.group_id");
+        return group;
+    }
+}