Skip to content
package it.inaf.ia2.gms.client.call;
import it.inaf.ia2.gms.client.BaseGmsClientTest;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class RemoveMemberTest extends BaseGmsClientTest {
@BeforeEach
@Override
public void init() {
super.init();
}
@Test
public void testRemoveMember() {
CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(204));
when(httpClient.sendAsync(any(), any())).thenReturn(response);
gmsClient.removeMember("LBT.INAF", "user");
verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "ws/jwt/membership/LBT.INAF?user_id=user"), any());
}
}
package it.inaf.ia2.gms.client.call;
import it.inaf.ia2.gms.client.BaseGmsClientTest;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class RemovePermissionTest extends BaseGmsClientTest {
@BeforeEach
@Override
public void init() {
super.init();
}
@Test
public void testRemovePermission() {
CompletableFuture response = CompletableFuture.completedFuture(getMockedResponse(204));
when(httpClient.sendAsync(any(), any())).thenReturn(response);
gmsClient.removePermission("LBT.INAF", "user");
verify(httpClient, times(1)).sendAsync(endpointEq("DELETE", "ws/jwt/permission/LBT.INAF?user_id=user"), any());
}
}
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<span v-if="group.active">{{group.groupName}}</span> <span v-if="group.active">{{group.groupName}}</span>
</li> </li>
</ol> </ol>
<a v-if="currentGroup" :href="'group/status/' + currentGroup.groupId" :download="currentGroup.groupName + '.csv'" id="csv-status-download" title="Download CSV"> <a v-if="currentGroup" :href="'group/status?groupId=' + currentGroup.groupId" :download="currentGroup.groupName + '.csv'" id="csv-status-download" title="Download CSV">
<font-awesome-icon icon="download"></font-awesome-icon> <font-awesome-icon icon="download"></font-awesome-icon>
</a> </a>
</nav> </nav>
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>AuthLib</artifactId> <artifactId>auth-lib</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
...@@ -68,36 +68,46 @@ ...@@ -68,36 +68,46 @@
</dependency> </dependency>
</dependencies> </dependencies>
<profiles>
<profile>
<id>build-gui</id>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.7.6</version>
<configuration>
<nodeVersion>v12.6.0</nodeVersion>
<environmentVariables>
<VUE_APP_SHOW_USER_ID_IN_SEARCH>${show.user_id_in_search}</VUE_APP_SHOW_USER_ID_IN_SEARCH>
</environmentVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>install-node-and-npm</goal>
</goals>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build --prefix ../gms-ui</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build> <build>
<finalName>gms</finalName> <finalName>gms</finalName>
<plugins> <plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.7.6</version>
<configuration>
<nodeVersion>v12.6.0</nodeVersion>
<environmentVariables>
<VUE_APP_SHOW_USER_ID_IN_SEARCH>${show.user_id_in_search}</VUE_APP_SHOW_USER_ID_IN_SEARCH>
</environmentVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>install-node-and-npm</goal>
</goals>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build --prefix ../gms-ui</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version> <version>3.1.0</version>
...@@ -184,4 +194,10 @@ ...@@ -184,4 +194,10 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<repositories>
<repository>
<id>ia2.snapshot</id>
<url>http://repo.ia2.inaf.it/maven/repository/snapshots</url>
</repository>
</repositories>
</project> </project>
...@@ -2,14 +2,11 @@ package it.inaf.ia2.gms; ...@@ -2,14 +2,11 @@ package it.inaf.ia2.gms;
import it.inaf.ia2.aa.AuthConfig; import it.inaf.ia2.aa.AuthConfig;
import it.inaf.ia2.aa.ServiceLocator; import it.inaf.ia2.aa.ServiceLocator;
import it.inaf.ia2.aa.UriCustomizer; import it.inaf.ia2.aa.UserManager;
import it.inaf.ia2.aa.jwt.QueryStringBuilder; import it.inaf.ia2.gms.authn.ServletRapClient;
import static it.inaf.ia2.gms.authn.ClientDbFilter.CLIENT_DB;
import it.inaf.ia2.gms.exception.BadRequestException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
...@@ -20,47 +17,20 @@ public class GmsApplication { ...@@ -20,47 +17,20 @@ public class GmsApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(GmsApplication.class, args); SpringApplication.run(GmsApplication.class, args);
}
AuthConfig authConfig = ServiceLocator.getInstance().getConfig(); @Bean
public AuthConfig authConfig() {
final String defaultAuthorizationUri = authConfig.getUserAuthorizationUri(); return ServiceLocator.getInstance().getConfig();
}
authConfig.setAuthorizationUriCustomizer(new UriCustomizer() {
@Override
public String getBaseUri(HttpServletRequest req) {
// for a better security we should check for allowed redirects
String redirect = req.getParameter("redirect");
if (redirect != null) {
return redirect;
}
return defaultAuthorizationUri;
}
@Override
public void customizeQueryString(HttpServletRequest req, QueryStringBuilder queryStringBuilder) {
String clientDb = req.getParameter(CLIENT_DB);
if (clientDb == null) {
HttpSession session = req.getSession(false);
if (session != null) {
clientDb = (String) session.getAttribute(CLIENT_DB);
}
}
if (clientDb == null) {
throw new BadRequestException("client_db not set");
}
queryStringBuilder.param(CLIENT_DB, clientDb);
}
});
final String defaultAccessTokenUri = authConfig.getAccessTokenUri(); @Bean
public UserManager userManager() {
return ServiceLocator.getInstance().getUserManager();
}
authConfig.setAccessTokenUriCustomizer(req -> { @Bean
String redirect = req.getParameter("token_uri"); public ServletRapClient servletRapClient() {
if (redirect != null) { return (ServletRapClient) ServiceLocator.getInstance().getRapClient();
return redirect;
}
return defaultAccessTokenUri;
});
} }
} }
package it.inaf.ia2.gms.authn; package it.inaf.ia2.gms.authn;
import it.inaf.ia2.aa.ServiceLocator; import it.inaf.ia2.aa.AuthConfig;
import it.inaf.ia2.aa.jwt.JwksClient; import it.inaf.ia2.aa.UserManager;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ClientDbFilter implements Filter { public class ClientDbFilter implements Filter {
public static final String CLIENT_DB = "client_db"; public static final String CLIENT_DB = "client_db";
private String defaultJwksUri; private final UserManager userManager;
private JwksClient jwksClient; private final String defaultJwksUri;
@Override public ClientDbFilter(AuthConfig authConfig, UserManager userManager) {
public void init(FilterConfig filterConfig) throws ServletException { this.userManager = userManager;
defaultJwksUri = ServiceLocator.getInstance().getConfig().getJwksUri(); defaultJwksUri = URI.create(authConfig.getRapBaseUri()).resolve(authConfig.getJwksEndpoint()).toString();
jwksClient = ServiceLocator.getInstance().getJwksClient();
} }
@Override @Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException { public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req; HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String clientDb = request.getParameter(CLIENT_DB); String clientDb = request.getParameter(CLIENT_DB);
if (clientDb != null) { if (clientDb != null) {
request.getSession().setAttribute(CLIENT_DB, clientDb); request.getSession().setAttribute(CLIENT_DB, clientDb);
String newUrl = defaultJwksUri.replaceAll("\\?client_name=(.*)", "?client_name=" + clientDb); String newUrl = defaultJwksUri.replaceAll("\\?client_name=(.*)", "?client_name=" + clientDb);
jwksClient.addJwksUrl(newUrl); userManager.addJwksUri(URI.create(newUrl));
} }
fc.doFilter(req, res); fc.doFilter(req, res);
......
package it.inaf.ia2.gms.authn;
import static it.inaf.ia2.gms.authn.ClientDbFilter.CLIENT_DB;
import it.inaf.ia2.gms.exception.BadRequestException;
import it.inaf.ia2.rap.client.call.GetUserCall;
import it.inaf.ia2.rap.data.RapUser;
import java.net.URI;
import java.net.http.HttpRequest;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ClientDbRapClient extends ServletRapClient {
private static final Logger LOG = LoggerFactory.getLogger(ClientDbRapClient.class);
public ClientDbRapClient(String baseUrl) {
super(baseUrl);
}
@Override
protected HttpRequest.Builder newAuthRequest(HttpRequest.Builder requestBuilder, HttpServletRequest request) {
return setClientDb(super.newClientSecretRequest(requestBuilder), request);
}
@Override
public HttpRequest.Builder newRequest(String endpoint, HttpServletRequest context) {
return setClientDb(super.newRequest(endpoint), context);
}
@Override
public HttpRequest.Builder newRequest(URI uri, HttpServletRequest context) {
return setClientDb(super.newRequest(uri), context);
}
private HttpRequest.Builder setClientDb(HttpRequest.Builder builder, HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
String clientDb = (String) session.getAttribute("client_db");
if (clientDb != null) {
builder.setHeader("client_db", clientDb);
LOG.debug("client_db=" + clientDb);
}
}
return builder;
}
@Override
public URI getAuthorizationUri(HttpServletRequest request) {
// for a better security we should check for allowed redirects
String redirect = request.getParameter("redirect");
URI uri;
if (redirect != null) {
uri = URI.create(redirect);
} else {
uri = super.getAuthorizationUri(request);
}
String clientDb = request.getParameter(CLIENT_DB);
if (clientDb == null) {
HttpSession session = request.getSession(false);
if (session != null) {
clientDb = (String) session.getAttribute(CLIENT_DB);
}
}
if (clientDb == null) {
throw new BadRequestException("client_db not set");
}
redirect = uri.toString();
redirect += redirect.contains("?") ? "&" : "?";
redirect += CLIENT_DB + "=" + clientDb;
return URI.create(redirect);
}
@Override
public URI getAccessTokenUri(HttpServletRequest request) {
String tokenUri = request.getParameter("token_uri");
if (tokenUri != null) {
return URI.create(tokenUri);
}
return super.getAccessTokenUri(request);
}
@Override
public List<RapUser> getUsers(String searchText, HttpServletRequest request) {
List<RapUser> users = new GetUserCall(this).getUsers(searchText, request);
return users.stream()
.filter(u -> u.getDisplayName().contains(searchText) || u.getPrimaryEmailAddress().contains(searchText))
.collect(Collectors.toList());
}
}
...@@ -26,6 +26,11 @@ public class GmsLoginFilter extends LoginFilter { ...@@ -26,6 +26,11 @@ public class GmsLoginFilter extends LoginFilter {
private boolean shouldNotFilter(HttpServletRequest request) throws ServletException { private boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
if (request.getUserPrincipal() != null) {
// Principal set using JWT
return true;
}
// Allow CORS check // Allow CORS check
if ("OPTIONS".equals(request.getMethod())) { if ("OPTIONS".equals(request.getMethod())) {
return true; return true;
......
package it.inaf.ia2.gms.authn; package it.inaf.ia2.gms.authn;
import io.jsonwebtoken.Jwt; import it.inaf.ia2.aa.UserManager;
import io.jsonwebtoken.Jwts; import it.inaf.ia2.aa.data.User;
import io.jsonwebtoken.SigningKeyResolver;
import it.inaf.ia2.aa.ServiceLocator;
import it.inaf.ia2.gms.persistence.LoggingDAO; import it.inaf.ia2.gms.persistence.LoggingDAO;
import java.io.IOException; import java.io.IOException;
import java.security.Principal; import java.security.Principal;
...@@ -16,15 +14,16 @@ import javax.servlet.ServletResponse; ...@@ -16,15 +14,16 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class JWTFilter implements Filter { public class JWTFilter implements Filter {
private final LoggingDAO loggingDAO; private final LoggingDAO loggingDAO;
private final SigningKeyResolver signingKeyResolver; private final UserManager userManager;
public JWTFilter(LoggingDAO loggingDAO) { public JWTFilter(LoggingDAO loggingDAO, UserManager userManager) {
this.loggingDAO = loggingDAO; this.loggingDAO = loggingDAO;
this.signingKeyResolver = ServiceLocator.getInstance().getTokenManager().getSigningKeyResolver(); this.userManager = userManager;
} }
@Override @Override
...@@ -34,19 +33,26 @@ public class JWTFilter implements Filter { ...@@ -34,19 +33,26 @@ public class JWTFilter implements Filter {
HttpServletResponse response = (HttpServletResponse) res; HttpServletResponse response = (HttpServletResponse) res;
String authHeader = request.getHeader("Authorization"); String authHeader = request.getHeader("Authorization");
if (authHeader == null) { if (authHeader == null) {
loggingDAO.logAction("Attempt to access WS without token", request);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Missing Authorization token"); if (request.isRequestedSessionIdValid()) {
HttpSession session = request.getSession(false);
User user = (User) session.getAttribute("user_data");
if (user != null) {
ServletRequestWithSessionPrincipal wrappedRequest = new ServletRequestWithSessionPrincipal(request, user);
fc.doFilter(wrappedRequest, res);
return;
}
}
fc.doFilter(req, res);
return; return;
} }
authHeader = authHeader.replace("Bearer", "").trim(); String token = authHeader.replace("Bearer", "").trim();
Jwt jwt = Jwts.parser() Map<String, Object> claims = userManager.parseIdTokenClaims(token);
.setSigningKeyResolver(signingKeyResolver)
.parse(authHeader);
Map<String, Object> claims = (Map<String, Object>) jwt.getBody();
if (claims.get("sub") == null) { if (claims.get("sub") == null) {
loggingDAO.logAction("Attempt to access WS with invalid token", request); loggingDAO.logAction("Attempt to access WS with invalid token", request);
...@@ -54,19 +60,34 @@ public class JWTFilter implements Filter { ...@@ -54,19 +60,34 @@ public class JWTFilter implements Filter {
return; return;
} }
ServletRequestWithJWTPrincipal wrappedRequest = new ServletRequestWithJWTPrincipal(request, claims); ServletRequestWithJWTPrincipal wrappedRequest = new ServletRequestWithJWTPrincipal(request, token, claims);
loggingDAO.logAction("WS access from " + wrappedRequest.getUserPrincipal().getName(), request); loggingDAO.logAction("WS access from " + wrappedRequest.getUserPrincipal().getName(), request);
fc.doFilter(wrappedRequest, res); fc.doFilter(wrappedRequest, res);
} }
private static class ServletRequestWithSessionPrincipal extends HttpServletRequestWrapper {
private final User principal;
public ServletRequestWithSessionPrincipal(HttpServletRequest request, User user) {
super(request);
this.principal = user;
}
@Override
public Principal getUserPrincipal() {
return principal;
}
}
private static class ServletRequestWithJWTPrincipal extends HttpServletRequestWrapper { private static class ServletRequestWithJWTPrincipal extends HttpServletRequestWrapper {
private final Principal principal; private final RapPrincipal principal;
public ServletRequestWithJWTPrincipal(HttpServletRequest request, Map<String, Object> jwtClaims) { public ServletRequestWithJWTPrincipal(HttpServletRequest request, String token, Map<String, Object> jwtClaims) {
super(request); super(request);
this.principal = new RapPrincipal(jwtClaims); this.principal = new RapPrincipal(token, jwtClaims);
} }
@Override @Override
......
package it.inaf.ia2.gms.authn;
import it.inaf.ia2.rap.client.BoundedRapClient;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
@Component
@RequestScope
public class RapClient extends BoundedRapClient<HttpServletRequest> {
@Autowired
public RapClient(ServletRapClient servletRapClient, HttpServletRequest request) {
super(servletRapClient, request);
}
}
...@@ -5,10 +5,12 @@ import java.util.Map; ...@@ -5,10 +5,12 @@ import java.util.Map;
public class RapPrincipal implements Principal { public class RapPrincipal implements Principal {
private final String token;
private final String sub; private final String sub;
private final String altSub; private final String altSub;
public RapPrincipal(Map<String, Object> jwtClaims) { public RapPrincipal(String token, Map<String, Object> jwtClaims) {
this.token = token;
sub = (String) jwtClaims.get("sub"); sub = (String) jwtClaims.get("sub");
altSub = (String) jwtClaims.get("alt_sub"); altSub = (String) jwtClaims.get("alt_sub");
} }
...@@ -24,4 +26,8 @@ public class RapPrincipal implements Principal { ...@@ -24,4 +26,8 @@ public class RapPrincipal implements Principal {
public String getAlternativeName() { public String getAlternativeName() {
return altSub; return altSub;
} }
public String getToken() {
return token;
}
} }
package it.inaf.ia2.gms.authn; package it.inaf.ia2.gms.authn;
import it.inaf.ia2.aa.AuthConfig;
import it.inaf.ia2.aa.UserManager;
import it.inaf.ia2.gms.persistence.LoggingDAO; import it.inaf.ia2.gms.persistence.LoggingDAO;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -44,9 +46,9 @@ public class SecurityConfig { ...@@ -44,9 +46,9 @@ public class SecurityConfig {
} }
@Bean @Bean
public FilterRegistrationBean clientDbFilter() { public FilterRegistrationBean clientDbFilter(AuthConfig authConfig, UserManager userManager) {
FilterRegistrationBean bean = new FilterRegistrationBean(); FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ClientDbFilter()); bean.setFilter(new ClientDbFilter(authConfig, userManager));
bean.addUrlPatterns("/*"); bean.addUrlPatterns("/*");
bean.setOrder(Ordered.HIGHEST_PRECEDENCE); bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean; return bean;
...@@ -56,10 +58,10 @@ public class SecurityConfig { ...@@ -56,10 +58,10 @@ public class SecurityConfig {
* Checks JWT for web services. * Checks JWT for web services.
*/ */
@Bean @Bean
public FilterRegistrationBean serviceJWTFilter(LoggingDAO loggingDAO) { public FilterRegistrationBean serviceJWTFilter(LoggingDAO loggingDAO, UserManager userManager) {
FilterRegistrationBean bean = new FilterRegistrationBean(); FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new JWTFilter(loggingDAO)); bean.setFilter(new JWTFilter(loggingDAO, userManager));
bean.addUrlPatterns("/ws/jwt/*"); bean.addUrlPatterns("/*");
bean.setOrder(Ordered.HIGHEST_PRECEDENCE); bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean; return bean;
} }
......
package it.inaf.ia2.gms.authn;
import it.inaf.ia2.aa.data.User;
import it.inaf.ia2.rap.client.RapClient;
import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
public class ServletRapClient extends RapClient<HttpServletRequest> {
public ServletRapClient(String baseUrl) {
super(baseUrl);
}
@Override
protected String getAccessToken(HttpServletRequest request) {
Principal principal = request.getUserPrincipal();
if (principal != null) {
if (principal instanceof User) {
return ((User) principal).getAccessToken();
}
if (principal instanceof RapPrincipal) {
return ((RapPrincipal) principal).getToken();
}
}
return null;
}
}
...@@ -14,58 +14,40 @@ public class SessionData { ...@@ -14,58 +14,40 @@ public class SessionData {
private static final String USER_DATA = "user_data"; private static final String USER_DATA = "user_data";
private User user;
@Autowired @Autowired
private HttpServletRequest request; private HttpServletRequest request;
private String userId;
private String userName;
private String accessToken;
private String refreshToken;
private long expiration;
@PostConstruct @PostConstruct
public void init() { public void init() {
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
if (session != null && session.getAttribute(USER_DATA) != null) { if (session != null && session.getAttribute(USER_DATA) != null) {
User user = (User) session.getAttribute(USER_DATA); setUser((User) session.getAttribute(USER_DATA));
userId = user.getName();
userName = user.getUserLabel();
accessToken = user.getAccessToken();
refreshToken = user.getRefreshToken();
setExpiresIn(user.getExpiresIn());
} }
} }
public String getUserId() { public void setUser(User user) {
return userId; this.user = user;
}
public String getAccessToken() {
return accessToken;
} }
public void setAccessToken(String accessToken) { public String getUserId() {
this.accessToken = accessToken; return user.getName();
}
public String getRefreshToken() {
return refreshToken;
} }
public void setRefreshToken(String refreshToken) { public String getUserName() {
this.refreshToken = refreshToken; return user.getUserLabel();
} }
public String getUserName() { public String getAccessToken() {
return userName; return user.getAccessToken();
} }
public void setExpiresIn(long expiresIn) { public String getRefreshToken() {
this.expiration = System.currentTimeMillis() + expiresIn * 1000; return user.getRefreshToken();
} }
public long getExpiresIn() { public long getExpiresIn() {
return (expiration - System.currentTimeMillis()) / 1000; return user.getExpiresIn();
} }
} }
package it.inaf.ia2.gms.controller; package it.inaf.ia2.gms.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.opencsv.CSVWriter; import com.opencsv.CSVWriter;
import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.manager.GroupStatusManager; import it.inaf.ia2.gms.manager.GroupStatusManager;
import it.inaf.ia2.gms.manager.GroupsManager; import it.inaf.ia2.gms.manager.GroupsManager;
import it.inaf.ia2.gms.model.request.AddGroupRequest; import it.inaf.ia2.gms.model.request.AddGroupRequest;
...@@ -13,9 +13,13 @@ import it.inaf.ia2.gms.model.request.GroupsRequest; ...@@ -13,9 +13,13 @@ import it.inaf.ia2.gms.model.request.GroupsRequest;
import it.inaf.ia2.gms.model.request.RenameGroupRequest; import it.inaf.ia2.gms.model.request.RenameGroupRequest;
import it.inaf.ia2.gms.model.request.SearchFilterRequest; import it.inaf.ia2.gms.model.request.SearchFilterRequest;
import it.inaf.ia2.gms.persistence.model.GroupEntity; import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.GroupNameService;
import it.inaf.ia2.gms.service.GroupsTreeBuilder; import it.inaf.ia2.gms.service.GroupsTreeBuilder;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -28,13 +32,16 @@ import org.springframework.web.bind.annotation.PathVariable; ...@@ -28,13 +32,16 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
public class GroupsController { public class GroupsController {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Autowired @Autowired
private SessionData session; private HttpServletRequest servletRequest;
@Autowired @Autowired
private GroupsManager groupsManager; private GroupsManager groupsManager;
...@@ -48,6 +55,9 @@ public class GroupsController { ...@@ -48,6 +55,9 @@ public class GroupsController {
@Autowired @Autowired
private GroupStatusManager groupStatusManager; private GroupStatusManager groupStatusManager;
@Autowired
private GroupNameService groupNameService;
@GetMapping(value = "/groups", produces = MediaType.APPLICATION_JSON_VALUE) @GetMapping(value = "/groups", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getGroupsTab(@Valid GroupsRequest request) { public ResponseEntity<?> getGroupsTab(@Valid GroupsRequest request) {
if (request.isOnlyPanel()) { if (request.isOnlyPanel()) {
...@@ -93,21 +103,40 @@ public class GroupsController { ...@@ -93,21 +103,40 @@ public class GroupsController {
return ResponseEntity.ok(groupsPanel); return ResponseEntity.ok(groupsPanel);
} }
@GetMapping(value = "/group/status/{groupId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) @GetMapping(value = "/group/status", produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE})
public void downloadStatus(@PathVariable("groupId") String groupId, HttpServletResponse response) throws Exception { public void downloadStatus(@RequestParam(value = "groupId", required = false) String groupId,
@RequestParam(value = "groupName", required = false) String groupName,
HttpServletRequest request, HttpServletResponse response) throws Exception {
if (groupId == null && groupName == null) {
response.sendError(400, "Parameter groupId or groupName is required");
return;
}
if (groupId == null) {
GroupEntity group = groupNameService.getGroupFromNames(Optional.of(groupName));
groupId = group.getId();
}
List<String[]> status = groupStatusManager.generateStatus(groupId);
try (OutputStream out = response.getOutputStream(); try ( OutputStream out = response.getOutputStream()) {
CSVWriter writer = new CSVWriter(new OutputStreamWriter(out))) {
writer.writeNext(new String[]{"program", "email"}); if ("application/json".equals(request.getHeader("Accept"))) {
MAPPER.writeValue(out, status);
} else {
try ( CSVWriter writer = new CSVWriter(new OutputStreamWriter(out))) {
writer.writeNext(new String[]{"program", "email"});
for (String[] row : groupStatusManager.generateStatus(groupId)) { for (String[] row : status) {
writer.writeNext(row); writer.writeNext(row);
}
}
} }
} }
} }
private <T extends PaginatedModelRequest & SearchFilterRequest> PaginatedData<GroupNode> getGroupsPanel(GroupEntity parentGroup, T request) { private <T extends PaginatedModelRequest & SearchFilterRequest> PaginatedData<GroupNode> getGroupsPanel(GroupEntity parentGroup, T request) {
return groupsTreeBuilder.listSubGroups(parentGroup, request, session.getUserId()); return groupsTreeBuilder.listSubGroups(parentGroup, request, servletRequest.getUserPrincipal().getName());
} }
} }
package it.inaf.ia2.gms.controller; package it.inaf.ia2.gms.controller;
import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.manager.GroupsManager; import it.inaf.ia2.gms.manager.GroupsManager;
import it.inaf.ia2.gms.manager.InvitedRegistrationManager; import it.inaf.ia2.gms.manager.InvitedRegistrationManager;
import it.inaf.ia2.gms.manager.PermissionsManager; import it.inaf.ia2.gms.manager.PermissionsManager;
...@@ -10,6 +9,7 @@ import it.inaf.ia2.gms.model.response.GroupsTabResponse; ...@@ -10,6 +9,7 @@ import it.inaf.ia2.gms.model.response.GroupsTabResponse;
import it.inaf.ia2.gms.persistence.model.GroupEntity; import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.GroupsService; import it.inaf.ia2.gms.service.GroupsService;
import it.inaf.ia2.gms.service.GroupsTreeBuilder; import it.inaf.ia2.gms.service.GroupsTreeBuilder;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component; ...@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
public class GroupsTabResponseBuilder { public class GroupsTabResponseBuilder {
@Autowired @Autowired
private SessionData session; HttpServletRequest servletRequest;
@Autowired @Autowired
private PermissionsManager permissionsManager; private PermissionsManager permissionsManager;
...@@ -46,7 +46,7 @@ public class GroupsTabResponseBuilder { ...@@ -46,7 +46,7 @@ public class GroupsTabResponseBuilder {
Permission permission = permissionsManager.getCurrentUserPermission(group); Permission permission = permissionsManager.getCurrentUserPermission(group);
response.setPermission(permission); response.setPermission(permission);
response.setGroupsPanel(groupsListBuilder.listSubGroups(group, request, session.getUserId())); response.setGroupsPanel(groupsListBuilder.listSubGroups(group, request, servletRequest.getUserPrincipal().getName()));
response.setLeaf(group.isLeaf()); response.setLeaf(group.isLeaf());
......
...@@ -83,6 +83,10 @@ public class HomePageController { ...@@ -83,6 +83,10 @@ public class HomePageController {
@GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE) @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
public String index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { public String index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// This page MUST NOT be cached to avoid losing the login redirect
response.setHeader("Cache-Control", "no-store, must-revalidate");
response.setHeader("Expires", "0");
Optional<List<InvitedRegistration>> optReg = invitedRegistrationManager.completeInvitedRegistrationIfNecessary(); Optional<List<InvitedRegistration>> optReg = invitedRegistrationManager.completeInvitedRegistrationIfNecessary();
if (optReg.isPresent()) { if (optReg.isPresent()) {
request.setAttribute("invited-registrations", optReg.get()); request.setAttribute("invited-registrations", optReg.get());
......
...@@ -7,7 +7,6 @@ import it.inaf.ia2.gms.manager.InvitedRegistrationManager; ...@@ -7,7 +7,6 @@ import it.inaf.ia2.gms.manager.InvitedRegistrationManager;
import it.inaf.ia2.gms.manager.MembershipManager; import it.inaf.ia2.gms.manager.MembershipManager;
import it.inaf.ia2.gms.manager.PermissionsManager; import it.inaf.ia2.gms.manager.PermissionsManager;
import it.inaf.ia2.gms.model.Permission; import it.inaf.ia2.gms.model.Permission;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.model.response.UserPermission; import it.inaf.ia2.gms.model.response.UserPermission;
import it.inaf.ia2.gms.persistence.GroupsDAO; import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.PermissionsDAO; import it.inaf.ia2.gms.persistence.PermissionsDAO;
...@@ -19,6 +18,7 @@ import it.inaf.ia2.gms.service.GroupsService; ...@@ -19,6 +18,7 @@ import it.inaf.ia2.gms.service.GroupsService;
import it.inaf.ia2.gms.service.JoinService; import it.inaf.ia2.gms.service.JoinService;
import it.inaf.ia2.gms.service.PermissionUtils; import it.inaf.ia2.gms.service.PermissionUtils;
import it.inaf.ia2.gms.service.SearchService; import it.inaf.ia2.gms.service.SearchService;
import it.inaf.ia2.rap.data.RapUser;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.security.Principal; import java.security.Principal;
...@@ -39,15 +39,16 @@ import org.springframework.web.bind.annotation.GetMapping; ...@@ -39,15 +39,16 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/** /**
* Web service called by other web applications using JWT (delegation). * This class needs some refactoring: it contains all endpoints that used JWT.
* Now all endpoints accept both a JWT token or a session, so some of them could
* be removed and others should be moved on dedicated classes. Some endpoints
* match 2 patters to achieve a smooth transition.
*/ */
@RestController @RestController
@RequestMapping("/ws/jwt")
public class JWTWebServiceController { public class JWTWebServiceController {
@Autowired @Autowired
...@@ -63,7 +64,7 @@ public class JWTWebServiceController { ...@@ -63,7 +64,7 @@ public class JWTWebServiceController {
private GroupsService groupsService; private GroupsService groupsService;
@Autowired @Autowired
private GroupNameService groupNameService; protected GroupNameService groupNameService;
@Autowired @Autowired
private MembershipManager membershipManager; private MembershipManager membershipManager;
...@@ -83,7 +84,7 @@ public class JWTWebServiceController { ...@@ -83,7 +84,7 @@ public class JWTWebServiceController {
/** /**
* This endpoint is compliant with the IVOA GMS standard. * This endpoint is compliant with the IVOA GMS standard.
*/ */
@GetMapping(value = "/search", produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/search", "/vo/search"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void getGroups(HttpServletResponse response) throws IOException { public void getGroups(HttpServletResponse response) throws IOException {
List<GroupEntity> memberships = membershipManager.getCurrentUserMemberships(); List<GroupEntity> memberships = membershipManager.getCurrentUserMemberships();
...@@ -104,10 +105,10 @@ public class JWTWebServiceController { ...@@ -104,10 +105,10 @@ public class JWTWebServiceController {
* be defined adding ".+", otherwise Spring will think it is a file * be defined adding ".+", otherwise Spring will think it is a file
* extension (thanks https://stackoverflow.com/a/16333149/771431) * extension (thanks https://stackoverflow.com/a/16333149/771431)
*/ */
@GetMapping(value = "/search/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/search/{group:.+}", "/vo/search/{group:.+}"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void isMemberOf(@PathVariable("group") String group, HttpServletResponse response) throws IOException { public void isMemberOf(@PathVariable("group") String group, HttpServletResponse response) throws IOException {
List<String> groupNames = extractGroupNames(group); List<String> groupNames = groupNameService.extractGroupNames(group);
boolean isMember = membershipManager.isCurrentUserMemberOf("ROOT"); boolean isMember = membershipManager.isCurrentUserMemberOf("ROOT");
if (!isMember) { if (!isMember) {
...@@ -135,13 +136,12 @@ public class JWTWebServiceController { ...@@ -135,13 +136,12 @@ public class JWTWebServiceController {
// else: empty response (as defined by GMS standard) // else: empty response (as defined by GMS standard)
} }
@GetMapping(value = {"/list/{group:.+}", "/list"}, produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/list/{group:.+}", "/ws/jwt/list"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void listGroups(@PathVariable("group") Optional<String> group, Principal principal, HttpServletResponse response) throws IOException { public void listGroups(@PathVariable("group") Optional<String> groupNames, Principal principal, HttpServletResponse response) throws IOException {
String userId = principal.getName(); String userId = principal.getName();
List<String> groupNames = extractGroupNames(group); GroupEntity parentGroup = groupNameService.getGroupFromNames(groupNames);
GroupEntity parentGroup = getGroupFromNames(groupNames);
List<GroupEntity> allSubGroups = groupsDAO.getDirectSubGroups(parentGroup.getPath()); List<GroupEntity> allSubGroups = groupsDAO.getDirectSubGroups(parentGroup.getPath());
...@@ -157,7 +157,7 @@ public class JWTWebServiceController { ...@@ -157,7 +157,7 @@ public class JWTWebServiceController {
try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) { try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (String groupName : groupNameService.getGroupsNames(visibleSubgroups)) { for (String groupName : groupNameService.getGroupsNames(visibleSubgroups)) {
pw.println(getShortGroupName(groupName, group)); pw.println(groupNameService.getShortGroupName(groupName, groupNames));
} }
} }
} }
...@@ -166,10 +166,10 @@ public class JWTWebServiceController { ...@@ -166,10 +166,10 @@ public class JWTWebServiceController {
* Creates a group and its ancestors if they are missing. It doesn't fail if * Creates a group and its ancestors if they are missing. It doesn't fail if
* the last group already exists. * the last group already exists.
*/ */
@PostMapping(value = "/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE) @PostMapping(value = "/ws/jwt/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE)
public void createGroup(@PathVariable("group") String groupParam, HttpServletRequest request, HttpServletResponse response) throws IOException { public void createGroup(@PathVariable("group") String groupParam, HttpServletRequest request, HttpServletResponse response) throws IOException {
List<String> groupNames = extractGroupNames(groupParam); List<String> groupNames = groupNameService.extractGroupNames(groupParam);
String leafParam = request.getParameter("leaf"); String leafParam = request.getParameter("leaf");
boolean leaf = leafParam == null ? false : Boolean.valueOf(leafParam); boolean leaf = leafParam == null ? false : Boolean.valueOf(leafParam);
...@@ -191,29 +191,29 @@ public class JWTWebServiceController { ...@@ -191,29 +191,29 @@ public class JWTWebServiceController {
} }
} }
@DeleteMapping(value = "/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE) @DeleteMapping(value = "/ws/jwt/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE)
public void deleteGroup(@PathVariable("group") String groupParam, HttpServletResponse response) { public void deleteGroup(@PathVariable("group") String groupParam, HttpServletResponse response) {
GroupEntity group = getGroupFromNames(extractGroupNames(groupParam)); GroupEntity group = groupNameService.getGroupFromNames(Optional.of(groupParam));
groupsDAO.deleteGroup(group); groupsDAO.deleteGroup(group);
response.setStatus(HttpServletResponse.SC_NO_CONTENT); response.setStatus(HttpServletResponse.SC_NO_CONTENT);
} }
@GetMapping(value = {"/membership/{group:.+}", "/membership"}, produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/membership/{group:.+}", "/ws/jwt/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void getMembership(@PathVariable("group") Optional<String> group, @RequestParam("user_id") String userId, HttpServletResponse response) throws IOException { public void getMembership(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId, HttpServletResponse response) throws IOException {
GroupEntity parent = getGroupFromNames(extractGroupNames(group)); GroupEntity parent = groupNameService.getGroupFromNames(groupNames);
List<GroupEntity> groups = membershipManager.getUserGroups(parent, userId); List<GroupEntity> groups = membershipManager.getUserGroups(parent, userId);
try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) { try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (String groupName : groupNameService.getGroupsNames(groups)) { for (String groupName : groupNameService.getGroupsNames(groups)) {
pw.println(getShortGroupName(groupName, group)); pw.println(groupNameService.getShortGroupName(groupName, groupNames));
} }
} }
} }
@PostMapping(value = {"/membership/{group:.+}", "/membership"}, produces = MediaType.TEXT_PLAIN_VALUE) @PostMapping(value = {"/ws/jwt/membership/{group:.+}", "/ws/jwt/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void addMember(@PathVariable("group") Optional<String> group, HttpServletRequest request, HttpServletResponse response) throws IOException { public void addMember(@PathVariable("group") Optional<String> groupNames, HttpServletRequest request, HttpServletResponse response) throws IOException {
String targetUserId = request.getParameter("user_id"); String targetUserId = request.getParameter("user_id");
if (targetUserId == null) { if (targetUserId == null) {
...@@ -221,64 +221,64 @@ public class JWTWebServiceController { ...@@ -221,64 +221,64 @@ public class JWTWebServiceController {
return; return;
} }
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(group)); GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
membershipManager.addMember(groupEntity, targetUserId); membershipManager.addMember(groupEntity, targetUserId);
} }
@DeleteMapping(value = {"/membership/{group:.+}", "/membership"}, produces = MediaType.TEXT_PLAIN_VALUE) @DeleteMapping(value = {"/ws/jwt/membership/{group:.+}", "/ws/jwt/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void removeMember(@PathVariable("group") Optional<String> group, @RequestParam("user_id") String userId, public void removeMember(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId,
HttpServletRequest request, HttpServletResponse response) throws IOException { HttpServletRequest request, HttpServletResponse response) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(group)); GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
membershipManager.removeMember(groupEntity, userId); membershipManager.removeMember(groupEntity, userId);
response.setStatus(HttpServletResponse.SC_NO_CONTENT); response.setStatus(HttpServletResponse.SC_NO_CONTENT);
} }
@GetMapping(value = {"/permission/{group:.+}", "/permission"}, produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void getUserPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") Optional<String> userId, HttpServletRequest request, HttpServletResponse response) throws IOException { public void getUserPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") Optional<String> userId, HttpServletRequest request, HttpServletResponse response) throws IOException {
GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
if (userId.isPresent()) { if (userId.isPresent()) {
try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) { try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (UserPermission userPermission : searchService.getUserPermission(userId.get(), permissionsManager.getCurrentUserPermissions(getRoot()))) { for (UserPermission userPermission : searchService.getUserPermission(groupEntity, userId.get(), permissionsManager.getCurrentUserPermissions(groupEntity))) {
String group = String.join(".", userPermission.getGroupCompleteName()); String group = String.join(".", userPermission.getGroupCompleteName());
pw.println(group + " " + userPermission.getPermission()); pw.println(group + " " + userPermission.getPermission());
} }
} }
} else { } else {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames));
try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) { try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (it.inaf.ia2.gms.model.UserPermission up : permissionsManager.getAllPermissions(groupEntity)) { for (it.inaf.ia2.gms.model.RapUserPermission up : permissionsManager.getAllPermissions(groupEntity)) {
pw.println(up.getUser().getId() + " " + up.getPermission()); pw.println(up.getUser().getId() + " " + up.getPermission());
} }
} }
} }
} }
@PostMapping(value = {"/permission/{group:.+}", "/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @PostMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void addPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException { public void addPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames)); GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
permissionsManager.addPermission(groupEntity, targetUserId, permission); permissionsManager.addPermission(groupEntity, targetUserId, permission);
} }
@PutMapping(value = {"/permission/{group:.+}", "/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @PutMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void setPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException { public void setPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String targetUserId, @RequestParam("permission") Permission permission) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames)); GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
permissionsManager.createOrUpdatePermission(groupEntity, targetUserId, permission); permissionsManager.createOrUpdatePermission(groupEntity, targetUserId, permission);
} }
@DeleteMapping(value = {"/permission/{group:.+}", "/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE) @DeleteMapping(value = {"/ws/jwt/permission/{group:.+}", "/ws/jwt/permission/"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void removePermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId, public void removePermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") String userId,
HttpServletRequest request, HttpServletResponse response) throws IOException { HttpServletRequest request, HttpServletResponse response) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames)); GroupEntity groupEntity = groupNameService.getGroupFromNames(groupNames);
permissionsManager.removePermission(groupEntity, userId); permissionsManager.removePermission(groupEntity, userId);
response.setStatus(HttpServletResponse.SC_NO_CONTENT); response.setStatus(HttpServletResponse.SC_NO_CONTENT);
} }
@GetMapping(value = "/check-invited-registration", produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/check-invited-registration", "/check-invited-registration"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void completeInvitedRegistrationIfNecessary(Principal principal, HttpServletResponse response) throws IOException { public void completeInvitedRegistrationIfNecessary(Principal principal, HttpServletResponse response) throws IOException {
String userId = principal.getName(); String userId = principal.getName();
...@@ -300,7 +300,7 @@ public class JWTWebServiceController { ...@@ -300,7 +300,7 @@ public class JWTWebServiceController {
} }
} }
@PostMapping(value = "/invited-registration", produces = MediaType.TEXT_PLAIN_VALUE) @PostMapping(value = {"/ws/jwt/invited-registration", "/invited-registration"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void addInvitedRegistration(@RequestParam("token_hash") String tokenHash, @RequestParam("email") String email, public void addInvitedRegistration(@RequestParam("token_hash") String tokenHash, @RequestParam("email") String email,
@RequestParam("groups") String groupNamesAndPermissionsParam, HttpServletResponse response) { @RequestParam("groups") String groupNamesAndPermissionsParam, HttpServletResponse response) {
...@@ -311,7 +311,7 @@ public class JWTWebServiceController { ...@@ -311,7 +311,7 @@ public class JWTWebServiceController {
int lastSpaceIndex = param.lastIndexOf(" "); int lastSpaceIndex = param.lastIndexOf(" ");
String groupName = param.substring(0, lastSpaceIndex); String groupName = param.substring(0, lastSpaceIndex);
Permission permission = Permission.valueOf(param.substring(lastSpaceIndex + 1)); Permission permission = Permission.valueOf(param.substring(lastSpaceIndex + 1));
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupName)); GroupEntity groupEntity = groupNameService.getGroupFromNames(Optional.of(groupName));
groupsPermissions.put(groupEntity, permission); groupsPermissions.put(groupEntity, permission);
} }
} }
...@@ -321,10 +321,10 @@ public class JWTWebServiceController { ...@@ -321,10 +321,10 @@ public class JWTWebServiceController {
response.setStatus(HttpServletResponse.SC_CREATED); response.setStatus(HttpServletResponse.SC_CREATED);
} }
@GetMapping(value = "/email/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE) @GetMapping(value = {"/ws/jwt/email/{group:.+}", "/email/{group:.+}"}, produces = MediaType.TEXT_PLAIN_VALUE)
public void getEmailOfMembers(@PathVariable("group") String groupNames, @RequestParam("permission") Optional<Permission> permission, HttpServletResponse response) throws IOException { public void getEmailOfMembers(@PathVariable("group") String groupNames, @RequestParam("permission") Optional<Permission> permission, HttpServletResponse response) throws IOException {
GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames)); GroupEntity groupEntity = groupNameService.getGroupFromNames(Optional.of(groupNames));
Set<String> selectedUserIds = null; Set<String> selectedUserIds = null;
if (permission.isPresent()) { if (permission.isPresent()) {
...@@ -340,74 +340,13 @@ public class JWTWebServiceController { ...@@ -340,74 +340,13 @@ public class JWTWebServiceController {
try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) { try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
for (RapUser member : membershipManager.getMembers(groupEntity)) { for (RapUser member : membershipManager.getMembers(groupEntity)) {
if (selectedUserIds == null || selectedUserIds.contains(member.getId())) { if (selectedUserIds == null || selectedUserIds.contains(member.getId())) {
pw.println(member.getPrimaryEmail()); pw.println(member.getPrimaryEmailAddress());
} }
} }
} }
} }
private GroupEntity getGroupFromNames(List<String> groupNames) { @PostMapping(value = {"/ws/jwt/join", "/join"}, produces = MediaType.APPLICATION_JSON_VALUE)
if (groupNames.isEmpty()) {
return getRoot();
}
return getGroupFromNamesAndIndex(groupNames, groupNames.size() - 1);
}
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;
}
private GroupEntity getRoot() {
return groupsDAO.findGroupById("ROOT")
.orElseThrow(() -> new IllegalStateException("Missing root group"));
}
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++) {
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;
}
private String getShortGroupName(String completeGroupName, Optional<String> groupPrefix) {
if (groupPrefix.isPresent()) {
return completeGroupName.substring(groupPrefix.get().length() + 1);
}
return completeGroupName;
}
@PostMapping(value = "/join", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> join(RapPrincipal principal) { public ResponseEntity<?> join(RapPrincipal principal) {
String fromUser = principal.getName(); String fromUser = principal.getName();
......
package it.inaf.ia2.gms.controller; package it.inaf.ia2.gms.controller;
import it.inaf.ia2.aa.ServiceLocator;
import it.inaf.ia2.aa.UserManager;
import it.inaf.ia2.gms.authn.SessionData; import it.inaf.ia2.gms.authn.SessionData;
import it.inaf.ia2.gms.rap.RapClient;
import java.util.HashMap; import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -19,14 +21,17 @@ public class KeepAliveController { ...@@ -19,14 +21,17 @@ public class KeepAliveController {
@Autowired @Autowired
private SessionData sessionData; private SessionData sessionData;
@Autowired private final UserManager userManager;
private RapClient rapClient;
public KeepAliveController() {
userManager = ServiceLocator.getInstance().getUserManager();
}
@GetMapping(value = "/keepAlive", produces = MediaType.APPLICATION_JSON_VALUE) @GetMapping(value = "/keepAlive", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> keepAlive() { public ResponseEntity<?> keepAlive(HttpServletRequest request) {
LOG.trace("Keepalive called"); LOG.trace("Keepalive called");
if (sessionData.getExpiresIn() < 60) { if (sessionData.getExpiresIn() < 60) {
rapClient.refreshToken(); sessionData.setUser(userManager.refreshToken(request));
LOG.trace("RAP token refreshed"); LOG.trace("RAP token refreshed");
} }
// empty JSON object response // empty JSON object response
......
...@@ -4,12 +4,12 @@ import it.inaf.ia2.gms.manager.MembershipManager; ...@@ -4,12 +4,12 @@ import it.inaf.ia2.gms.manager.MembershipManager;
import it.inaf.ia2.gms.manager.PermissionsManager; import it.inaf.ia2.gms.manager.PermissionsManager;
import it.inaf.ia2.gms.model.request.AddMemberRequest; import it.inaf.ia2.gms.model.request.AddMemberRequest;
import it.inaf.ia2.gms.model.response.PaginatedData; import it.inaf.ia2.gms.model.response.PaginatedData;
import it.inaf.ia2.gms.model.RapUser;
import it.inaf.ia2.gms.model.request.PaginatedModelRequest; import it.inaf.ia2.gms.model.request.PaginatedModelRequest;
import it.inaf.ia2.gms.model.request.RemoveMemberRequest; import it.inaf.ia2.gms.model.request.RemoveMemberRequest;
import it.inaf.ia2.gms.model.request.TabRequest; import it.inaf.ia2.gms.model.request.TabRequest;
import it.inaf.ia2.gms.persistence.model.GroupEntity; import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.GroupsService; import it.inaf.ia2.gms.service.GroupsService;
import it.inaf.ia2.rap.data.RapUser;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.validation.Valid; import javax.validation.Valid;
......