diff --git a/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java b/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java
index 6794f49410d31be3cd98a456cfa4ddc2527c7973..c2f55e5b11baf614d391b237aafe4afbb2cece0f 100644
--- a/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java
+++ b/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java
@@ -58,11 +58,11 @@ public class CLI implements CommandLineRunner {
 
         switch (args[0]) {
             case "create-group":
-                client.createGroup(getNames(args, 1));
+                client.addGroup(getNames(args, 1));
                 System.out.println("Group created");
                 break;
             case "delete-group":
-                client.deleteGroup(getNames(args, 1));
+                client.removeGroup(getNames(args, 1));
                 System.out.println("Group deleted");
                 break;
             case "add-member":
@@ -90,8 +90,8 @@ public class CLI implements CommandLineRunner {
                 if (args.length < 4) {
                     displayUsage();
                 }
-                client.deletePermission(getNames(args, args.length - 3), args[args.length - 2], args[args.length - 1]);
-                System.out.println("Permission added");
+                client.removePermission(getNames(args, args.length - 2), args[args.length - 1]);
+                System.out.println("Permission removed");
                 break;
             case "prepare-join":
                 if (args.length != 3) {
@@ -108,12 +108,12 @@ public class CLI implements CommandLineRunner {
 
     private void displayUsage() {
         System.out.println("java -jar gms-client.jar\n"
-                + "    create-group <name1 name2 name3>\n"
-                + "    delete-group <name1 name2 name3>\n"
+                + "    add-group <name1 name2 name3>\n"
+                + "    remove-group <name1 name2 name3>\n"
                 + "    add-member <name1 name2 name3> <user_id>\n"
                 + "    remove-member <name1 name2 name3> <user_id>\n"
                 + "    add-permission <name1 name2 name3> <user_id> <permission>\n"
-                + "    delete-permission <name1 name2 name3> <user_id> <permission>\n"
+                + "    remove-permission <name1 name2 name3> <user_id>\n"
                 + "    prepare-join <from_user_id> <to_user_id>");
         System.exit(0);
     }
diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java
index 634640f348db62c63d98bb47598ad71d344493db..abfbeb52ee77d46655fc50f4545f5bb133d376d2 100644
--- a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java
+++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java
@@ -40,7 +40,7 @@ public class GmsClient {
         this.restTemplate = restTemplate;
     }
 
-    public Group createGroup(List<String> names) {
+    public Group addGroup(List<String> names) {
 
         String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
                 .pathSegment(WS, "group")
@@ -51,7 +51,7 @@ public class GmsClient {
         return restTemplate.exchange(url, HttpMethod.POST, httpEntity, Group.class).getBody();
     }
 
-    public void deleteGroup(List<String> names) {
+    public void removeGroup(List<String> names) {
 
         String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
                 .pathSegment(WS, "group")
@@ -101,13 +101,12 @@ public class GmsClient {
         return restTemplate.exchange(url, HttpMethod.POST, httpEntity, Permission.class).getBody();
     }
 
-    public void deletePermission(List<String> names, String userId, String permission) {
+    public void removePermission(List<String> names, String userId) {
 
         String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
                 .pathSegment(WS, "permission")
                 .queryParam("names", names.toArray())
                 .queryParam("userId", userId)
-                .queryParam("permission", permission)
                 .toUriString();
 
         restTemplate.exchange(url, HttpMethod.DELETE, getEntity(), Void.class);
diff --git a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java
index d18b185d188a96b225b455bd5333f9339d50c12b..7771a98d5cae520b6c2c8927fa535a498a6b8505 100644
--- a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java
+++ b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java
@@ -51,7 +51,7 @@ public class GmsClientTest {
 
         List<String> names = Arrays.asList("LBT", "INAF");
 
-        client.createGroup(names);
+        client.addGroup(names);
 
         ArgumentCaptor<HttpEntity> entityCaptor = ArgumentCaptor.forClass(HttpEntity.class);
         verify(restTemplate, times(1)).exchange(eq(BASE_URL + "/ws/group"),
@@ -67,7 +67,7 @@ public class GmsClientTest {
 
         List<String> names = Arrays.asList("LBT", "INAF");
 
-        client.deleteGroup(names);
+        client.removeGroup(names);
 
         ArgumentCaptor<HttpEntity> entityCaptor = ArgumentCaptor.forClass(HttpEntity.class);
         verify(restTemplate, times(1)).exchange(eq(BASE_URL + "/ws/group?names=LBT&names=INAF"),
@@ -140,10 +140,10 @@ public class GmsClientTest {
 
         List<String> names = Arrays.asList("LBT", "INAF");
 
-        client.deletePermission(names, "user_id", "ADMIN");
+        client.removePermission(names, "user_id");
 
         ArgumentCaptor<HttpEntity> entityCaptor = ArgumentCaptor.forClass(HttpEntity.class);
-        verify(restTemplate, times(1)).exchange(eq(BASE_URL + "/ws/permission?names=LBT&names=INAF&userId=user_id&permission=ADMIN"),
+        verify(restTemplate, times(1)).exchange(eq(BASE_URL + "/ws/permission?names=LBT&names=INAF&userId=user_id"),
                 eq(HttpMethod.DELETE), entityCaptor.capture(), eq(Void.class));
 
         HttpEntity<?> entity = entityCaptor.getValue();
diff --git a/gms-ui/src/api/server/index.js b/gms-ui/src/api/server/index.js
index b84d0034088859964d613f2eef04ff552f59d777..0e883d9bc93198aee4247f2be3b2c02e5d291e59 100644
--- a/gms-ui/src/api/server/index.js
+++ b/gms-ui/src/api/server/index.js
@@ -82,7 +82,7 @@ export default {
       })
     });
   },
-  deleteGroup (groupId, input) {
+  removeGroup (groupId, input) {
     let url = BASE_API_URL + 'group/' + groupId
             + '?paginatorPageSize=' + input.paginatorPageSize
             + '&paginatorPage=' + input.paginatorPage;
@@ -128,5 +128,71 @@ export default {
         paginatorPage: input.paginatorPage
       })
     });
+  },
+  getPermission (groupId, userId) {
+    let url = BASE_API_URL + 'permission?groupId=' + groupId + '&userId=' + userId;
+
+    return apiRequest(url, {
+      method: 'GET',
+      cache: 'no-cache',
+      credentials: 'include',
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json',
+      }
+    });
+  },
+  addMember (userId, permission, input) {
+    let url = BASE_API_URL + 'member';
+
+    return apiRequest(url, {
+      method: 'POST',
+      cache: 'no-cache',
+      credentials: 'include',
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json',
+      },
+      body: JSON.stringify({
+        groupId: input.selectedGroupId,
+        userId: userId,
+        permission: permission,
+        paginatorPageSize: input.paginatorPageSize,
+        paginatorPage: input.paginatorPage
+      })
+    });
+  },
+  removeMember (userId, removeAlsoPermission, input) {
+    let url = BASE_API_URL + 'member'
+            + '?groupId=' + input.selectedGroupId
+            + '&userId=' + userId
+            + '&removeAlsoPermission=' + removeAlsoPermission
+            + '&paginatorPageSize=' + input.paginatorPageSize
+            + '&paginatorPage=' + input.paginatorPage;
+    return apiRequest(url, {
+      method: 'DELETE',
+      cache: 'no-cache',
+      credentials: 'include',
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json',
+      }
+    });
+  },
+  removePermission (userId, input) {
+    let url = BASE_API_URL + 'permission'
+            + '?groupId=' + input.selectedGroupId
+            + '&userId=' + userId
+            + '&paginatorPageSize=' + input.paginatorPageSize
+            + '&paginatorPage=' + input.paginatorPage;
+    return apiRequest(url, {
+      method: 'DELETE',
+      cache: 'no-cache',
+      credentials: 'include',
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json',
+      }
+    });
   }
 };
diff --git a/gms-ui/src/components/GroupsPanel.vue b/gms-ui/src/components/GroupsPanel.vue
index 3ddfc6a4dec53b83fef3e602b0a828f2758108f6..04b55fc0d7214cc337a9563a8cae9fd451dbf59e 100644
--- a/gms-ui/src/components/GroupsPanel.vue
+++ b/gms-ui/src/components/GroupsPanel.vue
@@ -14,7 +14,7 @@
               <font-awesome-icon icon="edit"></font-awesome-icon>
             </a>
             &nbsp;
-            <a href="#" v-on:click.stop="openDeleteGroupModal(group)" class="text-danger" title="Delete">
+            <a href="#" v-on:click.stop="openRemoveGroupModal(group)" class="text-danger" title="Delete">
               <font-awesome-icon icon="trash"></font-awesome-icon>
             </a>
           </span>
@@ -48,20 +48,20 @@
     <div class="text-center">
     </div>
     <RenameGroupModal ref="renameGroupModal" />
-    <ConfirmDeleteGroupModal ref="confirmDeleteGroupModal" />
+    <ConfirmRemoveGroupModal ref="confirmRemoveGroupModal" />
   </b-tab>
 </template>
 
 <script>
-import RenameGroupModal from './modals/RenameGroupModal.vue'
-import ConfirmDeleteGroupModal from './modals/ConfirmDeleteGroupModal.vue'
-import { mapState, mapActions } from 'vuex'
+import RenameGroupModal from './modals/RenameGroupModal.vue';
+import ConfirmRemoveGroupModal from './modals/ConfirmRemoveGroupModal.vue';
+import { mapState, mapActions } from 'vuex';
 
 export default {
   name: 'GroupsPanel',
   components: {
     RenameGroupModal,
-    ConfirmDeleteGroupModal
+    ConfirmRemoveGroupModal
   },
   computed: mapState({
     model: state => state.model,
@@ -85,8 +85,8 @@ export default {
     openRenameGroupModal: function(group) {
       this.$refs.renameGroupModal.openRenameGroupModal(group);
     },
-    openDeleteGroupModal: function(group) {
-      this.$refs.confirmDeleteGroupModal.openDeleteGroupModal(group);
+    openRemoveGroupModal: function(group) {
+      this.$refs.confirmRemoveGroupModal.openRemoveGroupModal(group);
     },
     setPage: function(page) {
       console.log('setPage ', page);
diff --git a/gms-ui/src/components/Main.vue b/gms-ui/src/components/Main.vue
index 0fc06ebe5f89b1fdb41c0bd944a1439c5ae66c4f..27862fd25a5a512f9aefc7d2d0a681d2e586e895 100644
--- a/gms-ui/src/components/Main.vue
+++ b/gms-ui/src/components/Main.vue
@@ -8,13 +8,14 @@
         <PermissionsPanel />
         <template slot="tabs-end">
           <b-button variant="primary" class="in-tabs-header-btn" v-if="showAddGroupBtn" v-on:click="openAddGroupModal">Add group</b-button>
-          <b-button variant="primary" class="in-tabs-header-btn" v-if="showAddMemberBtn">Add member</b-button>
-          <b-button variant="primary" class="in-tabs-header-btn" v-if="showAddCollaboratorBtn">Add collaborator</b-button>
+          <b-button variant="primary" class="in-tabs-header-btn" v-if="showAddMemberBtn" v-on:click="openAddMemberModal">Add member</b-button>
+          <b-button variant="primary" class="in-tabs-header-btn" v-if="showAddCollaboratorBtn" v-on:click="openAddMemberModal">Add collaborator</b-button>
           <b-button variant="primary" class="in-tabs-header-btn" v-if="showAddPermissionBtn" v-on:click="openAddPermissionModal">Add permission</b-button>
         </template>
       </b-tabs>
     </b-card>
-    <NewGroupModal />
+    <AddGroupModal />
+    <AddMemberModal />
     <AddPermissionModal />
   </div>
 </template>
@@ -24,7 +25,7 @@ import GroupsBreadcrumb from './GroupsBreadcrumb.vue'
 import GroupsPanel from './GroupsPanel.vue'
 import MembersPanel from './MembersPanel.vue'
 import PermissionsPanel from './PermissionsPanel.vue'
-import NewGroupModal from './modals/NewGroupModal.vue'
+import AddGroupModal from './modals/AddGroupModal.vue'
 import AddMemberModal from './modals/AddMemberModal.vue'
 import AddPermissionModal from './modals/AddPermissionModal.vue'
 import { mapState } from 'vuex';
@@ -36,7 +37,7 @@ export default {
     GroupsPanel,
     MembersPanel,
     PermissionsPanel,
-    NewGroupModal,
+    AddGroupModal,
     AddMemberModal,
     AddPermissionModal
   },
@@ -67,10 +68,10 @@ export default {
       }
     },
     openAddGroupModal: function() {
-      this.$bvModal.show('new-group-modal');
+      this.$bvModal.show('add-group-modal');
     },
     openAddMemberModal: function() {
-
+      this.$bvModal.show('add-member-modal');
     },
     openAddPermissionModal: function() {
       this.$bvModal.show('add-permission-modal');
diff --git a/gms-ui/src/components/MembersPanel.vue b/gms-ui/src/components/MembersPanel.vue
index 3e28e93da51882b39da164110674a99cabb38162..d60a9e794017299d76781421c2d36bc067fa5062 100644
--- a/gms-ui/src/components/MembersPanel.vue
+++ b/gms-ui/src/components/MembersPanel.vue
@@ -3,12 +3,11 @@
     <div v-if="model.membersPanel !== null">
       <b-list-group v-for="member in model.membersPanel.items" id="members-list">
         <b-list-group-item href="#">
-          {{member.label}}
-          <span v-if="model.permission === 'ADMIN'">
-            <a href="#" v-on:click="changeMemberPermission(member)">
-              <font-awesome-icon icon="edit"></font-awesome-icon>
-            </a>
-            <a href="#" v-on:click="deleteMember(member)">
+          <div class="float-left">
+            <User v-bind:user="member" />
+          </div>
+          <span v-if="model.permission === 'ADMIN' || model.permission === 'MANAGE_MEMBERS'" class="float-right">
+            <a href="#" v-on:click.stop="openRemoveMemberModal(member)" class="text-danger" title="Remove member">
               <font-awesome-icon icon="trash"></font-awesome-icon>
             </a>
           </span>
@@ -25,27 +24,49 @@
         v-on:change="setPage"
       ></b-pagination>
     </div>
+    <ConfirmRemoveMemberModal ref="confirmRemoveMemberModal" />
   </b-tab>
 </template>
 
 <script>
+import client from 'api-client';
+import User from './User.vue';
+import ConfirmRemoveMemberModal from './modals/ConfirmRemoveMemberModal.vue'
 import { mapState } from 'vuex';
 
 export default {
   name: 'MembersPanel',
+  components: {
+    User,
+    ConfirmRemoveMemberModal
+  },
   computed: mapState({
-    model: state => state.model,
+    model: state => state.model
   }),
   methods: {
-    deleteMember: function(member) {
-      console.log('deleteMember ' + member.id);
-    },
-    changeMemberPermission: function(member) {
-      console.log('changeMemberPermission ' + member.id);
+    openRemoveMemberModal: function(member) {
+      getMemberPermission(this, member)
+        .then(memberPermission => {
+          this.$refs.confirmRemoveMemberModal.openRemoveMemberModal(member, memberPermission);
+        });
     },
     setPage: function(page) {
       console.log('setPage ', page);
     }
   }
 }
+
+function getMemberPermission(self, member) {
+  return new Promise((resolve, reject) => {
+    if(self.model.permission === 'ADMIN') {
+      let groupId = self.$store.state.input.selectedGroupId;
+      client.getPermission(groupId, member.id)
+        .then(res => {
+          resolve(res.permission);
+        });
+    } else {
+      resolve(null);
+    }
+  });
+}
 </script>
diff --git a/gms-ui/src/components/PermissionsPanel.vue b/gms-ui/src/components/PermissionsPanel.vue
index e4ee838b89ee247bebb29af5c25e30d290150807..9c555838941cd31d911dacbf5b9e07eca3e13c78 100644
--- a/gms-ui/src/components/PermissionsPanel.vue
+++ b/gms-ui/src/components/PermissionsPanel.vue
@@ -15,7 +15,11 @@
               <User v-bind:user="up.user" />
             </td>
             <td>{{up.permission}}</td>
-            <td></td>
+            <td>
+              <a href="#" v-on:click.stop="openRemovePermissionModal(up.user)" class="text-danger" title="Remove permission">
+                <font-awesome-icon icon="trash"></font-awesome-icon>
+              </a>
+            </td>
           </tr>
         </tbody>
       </table>
@@ -30,24 +34,27 @@
         v-on:change="setPage"
       ></b-pagination>
     </div>
+    <ConfirmRemovePermissionModal ref="confirmRemovePermissionModal" />
   </b-tab>
 </template>
 
 <script>
-import User from './User.vue'
+import User from './User.vue';
+import ConfirmRemovePermissionModal from './modals/ConfirmRemovePermissionModal.vue'
 import { mapState } from 'vuex';
 
 export default {
   name: 'PermissionsPanel',
   components: {
-    User
+    User,
+    ConfirmRemovePermissionModal
   },
   computed: mapState({
     model: state => state.model,
   }),
   methods: {
-    deletePermission: function(userPermission) {
-
+    openRemovePermissionModal: function(user) {
+      this.$refs.confirmRemovePermissionModal.openRemovePermissionModal(user);
     },
     setPage: function(page) {
       console.log('setPage ', page);
diff --git a/gms-ui/src/components/modals/NewGroupModal.vue b/gms-ui/src/components/modals/AddGroupModal.vue
similarity index 92%
rename from gms-ui/src/components/modals/NewGroupModal.vue
rename to gms-ui/src/components/modals/AddGroupModal.vue
index e976b8c905986de3fc529b295615ab1e36e294fa..6f5ba170118e3f471f3f40130d0612674806346c 100644
--- a/gms-ui/src/components/modals/NewGroupModal.vue
+++ b/gms-ui/src/components/modals/AddGroupModal.vue
@@ -1,5 +1,5 @@
 <template>
-  <b-modal id="new-group-modal" title="Add group" @show="resetModal" ok-title="Add" @ok="addGroup">
+  <b-modal id="add-group-modal" title="Add group" @show="resetModal" ok-title="Add" @ok="addGroup">
     <b-form inline>
       <label class="w-25" for="new-group-name-input">Group name:</label>
       <b-form-input v-model="newGroupName"
@@ -18,7 +18,7 @@
 import client from 'api-client';
 
 export default {
-  name: 'NewGroupModal',
+  name: 'AddGroupModal',
   computed: {
     newGroupNameState() {
       if(this.newGroupNameError) {
@@ -56,7 +56,7 @@ export default {
             this.newGroupNameError = res.message;
           } else {
             this.$store.commit('updateGroupsPanel', res);
-            this.$bvModal.hide('new-group-modal');
+            this.$bvModal.hide('add-group-modal');
           }
         });
     }
diff --git a/gms-ui/src/components/modals/AddMemberModal.vue b/gms-ui/src/components/modals/AddMemberModal.vue
index 23d47959172fb7f90f70188bad2bda21e25663a3..db7c06a36056376e8fbeefe28049e959f98190b2 100644
--- a/gms-ui/src/components/modals/AddMemberModal.vue
+++ b/gms-ui/src/components/modals/AddMemberModal.vue
@@ -1,26 +1,32 @@
 <template>
   <b-modal id="add-member-modal" title="Add member" ok-title="Add" @ok="addMember">
-    <SearchUser />
+    <SearchUser ref="searchUser" />
   </b-modal>
 </template>
 
 <script>
 import client from 'api-client';
 import SearchUser from './SearchUser.vue'
+import { mapState } from 'vuex';
 
 export default {
   name: 'AddMemberModal',
   components: {
     SearchUser
   },
-  data: function() {
-    return {
-      permission: 'VIEW_MEMBERS'
-    }
-  },
   methods: {
-    addMember: function() {
+    addMember: function(event) {
+      // Prevent modal from closing
+      event.preventDefault();
+
+      let userId = this.$refs.searchUser.selectedUser;
+      let permission = this.$refs.searchUser.permission;
 
+      client.addMember(userId, permission, this.$store.state.input)
+        .then(res => {
+          this.$store.commit('updateMembersPanel', res);
+          this.$bvModal.hide('add-member-modal');
+        });
     }
   }
 };
diff --git a/gms-ui/src/components/modals/AddPermissionModal.vue b/gms-ui/src/components/modals/AddPermissionModal.vue
index 7b792e9fb52dae185fecc7ecc5cb4b97d677b923..9e1db368f3c9f705ab831e58e3fa1db057cd0c55 100644
--- a/gms-ui/src/components/modals/AddPermissionModal.vue
+++ b/gms-ui/src/components/modals/AddPermissionModal.vue
@@ -13,10 +13,6 @@ export default {
   components: {
     SearchUser
   },
-  data: function() {
-    return {
-    }
-  },
   methods: {
     addPermission: function(event) {
       // Prevent modal from closing
diff --git a/gms-ui/src/components/modals/ConfirmDeleteGroupModal.vue b/gms-ui/src/components/modals/ConfirmDeleteGroupModal.vue
deleted file mode 100644
index e563c530f24851f3275673a85626218c9fe6af8c..0000000000000000000000000000000000000000
--- a/gms-ui/src/components/modals/ConfirmDeleteGroupModal.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-<template>
-  <b-modal id="confirm-delete-group-modal" title="Confirm action" ok-title="Delete" @ok="deleteGroup" ok-variant="danger">
-    <p v-if="groupToDelete">Are you sure that you want to delete the group <strong>{{groupToDelete.groupName}}</strong>?</p>
-  </b-modal>
-</template>
-
-<script>
-import client from 'api-client';
-
-export default {
-  name: 'ConfirmDeleteGroupModal',
-  data: function() {
-    return {
-      groupToDelete: null
-    }
-  },
-  methods: {
-    openDeleteGroupModal: function(group) {
-      this.groupToDelete = group;
-      this.$bvModal.show('confirm-delete-group-modal');
-    },
-    deleteGroup: function() {
-      client.deleteGroup(this.groupToDelete.groupId, this.$store.state.input)
-        .then(res => {
-          this.$store.commit('updateGroupsPanel', res);
-          this.$bvModal.hide('confirm-delete-group-modal');
-        })
-    }
-  }
-}
-</script>
diff --git a/gms-ui/src/components/modals/ConfirmRemoveGroupModal.vue b/gms-ui/src/components/modals/ConfirmRemoveGroupModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f22196a277f7093b1b923b14d00ca36d36d9d039
--- /dev/null
+++ b/gms-ui/src/components/modals/ConfirmRemoveGroupModal.vue
@@ -0,0 +1,34 @@
+<template>
+  <b-modal id="confirm-remove-group-modal" title="Confirm action" ok-title="Delete" @ok="removeGroup" ok-variant="danger">
+    <p v-if="groupToRemove">Are you sure that you want to delete the group <strong>{{groupToRemove.groupName}}</strong>?</p>
+  </b-modal>
+</template>
+
+<script>
+import client from 'api-client';
+
+export default {
+  name: 'ConfirmRemoveGroupModal',
+  data: function() {
+    return {
+      groupToRemove: null
+    }
+  },
+  methods: {
+    openRemoveGroupModal: function(group) {
+      this.groupToRemove = group;
+      this.$bvModal.show('confirm-remove-group-modal');
+    },
+    removeGroup: function(event) {
+      // Prevent modal from closing
+      event.preventDefault();
+
+      client.removeGroup(this.groupToRemove.groupId, this.$store.state.input)
+        .then(res => {
+          this.$store.commit('updateGroupsPanel', res);
+          this.$bvModal.hide('confirm-remove-group-modal');
+        })
+    }
+  }
+}
+</script>
diff --git a/gms-ui/src/components/modals/ConfirmRemoveMemberModal.vue b/gms-ui/src/components/modals/ConfirmRemoveMemberModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..48d2a8c2afb10ce00f98baed6ec3113f4c2e053e
--- /dev/null
+++ b/gms-ui/src/components/modals/ConfirmRemoveMemberModal.vue
@@ -0,0 +1,44 @@
+<template>
+  <b-modal id="confirm-remove-member-modal" title="Confirm action" ok-title="Remove" @ok="removeMember" ok-variant="danger">
+    <p v-if="memberToRemove">Are you sure that you want to remove the user {{memberToRemove.displayName}} from this group?</p>
+    <b-form inline v-if="model.permission === 'ADMIN' && memberPermission">
+      <b-form-checkbox v-model="removeAlsoPermission">Remove also permission ({{memberPermission}})</b-form-checkbox>
+    </b-form>
+  </b-modal>
+</template>
+
+<script>
+import client from 'api-client';
+import { mapState, mapActions } from 'vuex';
+
+export default {
+  name: 'ConfirmRemoveGroupModal',
+  data: function() {
+    return {
+      memberToRemove: null,
+      memberPermission: null,
+      removeAlsoPermission: true
+    }
+  },
+  computed: mapState({
+    model: state => state.model
+  }),
+  methods: {
+    openRemoveMemberModal: function(member, memberPermission) {
+      this.memberToRemove = member;
+      this.memberPermission = memberPermission;
+      this.$bvModal.show('confirm-remove-member-modal');
+    },
+    removeMember: function(event) {
+      // Prevent modal from closing
+      event.preventDefault();
+
+      client.removeMember(this.memberToRemove.id, this.removeAlsoPermission, this.$store.state.input)
+        .then(res => {
+          this.$store.commit('updateMembersPanel', res);
+          this.$bvModal.hide('confirm-remove-member-modal');
+        });
+    }
+  }
+}
+</script>
diff --git a/gms-ui/src/components/modals/ConfirmRemovePermissionModal.vue b/gms-ui/src/components/modals/ConfirmRemovePermissionModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4964e08f52bbeb7090290de65c1400d6fc2f6e7f
--- /dev/null
+++ b/gms-ui/src/components/modals/ConfirmRemovePermissionModal.vue
@@ -0,0 +1,38 @@
+<template>
+  <b-modal id="confirm-remove-permission-modal" title="Confirm action" ok-title="Remove" @ok="removePermission" ok-variant="danger">
+    <p v-if="user">Are you sure that you want to remove the permission for the user {{user.displayName}}?</p>
+  </b-modal>
+</template>
+
+<script>
+import client from 'api-client';
+import { mapState, mapActions } from 'vuex';
+
+export default {
+  name: 'ConfirmRemovePermissionModal',
+  data: function() {
+    return {
+      user: null
+    }
+  },
+  computed: mapState({
+    model: state => state.model
+  }),
+  methods: {
+    openRemovePermissionModal: function(user) {
+      this.user = user;
+      this.$bvModal.show('confirm-remove-permission-modal');
+    },
+    removePermission: function(event) {
+      // Prevent modal from closing
+      event.preventDefault();
+
+      client.removePermission(this.user.id, this.$store.state.input)
+        .then(res => {
+          this.$store.commit('updatePermissionsPanel', res);
+          this.$bvModal.hide('confirm-remove-permission-modal');
+        });
+    }
+  }
+}
+</script>
diff --git a/gms-ui/src/store.js b/gms-ui/src/store.js
index 44ce164d27bc34d376eab01eb6b16c4d4f467ace..ddfed3b0703b3cb8d4014d015f11f62efafcb57e 100644
--- a/gms-ui/src/store.js
+++ b/gms-ui/src/store.js
@@ -31,6 +31,9 @@ export default new Vuex.Store({
     },
     updatePermissionsPanel(state, permissionsPanel) {
       this.state.model.permissionsPanel = permissionsPanel;
+    },
+    updateMembersPanel(state, membersPanel) {
+      this.state.model.membersPanel = membersPanel;
     }
   },
   getters: {
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 3aef326aeeac096a3ca0af02f21575ae248b1969..d6069b18956a2c410f178fdde62c0acc02145779 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
@@ -2,10 +2,12 @@ package it.inaf.ia2.gms.controller;
 
 import it.inaf.ia2.gms.authn.SessionData;
 import it.inaf.ia2.gms.exception.UnauthorizedException;
+import it.inaf.ia2.gms.model.AddMemberRequest;
 import it.inaf.ia2.gms.model.MemberRequest;
 import it.inaf.ia2.gms.model.PaginatedData;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.model.RapUser;
+import it.inaf.ia2.gms.model.RemoveMemberRequest;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.service.GroupsService;
 import it.inaf.ia2.gms.service.MembersService;
@@ -37,32 +39,55 @@ public class MembersController {
     private MembersService membersService;
 
     @PostMapping(value = "/member", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-    public ResponseEntity<PaginatedData<RapUser>> addMember(@Valid @RequestBody MemberRequest request) {
+    public ResponseEntity<PaginatedData<RapUser>> addMember(@Valid @RequestBody AddMemberRequest request) {
 
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
-        verifyCurrentUserCanManageMembers(group);
+        Permission currentUserPermission = verifyCurrentUserCanManageMembers(group);
 
         membersService.addMember(request.getGroupId(), request.getUserId());
+        if (currentUserPermission == Permission.MANAGE_MEMBERS) {
+            // Automatically assign the VIEW_MEMBERS permission ("Add collaborator" feature)
+            permissionsService.addPermission(group, request.getUserId(), Permission.VIEW_MEMBERS);
+        } else if (request.getPermission() != null) {
+            // Admin users can specify a permission
+            permissionsService.addPermission(group, request.getUserId(), request.getPermission());
+        }
 
         return new ResponseEntity<>(getMembersPanel(request), HttpStatus.CREATED);
     }
 
     @DeleteMapping(value = "/member", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-    public ResponseEntity<PaginatedData<RapUser>> removeMember(@Valid MemberRequest request) {
+    public ResponseEntity<PaginatedData<RapUser>> removeMember(@Valid RemoveMemberRequest request) {
 
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
-        verifyCurrentUserCanManageMembers(group);
+        Permission currentUserPermission = verifyCurrentUserCanManageMembers(group);
 
         membersService.removeMember(group.getId(), request.getUserId());
 
+        // 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
+                && permissionsService.getUserPermissionForGroup(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) {
+            permissionsService.removePermission(group, request.getUserId());
+        }
+
         return ResponseEntity.ok(getMembersPanel(request));
     }
 
-    private void verifyCurrentUserCanManageMembers(GroupEntity group) {
+    private Permission verifyCurrentUserCanManageMembers(GroupEntity group) {
         Permission currentNodePermission = permissionsService.getUserPermissionForGroup(group, session.getUserId());
         if (currentNodePermission != Permission.ADMIN && currentNodePermission != Permission.MANAGE_MEMBERS) {
             throw new UnauthorizedException("Missing admin or manage members permissions");
         }
+        return currentNodePermission;
     }
 
     private PaginatedData<RapUser> getMembersPanel(MemberRequest request) {
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
index 53582bbbed7b141a6975291e442dc2ec1bc97926..cd9ba1e87af24c08fe220cacb420f04fca4e115a 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
@@ -2,22 +2,28 @@ package it.inaf.ia2.gms.controller;
 
 import it.inaf.ia2.gms.authn.SessionData;
 import it.inaf.ia2.gms.exception.UnauthorizedException;
-import it.inaf.ia2.gms.model.PermissionRequest;
+import it.inaf.ia2.gms.model.AddPermissionRequest;
+import it.inaf.ia2.gms.model.MemberRequest;
 import it.inaf.ia2.gms.model.PaginatedData;
+import it.inaf.ia2.gms.model.PaginatedModelRequest;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.model.UserPermission;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.service.GroupsService;
 import it.inaf.ia2.gms.service.PermissionsService;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import javax.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
@@ -32,8 +38,24 @@ public class PermissionsController {
     @Autowired
     private PermissionsService permissionsService;
 
+    @GetMapping(value = "/permission")
+    public ResponseEntity<Map<String, Permission>> getUserPermission(@RequestParam("groupId") String groupId, @RequestParam("userId") String userId) {
+
+        GroupEntity group = groupsService.getGroupById(groupId);
+        verifyCurrentUserCanManagePermissions(group);
+
+        Permission permission = permissionsService.getUserPermissionForGroup(group, userId);
+        if (permission == null) {
+            return ResponseEntity.notFound().build();
+        } else {
+            Map<String, Permission> response = new HashMap<>();
+            response.put("permission", permission);
+            return ResponseEntity.ok(response);
+        }
+    }
+
     @PostMapping(value = "/permission", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-    public ResponseEntity<PaginatedData<UserPermission>> addPermission(@Valid @RequestBody PermissionRequest request) {
+    public ResponseEntity<PaginatedData<UserPermission>> addPermission(@Valid @RequestBody AddPermissionRequest request) {
 
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
         verifyCurrentUserCanManagePermissions(group);
@@ -44,12 +66,12 @@ public class PermissionsController {
     }
 
     @DeleteMapping(value = "/permission", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-    public ResponseEntity<PaginatedData<UserPermission>> deletePermission(@Valid PermissionRequest request) {
+    public ResponseEntity<PaginatedData<UserPermission>> deletePermission(@Valid MemberRequest request) {
 
         GroupEntity group = groupsService.getGroupById(request.getGroupId());
         verifyCurrentUserCanManagePermissions(group);
 
-        permissionsService.deletePermission(group, request.getUserId(), request.getPermission());
+        permissionsService.removePermission(group, request.getUserId());
 
         return ResponseEntity.ok(getPermissionsPanel(group, request));
     }
@@ -61,7 +83,7 @@ public class PermissionsController {
         }
     }
 
-    private PaginatedData<UserPermission> getPermissionsPanel(GroupEntity group, PermissionRequest request) {
+    private PaginatedData<UserPermission> getPermissionsPanel(GroupEntity group, PaginatedModelRequest request) {
         List<UserPermission> permissions = permissionsService.getAllPermissions(group);
         return new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize());
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/WebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/WebServiceController.java
index 04c067cb2a92882d0fd2cd83f8ddfdc58625a1b4..b57df946d7a6ba6a52d06a5ebb4ac5cfda8d6c1d 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/WebServiceController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/WebServiceController.java
@@ -101,12 +101,11 @@ public class WebServiceController {
     }
 
     @DeleteMapping("/permission")
-    public ResponseEntity<?> deletePermission(@RequestParam("names") String[] names,
-            @RequestParam("userId") String userId, @RequestParam("permission") Permission permission) {
+    public ResponseEntity<?> deletePermission(@RequestParam("names") String[] names, @RequestParam("userId") String userId) {
 
         GroupEntity group = getGroupByNames(Arrays.asList(names));
 
-        permissionsService.deletePermission(group, userId, permission);
+        permissionsService.removePermission(group, userId);
 
         return ResponseEntity.noContent().build();
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/AddMemberRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/AddMemberRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f55c0af85c34633e0bea6397e68483f5c0e4513
--- /dev/null
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/AddMemberRequest.java
@@ -0,0 +1,19 @@
+package it.inaf.ia2.gms.model;
+
+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).
+     */
+    private Permission permission;
+
+    public Permission getPermission() {
+        return permission;
+    }
+
+    public void setPermission(Permission permission) {
+        this.permission = permission;
+    }
+}
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/PermissionRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/AddPermissionRequest.java
similarity index 91%
rename from gms/src/main/java/it/inaf/ia2/gms/model/PermissionRequest.java
rename to gms/src/main/java/it/inaf/ia2/gms/model/AddPermissionRequest.java
index 17764538ba035424c5efe042ecd0dfa820b84aeb..e4b2037e6eed7a8609c90f7df18b70d0e9b5b3bd 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/model/PermissionRequest.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/AddPermissionRequest.java
@@ -3,7 +3,7 @@ package it.inaf.ia2.gms.model;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
-public class PermissionRequest extends PaginatedModelRequest {
+public class AddPermissionRequest extends PaginatedModelRequest {
 
     @NotEmpty
     private String groupId;
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/RemoveMemberRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/RemoveMemberRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff2251574aee036bbc5ceddb1358b0cdbfa2fab1
--- /dev/null
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/RemoveMemberRequest.java
@@ -0,0 +1,14 @@
+package it.inaf.ia2.gms.model;
+
+public class RemoveMemberRequest extends MemberRequest {
+
+    private boolean removeAlsoPermission;
+
+    public boolean isRemoveAlsoPermission() {
+        return removeAlsoPermission;
+    }
+
+    public void setRemoveAlsoPermission(boolean removeAlsoPermission) {
+        this.removeAlsoPermission = removeAlsoPermission;
+    }
+}
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java
index 62460310836177809d82441e9c9d954efefbf9db..2aee489cfd7ecda2c7c09abeba7a384e72587230 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsDAO.java
@@ -23,9 +23,11 @@ public class PermissionsDAO {
         jdbcTemplate = new JdbcTemplate(dataSource);
     }
 
-    public PermissionEntity createPermission(PermissionEntity userPermission) {
+    public PermissionEntity createOrUpdatePermission(PermissionEntity userPermission) {
 
-        String sql = "INSERT INTO gms_permission(group_id, user_id, permission, group_path) VALUES(?, ?, ?, ?)";
+        String sql = "INSERT INTO gms_permission(group_id, user_id, permission, group_path) VALUES(?, ?, ?, ?)\n"
+                + "ON CONFLICT (group_id, user_id) DO UPDATE\n"
+                + "SET permission = EXCLUDED.permission";
 
         jdbcTemplate.update(conn -> {
             PreparedStatement ps = conn.prepareStatement(sql);
@@ -131,15 +133,14 @@ public class PermissionsDAO {
         });
     }
 
-    public void deletePermission(String groupId, String userId, Permission permission) {
+    public void deletePermission(String groupId, String userId) {
 
-        String sql = "DELETE FROM gms_permission WHERE group_id = ? AND user_id = ? AND permission = ?";
+        String sql = "DELETE FROM gms_permission WHERE group_id = ? AND user_id = ?";
 
         jdbcTemplate.update(conn -> {
             PreparedStatement ps = conn.prepareStatement(sql);
             ps.setString(1, groupId);
             ps.setString(2, userId);
-            ps.setObject(3, permission.toString(), Types.OTHER);
             return ps;
         });
     }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
index ea9761d257384e8b3e216bb83178c270eed8a269..667e3fe4517393968a2f7307746b87c5757e3bdd 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
@@ -60,8 +60,8 @@ public class PermissionsService {
         return PermissionUtils.getGroupPermission(group, permissions).orElse(null);
     }
 
-    public void deletePermission(GroupEntity group, String userId, Permission permission) {
-        permissionsDAO.deletePermission(group.getId(), userId, permission);
+    public void removePermission(GroupEntity group, String userId) {
+        permissionsDAO.deletePermission(group.getId(), userId);
     }
 
     public PermissionEntity addPermission(GroupEntity group, String userId, Permission permission) {
@@ -72,7 +72,7 @@ public class PermissionsService {
         permissionEntity.setPermission(permission);
         permissionEntity.setGroupPath(group.getPath());
 
-        return permissionsDAO.createPermission(permissionEntity);
+        return permissionsDAO.createOrUpdatePermission(permissionEntity);
     }
 
     public Optional<PermissionEntity> findPermissionEntity(String groupId, String userId, Permission permission) {
diff --git a/gms/src/main/resources/sql/init.sql b/gms/src/main/resources/sql/init.sql
index 55d7def759ac75b3b19d3eafbfd635ff2632868e..7c5a39766ec955242a2ec897548ac3cf8ed19cc1 100644
--- a/gms/src/main/resources/sql/init.sql
+++ b/gms/src/main/resources/sql/init.sql
@@ -25,7 +25,7 @@ CREATE TABLE gms_permission (
   user_id varchar NOT NULL,
   permission permission_type NOT NULL,
   group_path ltree NOT NULL, -- group_path is copied here for performance reasons
-  primary key (group_id, user_id, permission),
+  primary key (group_id, user_id), -- we can have 1 permission for each group
   foreign key (group_id) references gms_group(id),
   foreign key (group_path) references gms_group(path)
 );
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 8d1a436902c47246de2eaf34877828cc93793f5c..b18fc5a790db88b991167e13b1fd91b667ba8250 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
@@ -2,7 +2,7 @@ package it.inaf.ia2.gms.controller;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import it.inaf.ia2.gms.authn.SessionData;
-import it.inaf.ia2.gms.model.MemberRequest;
+import it.inaf.ia2.gms.model.AddMemberRequest;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.service.GroupsService;
@@ -67,7 +67,7 @@ public class MembersControllerTest {
     @Test
     public void testAddMember() throws Exception {
 
-        MemberRequest request = new MemberRequest();
+        AddMemberRequest request = new AddMemberRequest();
         request.setGroupId("group_id");
         request.setUserId("user_id");
         request.setPaginatorPage(1);
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
index 7aa612e909bd72277c719dba426b862c63758a00..4b635ebb2fd92e59bfa18364fd18136cc11e31e9 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
@@ -3,7 +3,7 @@ package it.inaf.ia2.gms.controller;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import it.inaf.ia2.gms.authn.SessionData;
 import it.inaf.ia2.gms.model.Permission;
-import it.inaf.ia2.gms.model.PermissionRequest;
+import it.inaf.ia2.gms.model.AddPermissionRequest;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.service.GroupsService;
 import it.inaf.ia2.gms.service.PermissionsService;
@@ -21,6 +21,7 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -62,10 +63,29 @@ public class PermissionsControllerTest {
         when(permissionsService.getUserPermissionForGroup(eq(group), eq("admin_id"))).thenReturn(Permission.ADMIN);
     }
 
+    @Test
+    public void testGetPermission() throws Exception {
+
+        when(permissionsService.getUserPermissionForGroup(eq(group), eq("user_id"))).thenReturn(Permission.MANAGE_MEMBERS);
+
+        mockMvc.perform(get("/permission?groupId=group_id&userId=user_id")
+                .contentType(MediaType.APPLICATION_JSON_UTF8))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.permission", is("MANAGE_MEMBERS")));
+    }
+
+    @Test
+    public void testGetInexistentPermission() throws Exception {
+
+        mockMvc.perform(get("/permission?groupId=group_id&userId=user_id")
+                .contentType(MediaType.APPLICATION_JSON_UTF8))
+                .andExpect(status().isNotFound());
+    }
+
     @Test
     public void testAddPermission() throws Exception {
 
-        PermissionRequest request = new PermissionRequest();
+        AddPermissionRequest request = new AddPermissionRequest();
         request.setGroupId("group_id");
         request.setUserId("user_id");
         request.setPermission(Permission.ADMIN);
@@ -82,12 +102,12 @@ public class PermissionsControllerTest {
     }
 
     @Test
-    public void testDeletePermission() throws Exception {
+    public void testRemovePermission() throws Exception {
 
-        mockMvc.perform(delete("/permission?groupId=group_id&userId=user_id&permission=ADMIN&paginatorPage=1&paginatorPageSize=10"))
+        mockMvc.perform(delete("/permission?groupId=group_id&userId=user_id&paginatorPage=1&paginatorPageSize=10"))
                 .andExpect(status().isOk())
                 .andExpect(jsonPath("$.currentPage", is(1)));
 
-        verify(permissionsService, times(1)).deletePermission(eq(group), eq("user_id"), eq(Permission.ADMIN));
+        verify(permissionsService, times(1)).removePermission(eq(group), eq("user_id"));
     }
 }
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java
index ee1d3f1397cb210e4142314aa82aba2e31390d1b..422b915e2a0a56c64bcc45bdca5970fcfea4bd5d 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/WebServiceControllerTest.java
@@ -181,7 +181,7 @@ public class WebServiceControllerTest {
     }
 
     @Test
-    public void testDeletePermission() throws Exception {
+    public void testRemovePermission() throws Exception {
 
         List<String> names = Arrays.asList("LBT", "INAF");
         GroupEntity inaf = getInafGroup();
@@ -190,7 +190,7 @@ public class WebServiceControllerTest {
         mockMvc.perform(delete("/ws/permission?names=LBT&names=INAF&userId=user_id&permission=ADMIN"))
                 .andExpect(status().isNoContent());
 
-        verify(permissionsService, times(1)).deletePermission(eq(inaf), eq("user_id"), eq(Permission.ADMIN));
+        verify(permissionsService, times(1)).removePermission(eq(inaf), eq("user_id"));
     }
 
     @Test
diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
index 88f18082f196ec3462f424b292c130a0ee8d92ef..0b79415a8321b348afd5e4647a56e5b4e6f1dbcc 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/NestedGroupsIntegrationTest.java
@@ -43,7 +43,7 @@ public class NestedGroupsIntegrationTest {
         superAdminPermission.setGroupId(GroupsService.ROOT);
         superAdminPermission.setPermission(Permission.ADMIN);
         superAdminPermission.setGroupPath("");
-        permissionsDAO.createPermission(superAdminPermission);
+        permissionsDAO.createOrUpdatePermission(superAdminPermission);
 
         // Setup groups
         GroupEntity root = groupsService.getRoot();
@@ -95,29 +95,28 @@ public class NestedGroupsIntegrationTest {
         assertFalse(p2.isHasChildren());
 
         // Setup lower permissions
-        permissionsDAO.deletePermission(superAdminPermission.getGroupId(),
-                superAdminPermission.getUserId(), superAdminPermission.getPermission());
+        permissionsDAO.deletePermission(superAdminPermission.getGroupId(), superAdminPermission.getUserId());
 
         PermissionEntity p1Permission = new PermissionEntity();
         p1Permission.setUserId(userId);
         p1Permission.setGroupId(lbtInafProgram1.getId());
         p1Permission.setPermission(Permission.MANAGE_MEMBERS);
         p1Permission.setGroupPath(lbtInafProgram1.getPath());
-        permissionsDAO.createPermission(p1Permission);
+        permissionsDAO.createOrUpdatePermission(p1Permission);
 
         PermissionEntity lbtPermission = new PermissionEntity();
         lbtPermission.setUserId(userId);
         lbtPermission.setGroupId(lbtInaf.getId());
         lbtPermission.setPermission(Permission.VIEW_MEMBERS);
         lbtPermission.setGroupPath(lbtInaf.getPath());
-        permissionsDAO.createPermission(lbtPermission);
+        permissionsDAO.createOrUpdatePermission(lbtPermission);
 
         PermissionEntity radioPermission = new PermissionEntity();
         radioPermission.setUserId(userId);
         radioPermission.setGroupId(radio.getId());
         radioPermission.setPermission(Permission.VIEW_MEMBERS);
         radioPermission.setGroupPath(radio.getPath());
-        permissionsDAO.createPermission(radioPermission);
+        permissionsDAO.createOrUpdatePermission(radioPermission);
 
         // Check level 0 (ROOT)
         groupNodes = groupsTreeBuilder.listSubGroups(root.getId(), userId, request).getItems();
diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/PermissionsDAOTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/PermissionsDAOTest.java
index 6f411d818821c55396fa458448552a801bc3b3e2..0bffd30034d022ef56f0058e05768ffe9e8e641d 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/persistence/PermissionsDAOTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/PermissionsDAOTest.java
@@ -48,7 +48,7 @@ public class PermissionsDAOTest {
         permission.setPermission(Permission.ADMIN);
         permission.setGroupPath(root.getPath());
 
-        permissionsDAO.createPermission(permission);
+        permissionsDAO.createOrUpdatePermission(permission);
 
         List<PermissionEntity> permissions = permissionsDAO.findUserPermissions(userId);
 
@@ -62,7 +62,11 @@ public class PermissionsDAOTest {
         permissions = permissionsDAO.getGroupsPermissions(root.getId());
         assertEquals(1, permissions.size());
 
-        permissionsDAO.deletePermission(permission.getGroupId(), permission.getUserId(), permission.getPermission());
+        // test upsert
+        permission.setPermission(Permission.MANAGE_MEMBERS);
+        permissionsDAO.createOrUpdatePermission(permission);
+
+        permissionsDAO.deletePermission(permission.getGroupId(), permission.getUserId());
 
         permissions = permissionsDAO.findUserPermissions(userId);
         assertTrue(permissions.isEmpty());
diff --git a/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java
index 3d5c94493ce32cb7f45109d5ded8c977fd62ea1d..c296be93e38b123f8a6a917d7ccd449cc8af1b36 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java
@@ -59,7 +59,7 @@ public class PermissionsServiceIntegrationTest {
         superAdminPermission.setGroupId(root.getId());
         superAdminPermission.setPermission(Permission.ADMIN);
         superAdminPermission.setGroupPath(root.getPath());
-        permissionsDAO.createPermission(superAdminPermission);
+        permissionsDAO.createOrUpdatePermission(superAdminPermission);
 
         List<UserPermission> permissions = permissionsService.getAllPermissions(root);
 
@@ -67,6 +67,6 @@ public class PermissionsServiceIntegrationTest {
         assertEquals(Permission.ADMIN, permissions.get(0).getPermission());
         assertEquals(USER_ID, permissions.get(0).getUser().getId());
 
-        permissionsService.deletePermission(root, USER_ID, Permission.ADMIN);
+        permissionsService.removePermission(root, USER_ID);
     }
 }