Skip to content
package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.exception.BadRequestException;
import it.inaf.ia2.gms.manager.GroupsManager;
import it.inaf.ia2.gms.manager.PermissionsManager;
import it.inaf.ia2.gms.model.request.AddPermissionRequest;
......@@ -7,15 +8,20 @@ import it.inaf.ia2.gms.model.request.MemberRequest;
import it.inaf.ia2.gms.model.response.PaginatedData;
import it.inaf.ia2.gms.model.request.PaginatedModelRequest;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.UserPermission;
import it.inaf.ia2.gms.model.RapUserPermission;
import it.inaf.ia2.gms.model.request.TabRequest;
import it.inaf.ia2.gms.model.request.UpdatePermissionRequest;
import it.inaf.ia2.gms.model.response.UserPermission;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.service.GroupNameService;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
......@@ -39,10 +45,10 @@ public class PermissionsController {
private PermissionsManager permissionsManager;
@GetMapping(value = "/permissions", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PaginatedData<UserPermission>> getPermissionsTab(TabRequest request) {
public ResponseEntity<PaginatedData<RapUserPermission>> getPermissionsTab(TabRequest request) {
GroupEntity group = groupsManager.getGroupById(request.getGroupId());
PaginatedData<UserPermission> permissionsPanel = getPermissionsPanel(group, request);
PaginatedData<RapUserPermission> permissionsPanel = getPermissionsPanel(group, request);
return ResponseEntity.ok(permissionsPanel);
}
......@@ -63,7 +69,7 @@ public class PermissionsController {
}
@PostMapping(value = "/permission", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PaginatedData<UserPermission>> addPermission(@Valid @RequestBody AddPermissionRequest request) {
public ResponseEntity<PaginatedData<RapUserPermission>> addPermission(@Valid @RequestBody AddPermissionRequest request) {
GroupEntity group = groupsManager.getGroupById(request.getGroupId());
if (request.isOverride()) {
......@@ -88,7 +94,7 @@ public class PermissionsController {
}
@DeleteMapping(value = "/permission", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PaginatedData<UserPermission>> deletePermission(@Valid MemberRequest request) {
public ResponseEntity<PaginatedData<RapUserPermission>> deletePermission(@Valid MemberRequest request) {
GroupEntity group = groupsManager.getGroupById(request.getGroupId());
permissionsManager.removePermission(group, request.getUserId());
......@@ -96,8 +102,8 @@ public class PermissionsController {
return ResponseEntity.ok(getPermissionsPanel(group, request));
}
private PaginatedData<UserPermission> getPermissionsPanel(GroupEntity group, PaginatedModelRequest request) {
List<UserPermission> permissions = permissionsManager.getAllPermissions(group);
private PaginatedData<RapUserPermission> getPermissionsPanel(GroupEntity group, PaginatedModelRequest request) {
List<RapUserPermission> permissions = permissionsManager.getAllPermissions(group);
Collections.sort(permissions, (p1, p2) -> {
return p1.getUser().getDisplayName().compareTo(p2.getUser().getDisplayName());
});
......
package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.model.response.PaginatedData;
import it.inaf.ia2.gms.model.response.SearchResponseItem;
import it.inaf.ia2.gms.model.response.UserSearchResponse;
import it.inaf.ia2.gms.service.SearchService;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
......@@ -18,7 +17,7 @@ import org.springframework.web.bind.annotation.RestController;
public class SearchController {
@Autowired
private SessionData sessionData;
private HttpServletRequest servletRequest;
@Autowired
private SearchService searchService;
......@@ -27,14 +26,14 @@ public class SearchController {
public ResponseEntity<PaginatedData<SearchResponseItem>> getSearchResults(@RequestParam("query") String query,
@RequestParam("page") int page, @RequestParam("pageSize") int pageSize) {
PaginatedData<SearchResponseItem> response = searchService.search(query, sessionData.getUserId(), page, pageSize);
PaginatedData<SearchResponseItem> response = searchService.search(query, servletRequest.getUserPrincipal().getName(), page, pageSize);
return ResponseEntity.ok(response);
}
@GetMapping(value = "/search/user/{userId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserSearchResponse> getSearchResultUser(@PathVariable("userId") String userId) {
UserSearchResponse response = searchService.getUserSearchResult(sessionData.getUserId(), userId);
UserSearchResponse response = searchService.getUserSearchResult(servletRequest.getUserPrincipal().getName(), userId);
return ResponseEntity.ok(response);
}
}
package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.rap.RapClient;
import it.inaf.ia2.gms.authn.RapClient;
import it.inaf.ia2.rap.data.RapUser;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
......@@ -18,6 +18,6 @@ public class UsersController {
@GetMapping(value = "users", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<RapUser>> searchUsers(@RequestParam("search") String searchText) {
return ResponseEntity.ok(rapClient.searchUsers(searchText));
return ResponseEntity.ok(rapClient.getUsers(searchText));
}
}
......@@ -2,19 +2,19 @@ package it.inaf.ia2.gms.manager;
import it.inaf.ia2.gms.exception.UnauthorizedException;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.persistence.GroupsDAO;
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 it.inaf.ia2.gms.service.GroupNameService;
import it.inaf.ia2.gms.service.GroupsService;
import it.inaf.ia2.gms.authn.RapClient;
import it.inaf.ia2.rap.data.RapUser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -38,9 +38,6 @@ public class GroupStatusManager extends UserAwareComponent {
@Autowired
private MembershipsDAO membershipsDAO;
@Autowired
private GroupNameService groupNameService;
@Autowired
private RapClient rapClient;
......@@ -50,14 +47,15 @@ public class GroupStatusManager extends UserAwareComponent {
Permission groupPermission = permissionsManager.getCurrentUserPermission(parentGroup);
if (groupPermission != Permission.ADMIN) {
throw new UnauthorizedException("ADMIN permission is needed for performing this action");
if (!Permission.includes(groupPermission, Permission.VIEW_MEMBERS)) {
throw new UnauthorizedException("VIEW_MEMBERS permission is needed for performing this action");
}
List<GroupEntity> groups = groupsDAO.getAllChildren(parentGroup.getPath());
groups.add(parentGroup);
List<String> names = groupNameService.getGroupsNames(groups);
Map<String, String> names = groupsDAO.getGroupCompleteNamesFromId(groups.stream()
.map(g -> g.getId()).collect(Collectors.toSet()));
List<MembershipEntity> memberships = membershipsDAO.findByGroups(groups.stream()
.map(g -> g.getId()).collect(Collectors.toList()));
......@@ -75,26 +73,29 @@ public class GroupStatusManager extends UserAwareComponent {
}
Map<String, String> usersMap = new HashMap<>();
for (RapUser user : rapClient.getUsers(memberships.stream()
.map(u -> u.getUserId()).collect(Collectors.toSet()))) {
usersMap.put(user.getId(), user.getPrimaryEmail());
Set<String> ids = memberships.stream().map(u -> u.getUserId()).collect(Collectors.toSet());
List<RapUser> usersList = rapClient.getUsers(ids);
for (RapUser user : usersList) {
usersMap.put(user.getId(), user.getPrimaryEmailAddress());
}
List<String[]> rows = new ArrayList<>();
for (int i = 0; i < groups.size(); i++) {
GroupEntity group = groups.get(i);
String groupName = names.get(i);
List<String> users = membersMap.get(group.getId());
if (users != null) {
for (String userId : users) {
String email = usersMap.get(userId);
if (email == null) {
LOG.warn("Unable to retrieve information about user " + userId);
continue;
String groupName = names.get(group.getId());
if (groupName != null) {
List<String> users = membersMap.get(group.getId());
if (users != null) {
for (String userId : users) {
String email = usersMap.get(userId);
if (email == null) {
LOG.warn("Unable to retrieve information about user " + userId);
continue;
}
String[] row = new String[]{groupName, email};
rows.add(row);
}
String[] row = new String[]{groupName, email};
rows.add(row);
}
}
}
......
package it.inaf.ia2.gms.manager;
import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.exception.BadRequestException;
import it.inaf.ia2.gms.exception.NotFoundException;
import it.inaf.ia2.gms.exception.UnauthorizedException;
......@@ -13,8 +12,8 @@ import it.inaf.ia2.gms.persistence.MembershipsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.InvitedRegistration;
import it.inaf.ia2.gms.persistence.model.MembershipEntity;
import it.inaf.ia2.gms.rap.RapClient;
import it.inaf.ia2.gms.service.PermissionsService;
import it.inaf.ia2.gms.authn.RapClient;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
......@@ -26,6 +25,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -54,7 +54,7 @@ public class InvitedRegistrationManager extends UserAwareComponent {
private RapClient rapClient;
@Autowired
private SessionData sessionData;
private HttpServletRequest servletRequest;
@Autowired
private LoggingDAO loggingDAO;
......@@ -104,7 +104,7 @@ public class InvitedRegistrationManager extends UserAwareComponent {
public Optional<List<InvitedRegistration>> completeInvitedRegistrationIfNecessary() {
List<InvitedRegistration> invitedRegistrations = completeInvitedRegistrationIfNecessary(sessionData.getUserId());
List<InvitedRegistration> invitedRegistrations = completeInvitedRegistrationIfNecessary(servletRequest.getUserPrincipal().getName());
InvitedRegistration invitedRegistrationFromToken = (InvitedRegistration) httpSession.getAttribute(INVITED_REGISTRATION);
......
......@@ -2,15 +2,15 @@ package it.inaf.ia2.gms.manager;
import it.inaf.ia2.gms.exception.UnauthorizedException;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
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.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.MembershipEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.rap.RapClient;
import it.inaf.ia2.gms.service.PermissionUtils;
import it.inaf.ia2.gms.authn.RapClient;
import it.inaf.ia2.rap.data.RapUser;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
......
......@@ -2,14 +2,14 @@ package it.inaf.ia2.gms.manager;
import it.inaf.ia2.gms.exception.UnauthorizedException;
import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.model.UserPermission;
import it.inaf.ia2.gms.model.RapUserPermission;
import it.inaf.ia2.gms.persistence.LoggingDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.persistence.model.PermissionEntity;
import it.inaf.ia2.gms.rap.RapClient;
import it.inaf.ia2.gms.service.PermissionUtils;
import it.inaf.ia2.gms.service.PermissionsService;
import it.inaf.ia2.gms.authn.RapClient;
import it.inaf.ia2.rap.data.RapUser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
......@@ -34,7 +34,7 @@ public class PermissionsManager extends UserAwareComponent {
this.loggingDAO = loggingDAO;
}
public List<UserPermission> getAllPermissions(GroupEntity group) {
public List<RapUserPermission> getAllPermissions(GroupEntity group) {
verifyUserCanManagePermissions(group);
......@@ -44,15 +44,17 @@ public class PermissionsManager extends UserAwareComponent {
.map(p -> p.getUserId())
.collect(Collectors.toSet());
Map<String, RapUser> users = rapClient.getUsers(userIdentifiers).stream()
List<RapUser> users = rapClient.getUsers(userIdentifiers);
Map<String, RapUser> usersMap = users.stream()
.collect(Collectors.toMap(RapUser::getId, Function.identity()));
List<UserPermission> result = new ArrayList<>();
List<RapUserPermission> result = new ArrayList<>();
for (PermissionEntity p : permissions) {
RapUser rapUser = users.get(p.getUserId());
RapUser rapUser = usersMap.get(p.getUserId());
if (rapUser != null) {
UserPermission permission = new UserPermission();
RapUserPermission permission = new RapUserPermission();
permission.setPermission(p.getPermission());
permission.setUser(rapUser);
result.add(permission);
......@@ -117,6 +119,11 @@ public class PermissionsManager extends UserAwareComponent {
}
}
public List<PermissionEntity> findUserPermissions(GroupEntity group, String userId) {
verifyUserCanManagePermissions(group);
return permissionsService.findUserPermissions(group, userId);
}
public Permission getUserPermission(GroupEntity group, String userId) {
return getUserPermission(group, userId, true);
}
......
package it.inaf.ia2.gms.manager;
import it.inaf.ia2.gms.authn.RapPrincipal;
import it.inaf.ia2.gms.authn.SessionData;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class UserAwareComponent {
@Autowired(required = false)
private SessionData session;
@Autowired
private HttpServletRequest request;
protected String getCurrentUserId() {
if (request.getUserPrincipal() != null && request.getUserPrincipal() instanceof RapPrincipal) {
return request.getUserPrincipal().getName();
} else {
return session.getUserId();
}
return request.getUserPrincipal().getName();
}
}
package it.inaf.ia2.gms.model;
import it.inaf.ia2.gms.model.response.UserGroup;
public class GroupPermission extends UserGroup {
private Permission permission;
public Permission getPermission() {
return permission;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
}
package it.inaf.ia2.gms.model;
public class Identity {
private IdentityType type;
private String typedId;
private String email;
private String name;
private String surname;
private boolean primary;
public IdentityType getType() {
return type;
}
public void setType(IdentityType type) {
this.type = type;
}
public String getTypedId() {
return typedId;
}
public void setTypedId(String typedId) {
this.typedId = typedId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primary) {
this.primary = primary;
}
}
package it.inaf.ia2.gms.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Arrays;
public enum IdentityType {
EDU_GAIN("eduGAIN"),
X509("X.509"),
ORCID("OrcID"),
GOOGLE("Google"),
LINKEDIN("LinkedIn"),
FACEBOOK("Facebook"),
LOCAL_IDP("LocalIdP");
private final String value;
IdentityType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
@JsonCreator
public static IdentityType forValue(String value) {
return Arrays.stream(IdentityType.values())
.filter(it -> value.equals(it.value)).findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unsupported IdentityType " + value));
}
@JsonValue
public String toValue() {
return value;
}
}
package it.inaf.ia2.gms.model;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class RapUser {
private String id;
private List<Identity> identities;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Identity> getIdentities() {
return identities;
}
public void setIdentities(List<Identity> identities) {
this.identities = identities;
}
public String getDisplayName() {
String displayName = null;
// trying to extract name and surname
for (Identity identity : identities) {
if (identity.getName() != null && identity.getSurname() != null) {
displayName = String.format("%s %s", identity.getName(), identity.getSurname());
if (identity.isPrimary()) { // prefer always primary
break;
}
}
}
if (displayName == null) { // No name and surname --> using primary email
displayName = getPrimaryEmail();
}
// Adding types
Set<String> types = identities.stream().map(i -> {
if (i.getType() == IdentityType.EDU_GAIN && i.getTypedId().endsWith("@ia2.inaf.it")) {
return "IA2";
}
return i.getType().getValue();
}).collect(Collectors.toSet());
displayName += String.format(" (%s)", String.join(", ", types));
return displayName;
}
public String getPrimaryEmail() {
Identity primaryIdentity = identities.stream().filter(i -> i.isPrimary()).findFirst()
.orElseThrow(() -> new IllegalStateException("No primary identity for user " + id));
return primaryIdentity.getEmail();
}
}
package it.inaf.ia2.gms.model;
import it.inaf.ia2.rap.data.RapUser;
public class RapUserPermission {
private RapUser user;
private Permission permission;
public RapUser getUser() {
return user;
}
public void setUser(RapUser user) {
this.user = user;
}
public Permission getPermission() {
return permission;
}
public void setPermission(Permission permission) {
this.permission = permission;
}
}
......@@ -2,15 +2,15 @@ package it.inaf.ia2.gms.model;
public class UserPermission {
private RapUser user;
private String userId;
private Permission permission;
public RapUser getUser() {
return user;
public String getUserId() {
return userId;
}
public void setUser(RapUser user) {
this.user = user;
public void setUserId(String userId) {
this.userId = userId;
}
public Permission getPermission() {
......
package it.inaf.ia2.gms.model.response;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.rap.data.RapUser;
import java.util.List;
public class UserSearchResponse {
......
......@@ -8,6 +8,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -159,6 +160,36 @@ public class GroupsDAO {
});
}
/**
* @param groupIds
* @return map having group id as keys and group complete name as values
*/
public Map<String, String> getGroupCompleteNamesFromId(Set<String> groupIds) {
Map<String, String> result = new HashMap<>();
if (groupIds.isEmpty()) {
return result;
}
String sql = "SELECT id, complete_name FROM group_complete_name WHERE id IN ("
+ String.join(",", Collections.nCopies(groupIds.size(), "?")) + ")";
jdbcTemplate.query(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
int i = 0;
for (String groupId : groupIds) {
ps.setString(++i, groupId);
}
return ps;
}, (rs, index) -> {
result.put(rs.getString("id"), rs.getString("complete_name"));
return null;
});
return result;
}
public Optional<GroupEntity> findGroupByParentAndName(String parentPath, String childName) {
String sql = "SELECT id, path, is_leaf, locked from gms_group WHERE name = ? AND path ~ ?";
......
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.authn.RapPrincipal;
import it.inaf.ia2.gms.authn.SessionData;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.PreparedStatement;
......@@ -9,7 +7,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
......@@ -24,9 +21,6 @@ public class LoggingDAO {
@Autowired(required = false)
private HttpServletRequest request;
@Autowired(required = false)
private SessionData sessionData;
@Autowired
public LoggingDAO(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
......@@ -89,13 +83,8 @@ public class LoggingDAO {
}
private String getUser(HttpServletRequest request) {
if (request.getUserPrincipal() != null && request.getUserPrincipal() instanceof RapPrincipal) {
if (request != null && request.getUserPrincipal() != null) {
return request.getUserPrincipal().getName();
} else if (request.getSession(false) != null) {
try {
return sessionData.getUserId();
} catch (BeanCreationException ex) {
}
}
return null;
}
......
......@@ -81,6 +81,10 @@ public class PermissionsDAO {
});
}
/**
* Finds all direct user permissions for a given parent path (returns also
* all sub-groups permissions).
*/
public List<PermissionEntity> findUserPermissions(String userId, String path) {
String sql = "SELECT group_id, permission, group_path FROM gms_permission WHERE user_id = ?\n"
......
package it.inaf.ia2.gms.rap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.model.RapUser;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
@Component
public class RapClient {
private static final Logger LOG = LoggerFactory.getLogger(RapClient.class);
@Value("${rap.ws-url}")
private String rapBaseUrl;
@Value("${security.oauth2.client.access-token-uri}")
private String accessTokenUri;
@Value("${security.oauth2.client.client-id}")
private String clientId;
@Value("${security.oauth2.client.client-secret}")
private String clientSecret;
@Value("${security.oauth2.client.scope}")
private String scope;
/* Use basic auth instead of JWT when asking for users
* Needed for Franco's version. */
@Value("${rap.ws.basic-auth}")
private boolean basicAuth;
@Autowired
private HttpServletRequest request;
@Autowired(required = false)
private SessionData sessionData;
private final RestTemplate rapRestTemplate;
private final RestTemplate refreshTokenRestTemplate;
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
public RapClient(RestTemplate rapRestTemplate) {
this.rapRestTemplate = rapRestTemplate;
this.refreshTokenRestTemplate = new RestTemplate();
}
public RapUser getUser(String userId) {
String url = rapBaseUrl + "/user/" + userId;
return httpCall(entity -> {
return rapRestTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<RapUser>() {
}).getBody();
});
}
public List<RapUser> getUsers(Set<String> identifiers) {
if (identifiers.isEmpty()) {
return new ArrayList<>();
}
String url = rapBaseUrl + "/user?identifiers=" + String.join(",", identifiers);
return httpCall(entity -> {
return rapRestTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<List<RapUser>>() {
}).getBody();
});
}
public List<RapUser> searchUsers(String searchText) {
if (searchText == null || searchText.trim().isEmpty()) {
return new ArrayList<>();
}
String url = rapBaseUrl + "/user?search=" + searchText;
return httpCall(entity -> {
return rapRestTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<List<RapUser>>() {
}).getBody();
});
}
private <R> R httpCall(Function<HttpEntity<?>, R> function) {
return httpCall(function, null);
}
private <R, T> R httpCall(Function<HttpEntity<?>, R> function, T body) {
try {
try {
return function.apply(getEntity(body));
} catch (HttpClientErrorException.Unauthorized ex) {
if (request.getSession(false) == null || sessionData.getExpiresIn() > 0) {
// we can't refresh the token without a session
throw ex;
}
refreshToken();
return function.apply(getEntity(body));
}
} catch (HttpStatusCodeException ex) {
try {
Map<String, String> map = objectMapper.readValue(ex.getResponseBodyAsString(), Map.class);
if (map.containsKey("error")) {
String error = map.get("error");
if (ex instanceof HttpClientErrorException) {
throw new HttpClientErrorException(ex.getStatusCode(), error);
} else if (ex instanceof HttpServerErrorException) {
throw new HttpServerErrorException(ex.getStatusCode(), error);
}
}
} catch (JsonProcessingException ignore) {
}
throw ex;
}
}
private <T> HttpEntity<T> getEntity(T body) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
if (basicAuth) { // Franco's version
String auth = clientId + ":" + clientSecret;
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
headers.add("Authorization", "Basic " + encodedAuth);
HttpSession session = request.getSession(false);
if (session != null) {
String clientDb = (String) session.getAttribute("client_db");
if (clientDb != null) {
headers.add("client_db", clientDb);
LOG.debug("client_db=" + clientDb);
}
}
} else if (request.getSession(false) != null) {
headers.add("Authorization", "Bearer " + sessionData.getAccessToken());
} else {
// from JWT web service
headers.add("Authorization", request.getHeader("Authorization"));
}
return new HttpEntity<>(body, headers);
}
public void refreshToken() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBasicAuth(clientId, clientSecret);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "refresh_token");
map.add("refresh_token", sessionData.getRefreshToken());
map.add("scope", scope.replace(",", " "));
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
ResponseEntity<Map> response = refreshTokenRestTemplate.postForEntity(accessTokenUri, request, Map.class);
Map<String, Object> values = response.getBody();
sessionData.setAccessToken((String) values.get("access_token"));
sessionData.setRefreshToken((String) values.get("refresh_token"));
sessionData.setExpiresIn((int) values.get("expires_in"));
}
}
package it.inaf.ia2.gms.service;
import it.inaf.ia2.gms.exception.BadRequestException;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -20,8 +22,12 @@ import org.springframework.stereotype.Service;
@Service
public class GroupNameService {
private final GroupsDAO groupsDAO;
@Autowired
private GroupsDAO groupsDAO;
public GroupNameService(GroupsDAO groupsDAO) {
this.groupsDAO = groupsDAO;
}
public List<String> getGroupsNamesFromIdentifiers(Set<String> groupIdentifiers) {
return getGroupsNames(groupsDAO.findGroupsByIds(groupIdentifiers));
......@@ -37,113 +43,113 @@ public class GroupNameService {
*/
public 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());
}
Set<String> groupIds = groups.stream().map(g -> g.getId()).collect(Collectors.toSet());
List<String> names = new ArrayList<>();
for (GroupEntity group : groups) {
names.add(getGroupCompleteName(group, idNameMap));
}
return names;
}
List<String> names = new ArrayList<>(groupsDAO.getGroupCompleteNamesFromId(groupIds).values());
private Set<String> getAllIdentifiers(List<GroupEntity> groups) {
Collections.sort(names);
Set<String> allIdentifiers = new HashSet<>();
for (GroupEntity group : groups) {
if (!"".equals(group.getPath())) {
String[] ids = group.getPath().split("\\.");
for (String id : ids) {
allIdentifiers.add(id);
}
}
}
return allIdentifiers;
return names;
}
private String getGroupCompleteName(GroupEntity group, Map<String, String> idNameMap) {
/**
* @param groups
* @return map having group id as keys and group names as values
*/
public Map<String, List<String>> getNames(Set<GroupEntity> groups) {
if ("ROOT".equals(group.getId())) {
return group.getName();
}
Set<String> groupIds = groups.stream()
.map(g -> g.getId()).collect(Collectors.toSet());
List<String> names = new ArrayList<>();
return getNamesFromIds(groupIds);
}
for (String groupId : group.getPath().split("\\.")) {
public Map<String, List<String>> getNamesFromIds(Set<String> groupIds) {
String groupName = idNameMap.get(groupId);
Map<String, List<String>> result = new HashMap<>();
// Dot inside names is considered a special character (because it is
// used to separate the group from its parents), so we use a
// backslash to escape it (client apps need to be aware of this).
groupName = groupName.replace("\\.", "\\\\.");
if (groupIds.contains("ROOT")) {
result.put("ROOT", Collections.singletonList(getRoot().getName()));
}
names.add(groupName);
for (Map.Entry<String, String> entry : groupsDAO.getGroupCompleteNamesFromId(groupIds).entrySet()) {
List<String> names = splitNames(entry.getValue());
result.put(entry.getKey(), names);
}
return String.join(".", names);
return result;
}
/**
* @param groupsIdPath map having group id as keys and group paths as values
* @return map having group id as keys and group names as values
*/
public Map<String, List<String>> getNames(List<Map.Entry<String, String>> groupsIdPath) {
private List<String> splitNames(String completeGroupName) {
return Arrays.asList(completeGroupName.split("(?<!\\\\)\\."));
}
Set<String> allIdentifiers = new HashSet<>();
for (Map.Entry<String, String> entry : groupsIdPath) {
allIdentifiers.addAll(getIdentifiers(entry.getValue()));
public String getShortGroupName(String completeGroupName, Optional<String> groupPrefix) {
if (groupPrefix.isPresent()) {
return completeGroupName.substring(groupPrefix.get().length() + 1);
}
return completeGroupName;
}
public GroupEntity getGroupFromNames(Optional<String> group) {
Map<String, String> groupSingleNamesMap = getGroupSingleNamesMap(allIdentifiers);
List<String> groupNames = extractGroupNames(group);
Map<String, List<String>> groupCompleteNamesMap = new HashMap<>();
for (Map.Entry<String, String> entry : groupsIdPath) {
List<String> groupCompleteName = getGroupCompleteName(groupSingleNamesMap, entry.getValue());
groupCompleteNamesMap.put(entry.getKey(), groupCompleteName);
if (groupNames.isEmpty()) {
return getRoot();
}
return getGroupFromNamesAndIndex(groupNames, groupNames.size() - 1);
}
return groupCompleteNamesMap;
public GroupEntity getGroupFromNamesAndIndex(Optional<String> group, int index) {
List<String> groupNames = extractGroupNames(group);
return getGroupFromNamesAndIndex(groupNames, index);
}
private Map<String, String> getGroupSingleNamesMap(Set<String> allIdentifiers) {
Map<String, String> groupNamesMap = new HashMap<>();
for (GroupEntity group : groupsDAO.findGroupsByIds(allIdentifiers)) {
groupNamesMap.put(group.getId(), group.getName());
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 BadRequestException("Unable to find group " + groupName));
parentPath = group.getPath();
}
if (group == null) {
throw new IllegalStateException();
}
return group;
}
return groupNamesMap;
private List<String> extractGroupNames(Optional<String> group) {
return extractGroupNames(group.orElse(null));
}
private List<String> getGroupCompleteName(Map<String, String> groupNamesMap, String groupPath) {
public List<String> extractGroupNames(String groupStr) {
if (groupStr == null || groupStr.isEmpty()) {
return new ArrayList<>();
}
List<String> names = new ArrayList<>();
if (groupPath.isEmpty()) {
names.add("Root");
} else {
List<String> identifiers = getIdentifiers(groupPath);
for (String groupId : identifiers) {
names.add(groupNamesMap.get(groupId));
String currentName = "";
for (int i = 0; i < groupStr.length(); i++) {
char c = groupStr.charAt(i);
// dot is the group separator and it must be escaped if used inside
// group names
if (c == '.' && groupStr.charAt(i - 1) != '\\') {
names.add(currentName.replace("\\.", "."));
currentName = "";
} else {
currentName += c;
}
}
names.add(currentName);
return names;
}
/**
* Returns the list of all identifiers including parent ones.
*/
private List<String> getIdentifiers(String groupPath) {
List<String> identifiers = new ArrayList<>();
if (!groupPath.isEmpty()) {
for (String id : groupPath.split(Pattern.quote("."))) {
identifiers.add(id);
}
}
return identifiers;
private GroupEntity getRoot() {
return groupsDAO.findGroupById("ROOT")
.orElseThrow(() -> new IllegalStateException("Missing root group"));
}
}