Commit c5de9aa2 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Added endpoints on JWTWebServiceController

parent 65a91b9f
......@@ -60,3 +60,5 @@ nbactions.xml
/gms-client/gms-client-lib/target/
/gms-client/gms-cli/target/
/gms/node/
nb-configuration.xml
......@@ -2,10 +2,19 @@ package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.authn.RapPrincipal;
import it.inaf.ia2.gms.exception.BadRequestException;
import it.inaf.ia2.gms.exception.UnauthorizedException;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.LoggingDAO;
import it.inaf.ia2.gms.persistence.MembershipsDAO;
import it.inaf.ia2.gms.persistence.PermissionsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.service.GroupsService;
import it.inaf.ia2.gms.service.JoinService;
import it.inaf.ia2.gms.service.MembersService;
import it.inaf.ia2.gms.service.PermissionUtils;
import it.inaf.ia2.gms.service.PermissionsService;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Principal;
......@@ -16,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
......@@ -42,6 +52,21 @@ public class JWTWebServiceController {
@Autowired
private GroupsDAO groupsDAO;
@Autowired
private GroupsService groupsService;
@Autowired
private MembersService membersService;
@Autowired
private PermissionsService permissionsService;
@Autowired
private PermissionsDAO permissionsDAO;
@Autowired
private LoggingDAO loggingDAO;
/**
* This endpoint is compliant with the IVOA GMS standard.
*/
......@@ -50,18 +75,12 @@ public class JWTWebServiceController {
List<GroupEntity> memberships = membershipsDAO.getUserMemberships(principal.getName());
// We need to return the complete group name, so it is necessary to load
// all the parents too.
Map<String, String> idNameMap = new HashMap<>();
Set<String> allIdentifiers = getAllIdentifiers(memberships);
for (GroupEntity group : groupsDAO.findGroupsByIds(allIdentifiers)) {
idNameMap.put(group.getId(), group.getName());
}
List<String> names = getGroupsNames(memberships);
try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (GroupEntity group : memberships) {
pw.println(getGroupCompleteName(group, idNameMap));
for (String name : names) {
pw.println(name);
}
}
}
......@@ -105,8 +124,171 @@ public class JWTWebServiceController {
// else: empty response (as defined by GMS standard)
}
@GetMapping(value = {"/list/{group:.+}", "/list"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void listGroups(@PathVariable("group") Optional<String> group, Principal principal, HttpServletResponse response) throws IOException {
String userId = principal.getName();
List<String> groupNames = extractGroupNames(group);
GroupEntity parentGroup = getGroupFromNames(groupNames);
List<GroupEntity> allSubGroups = groupsDAO.getDirectSubGroups(parentGroup.getPath());
// Select only the groups visible to the user
List<PermissionEntity> permissions = permissionsDAO.findUserPermissions(userId);
List<GroupEntity> visibleSubgroups = new ArrayList<>();
for (GroupEntity subgroup : allSubGroups) {
PermissionUtils.getGroupPermission(subgroup, permissions).ifPresent(permission -> {
visibleSubgroups.add(subgroup);
});
}
try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (String groupName : getGroupsNames(visibleSubgroups)) {
if (group.isPresent()) {
String shortName = groupName.substring(group.get().length() + 1);
pw.println(shortName);
} else {
pw.println(groupName);
}
}
}
}
@PostMapping(value = "/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE)
public void createGroup(@PathVariable("group") String group, Principal principal, HttpServletRequest request, HttpServletResponse response) throws IOException {
String userId = principal.getName();
List<String> groupNames = extractGroupNames(group);
GroupEntity parent = getParentFromNames(groupNames);
String newGroupName = groupNames.get(groupNames.size() - 1);
if (permissionsService.getUserPermissionForGroup(parent, userId) != Permission.ADMIN) {
loggingDAO.logAction("Unauthorized create group request, group_name=" + newGroupName);
throw new UnauthorizedException("Missing admin permission");
}
String leafParam = request.getParameter("leaf");
boolean leaf = leafParam == null ? false : Boolean.valueOf(leafParam);
groupsService.addGroup(parent, newGroupName, leaf);
loggingDAO.logAction("Added group: parent_path=" + parent.getPath() + ", group_name=" + newGroupName);
response.setStatus(HttpServletResponse.SC_CREATED);
try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
pw.println(group);
}
}
@PostMapping(value = {"/membership/{group:.+}", "/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void addMember(@PathVariable("group") Optional<String> group, Principal principal, HttpServletRequest request, HttpServletResponse response) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(group));
String userId = principal.getName();
membersService.verifyUserCanManageMembers(groupEntity, userId);
String targetUserId = request.getParameter("user_id");
if (targetUserId == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing user_id parameter");
return;
}
membersService.addMember(groupEntity.getId(), targetUserId);
loggingDAO.logAction("Added member, group_id=" + groupEntity.getId() + ", user_id=" + targetUserId);
}
@PostMapping(value = {"/permission/{group:.+}", "/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void addPermission(@PathVariable("group") Optional<String> groupNames, Principal principal, HttpServletRequest request, HttpServletResponse response) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames));
String userId = principal.getName();
permissionsService.verifyUserCanManagePermissions(groupEntity, userId);
String targetUserId = request.getParameter("user_id");
if (targetUserId == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing user_id parameter");
return;
}
String permissionParam = request.getParameter("permission");
if (permissionParam == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing permission parameter");
return;
}
Permission permission = Permission.valueOf(permissionParam);
permissionsService.addPermission(groupEntity, targetUserId, permission);
loggingDAO.logAction("Permission added, group_id=" + groupEntity.getId() + ", user_id="
+ targetUserId + ", permission=" + permission);
}
private GroupEntity getGroupFromNames(List<String> groupNames) {
if (groupNames.isEmpty()) {
return getRoot();
}
return getGroupFromNamesAndIndex(groupNames, groupNames.size() - 1);
}
private GroupEntity getParentFromNames(List<String> groupNames) {
if (groupNames.size() == 1) {
return getRoot();
}
return getGroupFromNamesAndIndex(groupNames, groupNames.size() - 2);
}
private GroupEntity getGroupFromNamesAndIndex(List<String> groupNames, int index) {
String parentPath = ""; // starting from ROOT
GroupEntity group = null;
for (int i = 0; i < index + 1; i++) {
String groupName = groupNames.get(i);
group = groupsDAO.findGroupByParentAndName(parentPath, groupName)
.orElseThrow(() -> new IllegalArgumentException("Unable to find group " + groupName));
parentPath = group.getPath();
}
if (group == null) {
throw new IllegalStateException();
}
return group;
}
private GroupEntity getRoot() {
return groupsDAO.findGroupById("ROOT")
.orElseThrow(() -> new IllegalStateException("Missing root group"));
}
/**
* Returns the list of the group complete names, given a list of GroupEntity
* objects.
*/
private List<String> getGroupsNames(List<GroupEntity> groups) {
// We need to return the complete group name, so it is necessary to load
// all the parents too.
Map<String, String> idNameMap = new HashMap<>();
Set<String> allIdentifiers = getAllIdentifiers(groups);
for (GroupEntity group : groupsDAO.findGroupsByIds(allIdentifiers)) {
idNameMap.put(group.getId(), group.getName());
}
List<String> names = new ArrayList<>();
for (GroupEntity group : groups) {
names.add(getGroupCompleteName(group, idNameMap));
}
return names;
}
private List<String> extractGroupNames(Optional<String> group) {
return extractGroupNames(group.orElse(null));
}
private List<String> extractGroupNames(String groupStr) {
if (groupStr == null || groupStr.isEmpty()) {
return new ArrayList<>();
}
List<String> names = new ArrayList<>();
String currentName = "";
for (int i = 0; i < groupStr.length(); i++) {
......
......@@ -64,9 +64,10 @@ public class MembersController {
public ResponseEntity<PaginatedData<RapUser>> addMember(@Valid @RequestBody AddMemberRequest request) {
GroupEntity group = groupsService.getGroupById(request.getGroupId());
Permission currentUserPermission = verifyCurrentUserCanManageMembers(group);
Permission currentUserPermission = membersService.verifyUserCanManageMembers(group, session.getUserId());
membersService.addMember(request.getGroupId(), request.getUserId());
loggingDAO.logAction("Added member, group_id=" + group.getId() + ", user_id=" + request.getUserId());
if (currentUserPermission == Permission.MANAGE_MEMBERS) {
// Automatically assign the VIEW_MEMBERS permission ("Add collaborator" feature)
permissionsService.addPermission(group, request.getUserId(), Permission.VIEW_MEMBERS);
......@@ -86,7 +87,7 @@ public class MembersController {
public ResponseEntity<PaginatedData<RapUser>> removeMember(@Valid RemoveMemberRequest request) {
GroupEntity group = groupsService.getGroupById(request.getGroupId());
Permission currentUserPermission = verifyCurrentUserCanManageMembers(group);
Permission currentUserPermission = membersService.verifyUserCanManageMembers(group, session.getUserId());
membersService.removeMember(group.getId(), request.getUserId());
loggingDAO.logAction("Member removed, group_id=" + group.getId() + ", user_id=" + request.getUserId());
......@@ -110,14 +111,6 @@ public class MembersController {
return ResponseEntity.ok(getMembersPanel(request));
}
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) {
List<RapUser> members = membersService.getMembers(request.getGroupId());
return new PaginatedData<>(members, request.getPaginatorPage(), request.getPaginatorPageSize());
......
......@@ -64,7 +64,7 @@ public class PermissionsController {
public ResponseEntity<Map<String, Permission>> getUserPermission(@RequestParam("groupId") String groupId, @RequestParam("userId") String userId) {
GroupEntity group = groupsService.getGroupById(groupId);
verifyCurrentUserCanManagePermissions(group);
permissionsService.verifyUserCanManagePermissions(group, session.getUserId());
Permission permission = permissionsService.getUserPermissionForGroup(group, userId);
if (permission == null) {
......@@ -80,7 +80,7 @@ public class PermissionsController {
public ResponseEntity<PaginatedData<UserPermission>> addPermission(@Valid @RequestBody AddPermissionRequest request) {
GroupEntity group = groupsService.getGroupById(request.getGroupId());
verifyCurrentUserCanManagePermissions(group);
permissionsService.verifyUserCanManagePermissions(group, session.getUserId());
permissionsService.addPermission(group, request.getUserId(), request.getPermission());
loggingDAO.logAction("Permission added, group_id=" + request.getGroupId() + ", user_id="
......@@ -93,7 +93,7 @@ public class PermissionsController {
public ResponseEntity<PaginatedData<UserPermission>> deletePermission(@Valid MemberRequest request) {
GroupEntity group = groupsService.getGroupById(request.getGroupId());
verifyCurrentUserCanManagePermissions(group);
permissionsService.verifyUserCanManagePermissions(group, session.getUserId());
permissionsService.removePermission(group, request.getUserId());
loggingDAO.logAction("Permission removed, group_id=" + request.getGroupId() + ", user_id=" + request.getUserId());
......@@ -101,14 +101,6 @@ public class PermissionsController {
return ResponseEntity.ok(getPermissionsPanel(group, request));
}
private void verifyCurrentUserCanManagePermissions(GroupEntity group) {
Permission currentNodePermissions = permissionsService.getUserPermissionForGroup(group, session.getUserId());
if (currentNodePermissions != Permission.ADMIN) {
loggingDAO.logAction("Unauthorized attempt to manage permissions");
throw new UnauthorizedException("Only admin users can handle permissions");
}
}
private PaginatedData<UserPermission> getPermissionsPanel(GroupEntity group, PaginatedModelRequest request) {
List<UserPermission> permissions = permissionsService.getAllPermissions(group);
return new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize());
......
......@@ -8,7 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.apache.commons.codec.binary.Base64;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
......@@ -41,19 +41,18 @@ public class RapClient {
@Value("${security.oauth2.client.scope}")
private String scope;
/* Use basic auth instead of JWT when asking for users */
@Value("${rap.ws.basic-auth}")
private boolean basicAuth;
@Autowired
private HttpServletRequest request;
private final SessionData sessionData;
@Autowired(required = false)
private SessionData sessionData;
private final RestTemplate rapRestTemplate;
private final RestTemplate refreshTokenRestTemplate;
@Autowired
public RapClient(SessionData sessionData, RestTemplate rapRestTemplate) {
this.sessionData = sessionData;
public RapClient(RestTemplate rapRestTemplate) {
this.rapRestTemplate = rapRestTemplate;
this.refreshTokenRestTemplate = new RestTemplate();
}
......@@ -94,6 +93,10 @@ public class RapClient {
try {
return function.apply(getEntity(body));
} catch (HttpClientErrorException.Unauthorized ex) {
if (sessionData == null) {
// we can't refresh the token without a session
throw ex;
}
refreshToken();
return function.apply(getEntity(body));
}
......@@ -103,13 +106,11 @@ public class RapClient {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
if (basicAuth) {
String auth = clientId + ":" + clientSecret;
String encodedAuth = Base64.encodeBase64String(auth.getBytes());
headers.add("Authorization", "Basic " + encodedAuth);
} else {
if (sessionData != null) {
headers.add("Authorization", "Bearer " + sessionData.getAccessToken());
} else {
// from JWT web service
headers.add("Authorization", request.getHeader("Authorization"));
}
return new HttpEntity<>(body, headers);
......
package it.inaf.ia2.gms.service;
import it.inaf.ia2.gms.exception.UnauthorizedException;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.persistence.MembershipsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.MembershipEntity;
import it.inaf.ia2.gms.rap.RapClient;
import java.util.List;
......@@ -16,6 +19,9 @@ public class MembersService {
@Autowired
private MembershipsDAO membershipsDAO;
@Autowired
private PermissionsService permissionsService;
@Autowired
private RapClient rapClient;
......@@ -42,4 +48,12 @@ public class MembersService {
public void removeMember(String groupId, String userId) {
membershipsDAO.removeMembership(groupId, userId);
}
public Permission verifyUserCanManageMembers(GroupEntity group, String userId) {
Permission currentNodePermission = permissionsService.getUserPermissionForGroup(group, userId);
if (currentNodePermission != Permission.ADMIN && currentNodePermission != Permission.MANAGE_MEMBERS) {
throw new UnauthorizedException("Missing admin or manage members permissions");
}
return currentNodePermission;
}
}
package it.inaf.ia2.gms.service;
import it.inaf.ia2.gms.exception.UnauthorizedException;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.model.UserPermission;
import it.inaf.ia2.gms.persistence.LoggingDAO;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.persistence.PermissionsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
......@@ -22,11 +24,13 @@ public class PermissionsService {
private final PermissionsDAO permissionsDAO;
private final RapClient rapClient;
private final LoggingDAO loggingDAO;
@Autowired
public PermissionsService(PermissionsDAO permissionsDAO, RapClient rapClient) {
public PermissionsService(PermissionsDAO permissionsDAO, RapClient rapClient, LoggingDAO loggingDAO) {
this.permissionsDAO = permissionsDAO;
this.rapClient = rapClient;
this.loggingDAO = loggingDAO;
}
public List<UserPermission> getAllPermissions(GroupEntity group) {
......@@ -55,6 +59,14 @@ public class PermissionsService {
return result;
}
public void verifyUserCanManagePermissions(GroupEntity group, String userId) {
Permission currentNodePermissions = getUserPermissionForGroup(group, userId);
if (currentNodePermissions != Permission.ADMIN) {
loggingDAO.logAction("Unauthorized attempt to manage permissions");
throw new UnauthorizedException("Only admin users can handle permissions");
}
}
public Permission getUserPermissionForGroup(GroupEntity group, String userId) {
List<PermissionEntity> permissions = permissionsDAO.findUserPermissions(userId, group.getPath());
return PermissionUtils.getGroupPermission(group, permissions).orElse(null);
......
......@@ -5,6 +5,7 @@ import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.model.UserPermission;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.LoggingDAO;
import it.inaf.ia2.gms.persistence.PermissionsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
......@@ -31,6 +32,9 @@ public class PermissionsServiceIntegrationTest {
@MockBean
private RapClient rapClient;
@MockBean
private LoggingDAO loggingDAO;
@Autowired
private DataSource dataSource;
......@@ -45,7 +49,7 @@ public class PermissionsServiceIntegrationTest {
rapUser.setId(USER_ID);
when(rapClient.getUsers(any())).thenReturn(Collections.singletonList(rapUser));
PermissionsService permissionsService = new PermissionsService(permissionsDAO, rapClient);
PermissionsService permissionsService = new PermissionsService(permissionsDAO, rapClient, loggingDAO);
// Create root
GroupEntity root = new GroupEntity();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment