diff --git a/.gitignore b/.gitignore index 4ea1475c5332a54f5b6192763bf1b04ec8c9e99a..d1ec16416c57863322f23b09a43ff35d00e7518f 100644 --- a/.gitignore +++ b/.gitignore @@ -101,7 +101,6 @@ jams-react-client/package-lock.json jams-server/src/main/resources/webapp/ # VScode -.vscode/ *.factorypath jams-server/doc/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..fccd0d13a4527fd4800ceb1bc783195000ae0f5e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Attach Debugger", + "request": "attach", + "hostName": "localhost", + "port": 35000, + "projectName": "jams-server" + } + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c0a41452cdaf8719d4860f238f25b2f9a632c785..8e0d99120cfdcb87b26687b760901f0fffe0fdfd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,8 +31,10 @@ RUN mkdir -p /app/jams-server/src/main/resources/webapp \ > /app/jams-server/src/main/resources/webapp/index.html RUN mvn package WORKDIR /app/jams -EXPOSE 3000 8080 -CMD java -jar jams-launcher.jar & npm start --prefix ../jams-react-client +EXPOSE 3000 8080 35000 +ENV JAVA_TOOL_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:35000 +CMD java -jar jams-server.jar 8080 \ + & npm start --prefix ../jams-react-client FROM build as prod WORKDIR /app/jams-react-client diff --git a/README.md b/README.md index 4fe3cec7361a534716f73b070955f9cf8c05f3a1..5db4eb58d39aa254e954699879bd9e4628f1af60 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,10 @@ In order to generate a pair of pem and key use the following command using opens `openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout server.key -out server.pem` +## Run with the debugger enabled + +`java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=localhost:35000 -jar jams-server.jar 8080` + ## Generate documentation To generate the documentation you will need `apidoc` installed on your system. @@ -61,7 +65,7 @@ chmod +x .git/hooks/pre-commit A development environment with react hot reloading can be created using: ``` docker build -f Dockerfile -t jams:dev --target dev . -docker run -it -p 3000:3000 -p 8080:8080 \ +docker run -it -p 3000:3000 -p 8080:8080 -p 35000:35000 \ -v $(pwd)/jams-react-client/src:/app/jams-react-client/src \ -v $(pwd)/jams-react-client/public:/app/jams-react-client/public \ --rm jams:dev 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 9b52529aed4b95d97fdff6306907e1a083576d97..fb0ab3d95c18024d335b1dfa7d781706a11ccbfb 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 @@ -73,10 +73,8 @@ public class TomcatLauncher { public TomcatLauncher(int port, String certificateFile, String keyFile) { if (!Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + certificateFile)) || !Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + keyFile))) { - log.info("Could not find certificate or keyfile, starting in plain HTTP connector as fallback!"); - tomcat.getService().addConnector(TomcatConnectorFactory.getNoSSLConnector(port)); - this.startServer(); - return; + log.info("Could not find certificate or keyfile, exiting"); + System.exit(1); } if (Files.exists(Paths.get(System.getProperty("user.dir") + File.separator + "keystore.jks"))) { log.info("Found a valid trust store, injecting into tomcat!"); diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java index a23bf7453817ed43b2352545561fe62dc53610c4..ac186055912445ffa8d12bdabfdd9d0eda39a5ac 100644 --- a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java +++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java @@ -22,9 +22,18 @@ */ package net.jami.jams.server.core.workflows; -import com.jsoniter.JsonIterator; -import lombok.extern.slf4j.Slf4j; +import static net.jami.jams.authmodule.UserAuthenticationModule.datastore; +import static net.jami.jams.server.Server.certificateAuthority; +import static net.jami.jams.server.Server.dataStore; +import static net.jami.jams.server.Server.nameServer; +import static net.jami.jams.server.Server.userAuthenticationModule; + +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; import net.jami.jams.authmodule.UserAuthenticationModule; import net.jami.jams.common.authmodule.AuthModuleKey; import net.jami.jams.common.dao.StatementElement; @@ -32,24 +41,12 @@ import net.jami.jams.common.dao.StatementList; import net.jami.jams.common.objects.devices.Device; import net.jami.jams.common.objects.requests.DeviceRegistrationRequest; import net.jami.jams.common.objects.responses.DeviceRegistrationResponse; -import net.jami.jams.common.objects.roots.X509Fields; -import net.jami.jams.common.objects.user.*; -import net.jami.jams.dht.DeviceReceiptGenerator; import net.jami.jams.common.objects.user.Group; -import net.jami.jams.dht.ETHAddressGenerator; - - -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Optional; - -import static net.jami.jams.authmodule.UserAuthenticationModule.datastore; -import static net.jami.jams.server.Server.certificateAuthority; -import static net.jami.jams.server.Server.dataStore; -import static net.jami.jams.server.Server.nameServer; -import static net.jami.jams.server.Server.userAuthenticationModule; +import net.jami.jams.common.objects.user.Policy; +import net.jami.jams.common.objects.user.User; +import net.jami.jams.common.objects.user.UserGroupMapping; +import net.jami.jams.common.objects.user.UserProfile; +import net.jami.jams.dht.DeviceReceiptGenerator; @Slf4j public class RegisterDeviceFlow { @@ -60,6 +57,7 @@ public class RegisterDeviceFlow { StatementList statementList = new StatementList(); statementList.addStatement(new StatementElement("username", "=", username, "")); User user = dataStore.getUserDao().getObjects(statementList).get(0); + UserProfile userProfile = userAuthenticationModule.getAuthSources() .get(new AuthModuleKey(user.getRealm(), user.getUserType())) .searchUserProfiles(username, "LOGON_NAME", Optional.empty()).get(0); @@ -69,7 +67,7 @@ public class RegisterDeviceFlow { } // Renew user certificate if expired with same private key - if(!user.getCertificate().getNotAfter().after(new Date())) { + if (!user.getCertificate().getNotAfter().after(new Date())) { user = UserAuthenticationModule.certificateAuthority.getRefreshedCertificate(user); datastore.updateUserCertificate(user); } @@ -85,16 +83,7 @@ public class RegisterDeviceFlow { } dataStore.getDeviceDao().storeObject(device); - Group group = new Group(); - - statementList = new StatementList(); - statementList.addStatement(new StatementElement("username", "=", username, "")); - if (dataStore.getUserGroupMappingsDao().getObjects(statementList) != null && !dataStore.getUserGroupMappingsDao().getObjects(statementList).isEmpty()) { - UserGroupMapping mapping = dataStore.getUserGroupMappingsDao().getObjects(statementList).get(0); - statementList = new StatementList(); - statementList.addStatement(new StatementElement("id", "=", mapping.getGroupId(), "")); - group = dataStore.getGroupDao().getObjects(statementList).get(0); - } + Group group = getGroupByUsername(username); DeviceRegistrationResponse response = new DeviceRegistrationResponse(); String policyData = getPolicyData(group); @@ -122,15 +111,32 @@ public class RegisterDeviceFlow { } } - private static String getPolicyData(Group group) { + public static Group getGroupByUsername(String username) { + Group group = new Group(); + + StatementList statementList = new StatementList(); + statementList.addStatement(new StatementElement("username", "=", username, "")); + List<UserGroupMapping> userGroupMappings = dataStore.getUserGroupMappingsDao().getObjects(statementList); + + if (userGroupMappings != null && !userGroupMappings.isEmpty()) { + UserGroupMapping mapping = userGroupMappings.get(0); + statementList = new StatementList(); + statementList.addStatement(new StatementElement("id", "=", mapping.getGroupId(), "")); + group = dataStore.getGroupDao().getObjects(statementList).get(0); + } + + return group; + } + + public static String getPolicyData(Group group) { if (!group.isEmpty() && group.hasBlueprint()) { - StatementElement st2 = new StatementElement("name", "=", group.getBlueprint(), ""); - StatementList statementList2 = new StatementList(); - statementList2.addStatement((st2)); + StatementElement statementElement = new StatementElement("name", "=", group.getBlueprint(), ""); + StatementList statementList = new StatementList(); + statementList.addStatement(statementElement); try { - Policy policy = dataStore.getPolicyDao().getObjects(statementList2).get(0); + Policy policy = dataStore.getPolicyDao().getObjects(statementList).get(0); return policy.getPolicyData(); - } catch (Exception e1) { + } catch (Exception e) { log.warn("No policy available for user - not adding a policy component to response"); } } diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/policyData/PolicyDataServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/policyData/PolicyDataServlet.java new file mode 100644 index 0000000000000000000000000000000000000000..c2e2d85d3f220df15cca202df31a4e25f250a75a --- /dev/null +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/policyData/PolicyDataServlet.java @@ -0,0 +1,82 @@ +/* +* Copyright (C) 2023 by Savoir-faire Linux +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +package net.jami.jams.server.servlets.api.auth.policyData; + +import java.io.IOException; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import net.jami.jams.common.objects.user.Group; +import net.jami.jams.server.core.workflows.RegisterDeviceFlow; +import net.jami.jams.server.servlets.api.auth.device.DeviceServlet; + +@WebServlet("/api/auth/policyData") +public class PolicyDataServlet extends HttpServlet { + + /** + * @apiVersion 1.0.0 + * @api {get} /api/auth/policyData Get policy data + * @apiName getPolicyData + * @apiGroup Policy Data + * + * + * @apiSuccess (200) {body} Policy Data + * @apiSuccessExample {json} Success-Response: + * [{ + * "allowCertFromHistory": true, + * "allowLookup": true, + * "allowCertFromContact": true, + * "allowCertFromTrusted": true, + * "Account.videoEnabled": true, + * "DHTRelay.PublicInCalls": false, + * "Account.autoAnswer": false, + * "Account.peerDiscovery": true, + * "Account.accountDiscovery": true, + * "Account.accountPublish": true, + * "Account.rendezVous": false, + * "Account.upnpEnabled": true, + * "Account.defaultModerators": "", + * "Account.uiCustomization": + * "{\"areTipsEnabled\":false,\"backgroundType\":\"default\"}" + * }] + * @apiError (500) {null} null Policy Data could not be retrieved + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String username = req.getAttribute("username").toString(); + + Group group = RegisterDeviceFlow.getGroupByUsername(username); + String policyData = RegisterDeviceFlow.getPolicyData(group); + + if (policyData == null) { + resp.setStatus(404); + return; + } + + JsonObject obj = JsonParser.parseString(policyData).getAsJsonObject(); + DeviceServlet.renameKeys(obj); + + resp.getOutputStream().write(obj.toString().getBytes()); + resp.setStatus(200); + } +}