Skip to content
Snippets Groups Projects
Commit c5de9aa2 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Added endpoints on JWTWebServiceController

parent 65a91b9f
No related branches found
No related tags found
No related merge requests found
......@@ -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();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment