diff --git a/jams-server/src/main/java/net/jami/jams/server/Server.java b/jams-server/src/main/java/net/jami/jams/server/Server.java index 4b26553c451ea57209f23586f8c6a09c5505e6f4..47d94a235d678eeb2b182848626786a08d4f1a81 100644 --- a/jams-server/src/main/java/net/jami/jams/server/Server.java +++ b/jams-server/src/main/java/net/jami/jams/server/Server.java @@ -31,16 +31,21 @@ public class Server { JsoniterRegistry.initCodecs(); } - public static DataStore dataStore; + public static DataStore dataStore; //This one gets loaded via JAR, to make it more flexible. - public static CertificateAuthority certificateAuthority; - public static AuthenticationModule userAuthenticationModule; - public static NameServer nameServer; + public static CertificateAuthority certificateAuthority; + public static AuthenticationModule userAuthenticationModule; + public static NameServer nameServer; + private static TomcatLauncher tomcatLauncher = null; public static void main(String[] args) { //Start tomcat. - TomcatLauncher tomcatLauncher = new TomcatLauncher(); - tomcatLauncher.startServer(); + switch (args.length){ + case 0: tomcatLauncher = new TomcatLauncher(8080); break; + case 1: tomcatLauncher = new TomcatLauncher(Integer.parseInt(args[0])); break; + case 3: tomcatLauncher = new TomcatLauncher(Integer.parseInt(args[0]),args[1],args[2]); + default: log.error("Incorrect number of start arguments provided!"); System.exit(-1); break; + } //Look for the config.json file locally. diff --git a/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java b/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java index d513fe783e9c4e0ba55a9a69a721d0c3fdc7f456..2964501e80eea1c3643acc84bf0846db47b5a64a 100644 --- a/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java +++ b/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java @@ -10,22 +10,36 @@ import org.apache.catalina.webresources.JarResourceSet; import org.apache.catalina.webresources.StandardRoot; import java.io.File; +import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import static net.jami.jams.server.core.TomcatConnectorFactory.getSSLConnectorWithTrustStore; + //This class boots the tomcat server which provides the subsystem //for the API calls. @Slf4j public class TomcatLauncher { private static final Tomcat tomcat = new Tomcat(); - private static StandardContext context; + + public TomcatLauncher(int port) { + tomcat.getService().addConnector(TomcatConnectorFactory.getNoSSLConnector(port)); + this.startServer(); + } + + public TomcatLauncher(int port, String certificateFile, String keyFile) { + //If running in SSL mode, we need a trusts store in order to let clients authenticate. + //In this case this is a bit of a dirty hack... + log.error("This functionality is not yet implemented!"); + } + + public void startServer() { - tomcat.getService().addConnector(TomcatConnectorFactory.getNoSSLConnector(8080)); String jarName = URLDecoder.decode(new File(Server.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getAbsolutePath(), StandardCharsets.UTF_8); log.info("JAR Resource File = " + jarName); - context = (StandardContext) tomcat.addWebapp("", new File(System.getProperty("user.dir")).getAbsolutePath()); + StandardContext context = (StandardContext) tomcat.addWebapp("", new File(System.getProperty("user.dir")).getAbsolutePath()); //Hack to prevent useless verbose messages. context.getJarScanner().setJarScanFilter((jarScanType, s) -> false); WebResourceRoot resources = new StandardRoot(context); @@ -43,7 +57,6 @@ public class TomcatLauncher { basePath.append("/jams-server"); resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", basePath.toString() + "/target/classes/net/jami/jams/server/servlets", "/")); resources.addPreResources(new DirResourceSet(resources, "/", basePath.toString() + "/target/classes", "/webapp")); - } context.setResources(resources); //We always go to login by default. diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..4168c5af31e1d67e4b1bfbae1f256267819dd8fa --- /dev/null +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java @@ -0,0 +1,54 @@ +package net.jami.jams.server.servlets.filters; + +import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jwt.SignedJWT; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import net.jami.jams.common.objects.user.AccessLevel; +import net.jami.jams.server.Server; + +import java.io.IOException; +import java.util.Date; + +import static net.jami.jams.server.Server.userAuthenticationModule; + +@WebFilter(urlPatterns = {"/api/admin/*"}) +@Slf4j +public class AdminApiFilter implements Filter { + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + if (!Server.isInstalled.get()) { + response.sendError(404,"This endpoint requires setup to be complete!"); + } else { + boolean authsuccess = false; + boolean isLogin = false; + if (request.getServletPath().contains("login")) isLogin = true; + if (request.getHeader("Bearer") != null){ + SignedJWT signedJWT = null; + try { + JWSVerifier jwsVerifier = new RSASSAVerifier(userAuthenticationModule.getAuthModulePubKey()); + signedJWT = SignedJWT.parse(request.getHeader("Bearer")); + if(signedJWT.verify(jwsVerifier) && signedJWT.getJWTClaimsSet().getExpirationTime().compareTo(new Date()) > 0 + && AccessLevel.valueOf(signedJWT.getJWTClaimsSet().getClaim("scope").toString()).equals(AccessLevel.ADMIN)){ + authsuccess = true; + request.setAttribute("username",signedJWT.getJWTClaimsSet().getSubject()); + } + } catch (Exception e) { + log.info("Received an invalid token, declining access..."); + } + } + if (authsuccess || isLogin){ + filterChain.doFilter(servletRequest, servletResponse); + } + else response.sendError(403,"This endpoint requires setup to be complete!"); + } + } + +} diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/APIFilter.java b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java similarity index 93% rename from jams-server/src/main/java/net/jami/jams/server/servlets/filters/APIFilter.java rename to jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java index d634a266aef8ec99b7edadcefc51e79f60911afa..c58c7d73b6106a123dc276cff6279c3c89611cbf 100644 --- a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/APIFilter.java +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java @@ -17,7 +17,7 @@ import static net.jami.jams.server.Server.userAuthenticationModule; @WebFilter(urlPatterns = {"/api/auth/*"}) @Slf4j -public class APIFilter implements Filter { +public class ApiFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { @@ -37,7 +37,6 @@ public class APIFilter implements Filter { if(signedJWT.verify(jwsVerifier) && signedJWT.getJWTClaimsSet().getExpirationTime().compareTo(new Date()) > 0){ authsuccess = true; request.setAttribute("username",signedJWT.getJWTClaimsSet().getSubject()); - request.setAttribute("accessLevel",signedJWT.getJWTClaimsSet().getClaim("scope")); } } catch (Exception e) { log.info("Received an invalid token, declining access...");