From: Mathieu Baudier Date: Mon, 9 Nov 2020 09:26:59 +0000 (+0100) Subject: Move various CMS extensions to Argeo SLC. X-Git-Tag: argeo-commons-2.1.89~35 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=72788789268d2ac01dcb817d134c057307ba6de8 Move various CMS extensions to Argeo SLC. --- diff --git a/dep/org.argeo.dep.cms.client/pom.xml b/dep/org.argeo.dep.cms.client/pom.xml index 0d56e6380..836577bb6 100644 --- a/dep/org.argeo.dep.cms.client/pom.xml +++ b/dep/org.argeo.dep.cms.client/pom.xml @@ -90,19 +90,6 @@ - - - org.argeo.tp.jackson - com.fasterxml.jackson.core.jackson-core - - - org.argeo.tp.jackson - com.fasterxml.jackson.core.jackson-databind - - - org.argeo.tp.jackson - com.fasterxml.jackson.core.jackson-annotations - org.argeo.tp.bouncycastle @@ -145,10 +132,6 @@ org.argeo.tp.apache.commons org.apache.commons.httpclient - - org.argeo.tp.apache.commons - org.apache.commons.vfs - org.argeo.tp.apache.commons org.apache.commons.net @@ -230,44 +213,6 @@ org.eclipse.equinox.metatype - - - org.argeo.tp.apache - org.apache.mina.core - - - org.argeo.tp.apache - org.apache.tomcat.jni - - - org.argeo.tp.apache - org.apache.sshd.core - - - org.argeo.tp.apache - org.apache.sshd.common - - - org.argeo.tp.apache - org.apache.sshd.sftp - - - org.argeo.tp.apache - org.apache.sshd.scp - - - org.argeo.tp.apache - org.apache.sshd.cli - - - org.argeo.tp.apache - org.apache.sshd.putty - - - org.argeo.tp.misc - net.i2p.crypto.eddsa - - org.argeo.tp.apache.felix diff --git a/dep/org.argeo.dep.cms.node/pom.xml b/dep/org.argeo.dep.cms.node/pom.xml index e8a9045bb..6ee79f98c 100644 --- a/dep/org.argeo.dep.cms.node/pom.xml +++ b/dep/org.argeo.dep.cms.node/pom.xml @@ -35,16 +35,6 @@ org.argeo.maintenance 2.1.89-SNAPSHOT - - - - - - - org.argeo.commons - org.argeo.ext.equinox.jetty - 2.1.89-SNAPSHOT - @@ -144,73 +134,7 @@ org.eclipse.jetty.xml - - - org.argeo.tp.jetty - org.eclipse.jetty.alpn.api - - - org.argeo.tp.jetty - org.eclipse.jetty.alpn.client - - - org.argeo.tp.jetty - org.eclipse.jetty.alpn.server - - - org.argeo.tp.jetty - org.eclipse.jetty.http2.common - - - org.argeo.tp.jetty - org.eclipse.jetty.http2.client - - - org.argeo.tp.jetty - org.eclipse.jetty.http2.client.http - - - org.argeo.tp.jetty - org.eclipse.jetty.http2.server - - - org.argeo.tp.jetty - org.eclipse.jetty.http2.hpack - - - - org.argeo.tp.javax - javax.websocket - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.api - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.common - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.client - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.server - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.servlet - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.javax.websocket - - - org.argeo.tp.jetty - org.eclipse.jetty.websocket.javax.websocket.server - diff --git a/org.argeo.cms/src/org/argeo/cms/integration/CmsExceptionsChain.java b/org.argeo.cms/src/org/argeo/cms/integration/CmsExceptionsChain.java deleted file mode 100644 index bbac176a5..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/CmsExceptionsChain.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** Serialisable wrapper of a {@link Throwable}. */ -public class CmsExceptionsChain { - public final static Log log = LogFactory.getLog(CmsExceptionsChain.class); - - private List exceptions = new ArrayList<>(); - - public CmsExceptionsChain() { - super(); - } - - public CmsExceptionsChain(Throwable exception) { - writeException(exception); - if (log.isDebugEnabled()) - log.error("Exception chain", exception); - } - - public String toJsonString(ObjectMapper objectMapper) { - try { - return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Cannot write system exceptions " + toString(), e); - } - } - - public void writeAsJson(ObjectMapper objectMapper, Writer writer) { - try { - JsonGenerator jg = objectMapper.writerWithDefaultPrettyPrinter().getFactory().createGenerator(writer); - jg.writeObject(this); - } catch (IOException e) { - throw new IllegalStateException("Cannot write system exceptions " + toString(), e); - } - } - - public void writeAsJson(ObjectMapper objectMapper, HttpServletResponse resp) { - try { - resp.setContentType("application/json"); - resp.setStatus(500); - writeAsJson(objectMapper, resp.getWriter()); - } catch (IOException e) { - throw new IllegalStateException("Cannot write system exceptions " + toString(), e); - } - } - - /** recursive */ - protected void writeException(Throwable exception) { - SystemException systemException = new SystemException(exception); - exceptions.add(systemException); - Throwable cause = exception.getCause(); - if (cause != null) - writeException(cause); - } - - public List getExceptions() { - return exceptions; - } - - public void setExceptions(List exceptions) { - this.exceptions = exceptions; - } - - /** An exception in the chain. */ - public static class SystemException { - private String type; - private String message; - private List stackTrace; - - public SystemException() { - } - - public SystemException(Throwable exception) { - this.type = exception.getClass().getName(); - this.message = exception.getMessage(); - this.stackTrace = new ArrayList<>(); - StackTraceElement[] elems = exception.getStackTrace(); - for (int i = 0; i < elems.length; i++) - stackTrace.add("at " + elems[i].toString()); - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public List getStackTrace() { - return stackTrace; - } - - public void setStackTrace(List stackTrace) { - this.stackTrace = stackTrace; - } - - @Override - public String toString() { - return "System exception: " + type + ", " + message + ", " + stackTrace; - } - - } - - @Override - public String toString() { - return exceptions.toString(); - } - -// public static void main(String[] args) throws Exception { -// try { -// try { -// try { -// testDeeper(); -// } catch (Exception e) { -// throw new Exception("Less deep exception", e); -// } -// } catch (Exception e) { -// throw new RuntimeException("Top exception", e); -// } -// } catch (Exception e) { -// CmsExceptionsChain vjeSystemErrors = new CmsExceptionsChain(e); -// ObjectMapper objectMapper = new ObjectMapper(); -// System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(vjeSystemErrors)); -// System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(e)); -// e.printStackTrace(); -// } -// } -// -// static void testDeeper() throws Exception { -// throw new IllegalStateException("Deep exception"); -// } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/CmsLoginServlet.java b/org.argeo.cms/src/org/argeo/cms/integration/CmsLoginServlet.java deleted file mode 100644 index 5bc13526c..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/CmsLoginServlet.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.IOException; -import java.util.Locale; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.argeo.api.NodeConstants; -import org.argeo.cms.auth.CmsSessionId; -import org.argeo.cms.auth.HttpRequestCallback; -import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.osgi.service.useradmin.Authorization; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** Externally authenticate an http session. */ -public class CmsLoginServlet extends HttpServlet { - public final static String PARAM_USERNAME = "username"; - public final static String PARAM_PASSWORD = "password"; - - private static final long serialVersionUID = 2478080654328751539L; - private ObjectMapper objectMapper = new ObjectMapper(); - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - doPost(request, response); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - LoginContext lc = null; - String username = request.getParameter(PARAM_USERNAME); - String password = request.getParameter(PARAM_PASSWORD); - try { - lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response) { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof NameCallback && username != null) - ((NameCallback) callback).setName(username); - else if (callback instanceof PasswordCallback && password != null) - ((PasswordCallback) callback).setPassword(password.toCharArray()); - else if (callback instanceof HttpRequestCallback) { - ((HttpRequestCallback) callback).setRequest(request); - ((HttpRequestCallback) callback).setResponse(response); - } - } - } - }); - lc.login(); - - Subject subject = lc.getSubject(); - CmsSessionId cmsSessionId = extractFrom(subject.getPrivateCredentials(CmsSessionId.class)); - if (cmsSessionId == null) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - Authorization authorization = extractFrom(subject.getPrivateCredentials(Authorization.class)); - Locale locale = extractFrom(subject.getPublicCredentials(Locale.class)); - - CmsSessionDescriptor cmsSessionDescriptor = new CmsSessionDescriptor(authorization.getName(), - cmsSessionId.getUuid().toString(), authorization.getRoles(), authorization.toString(), - locale != null ? locale.toString() : null); - - response.setContentType("application/json"); - JsonGenerator jg = objectMapper.getFactory().createGenerator(response.getWriter()); - jg.writeObject(cmsSessionDescriptor); - - String redirectTo = redirectTo(request); - if (redirectTo != null) - response.sendRedirect(redirectTo); - } catch (LoginException e) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - } - - protected T extractFrom(Set creds) { - if (creds.size() > 0) - return creds.iterator().next(); - else - return null; - } - - /** - * To be overridden in order to return a richer {@link CmsSessionDescriptor} to - * be serialized. - */ - protected CmsSessionDescriptor enrichJson(CmsSessionDescriptor cmsSessionDescriptor) { - return cmsSessionDescriptor; - } - - protected String redirectTo(HttpServletRequest request) { - return null; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/CmsLogoutServlet.java b/org.argeo.cms/src/org/argeo/cms/integration/CmsLogoutServlet.java deleted file mode 100644 index bc37b5f4f..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/CmsLogoutServlet.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.IOException; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.argeo.api.NodeConstants; -import org.argeo.cms.auth.CmsSessionId; -import org.argeo.cms.auth.CurrentUser; -import org.argeo.cms.auth.HttpRequestCallback; -import org.argeo.cms.auth.HttpRequestCallbackHandler; - -/** Externally authenticate an http session. */ -public class CmsLogoutServlet extends HttpServlet { - private static final long serialVersionUID = 2478080654328751539L; - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - doPost(request, response); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - LoginContext lc = null; - try { - lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response) { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof HttpRequestCallback) { - ((HttpRequestCallback) callback).setRequest(request); - ((HttpRequestCallback) callback).setResponse(response); - } - } - } - }); - lc.login(); - - Subject subject = lc.getSubject(); - CmsSessionId cmsSessionId = extractFrom(subject.getPrivateCredentials(CmsSessionId.class)); - if (cmsSessionId != null) {// logged in - CurrentUser.logoutCmsSession(subject); - } - - } catch (LoginException e) { - // ignore - } - - String redirectTo = redirectTo(request); - if (redirectTo != null) - response.sendRedirect(redirectTo); - } - - protected T extractFrom(Set creds) { - if (creds.size() > 0) - return creds.iterator().next(); - else - return null; - } - - protected String redirectTo(HttpServletRequest request) { - return null; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/CmsPrivateServletContext.java b/org.argeo.cms/src/org/argeo/cms/integration/CmsPrivateServletContext.java deleted file mode 100644 index 862d7ee08..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/CmsPrivateServletContext.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.argeo.cms.integration; - -import static org.argeo.api.NodeConstants.LOGIN_CONTEXT_USER; - -import java.io.IOException; -import java.security.AccessControlContext; -import java.security.PrivilegedAction; -import java.util.Map; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.argeo.cms.servlet.ServletAuthUtils; -import org.osgi.service.http.context.ServletContextHelper; - -/** Manages security access to servlets. */ -public class CmsPrivateServletContext extends ServletContextHelper { - public final static String LOGIN_PAGE = "argeo.cms.integration.loginPage"; - public final static String LOGIN_SERVLET = "argeo.cms.integration.loginServlet"; - private String loginPage; - private String loginServlet; - - public void init(Map properties) { - loginPage = properties.get(LOGIN_PAGE); - loginServlet = properties.get(LOGIN_SERVLET); - } - - /** - * Add the {@link AccessControlContext} as a request attribute, or redirect to - * the login page. - */ - @Override - public boolean handleSecurity(final HttpServletRequest request, HttpServletResponse response) throws IOException { - LoginContext lc = null; - - String pathInfo = request.getPathInfo(); - String servletPath = request.getServletPath(); - if ((pathInfo != null && (servletPath + pathInfo).equals(loginPage)) || servletPath.contentEquals(loginServlet)) - return true; - try { - lc = new LoginContext(LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response)); - lc.login(); - } catch (LoginException e) { - lc = processUnauthorized(request, response); - if (lc == null) - return false; - } - Subject.doAs(lc.getSubject(), new PrivilegedAction() { - - @Override - public Void run() { - // TODO also set login context in order to log out ? - ServletAuthUtils.configureRequestSecurity(request); - return null; - } - - }); - - return true; - } - - @Override - public void finishSecurity(HttpServletRequest request, HttpServletResponse response) { - ServletAuthUtils.clearRequestSecurity(request); - } - - protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) { - try { - response.sendRedirect(loginPage); - } catch (IOException e) { - throw new RuntimeException("Cannot redirect to login page", e); - } - return null; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/CmsSessionDescriptor.java b/org.argeo.cms/src/org/argeo/cms/integration/CmsSessionDescriptor.java deleted file mode 100644 index 19c244375..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/CmsSessionDescriptor.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Collections; -import java.util.Set; -import java.util.TreeSet; - -import org.argeo.cms.auth.CmsSession; -import org.osgi.service.useradmin.Authorization; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** A serializable descriptor of an internal {@link CmsSession}. */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class CmsSessionDescriptor implements Serializable, Authorization { - private static final long serialVersionUID = 8592162323372641462L; - - private String name; - private String cmsSessionId; - private String displayName; - private String locale; - private Set roles; - - public CmsSessionDescriptor() { - } - - public CmsSessionDescriptor(String name, String cmsSessionId, String[] roles, String displayName, String locale) { - this.name = name; - this.displayName = displayName; - this.cmsSessionId = cmsSessionId; - this.locale = locale; - this.roles = Collections.unmodifiableSortedSet(new TreeSet<>(Arrays.asList(roles))); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public String getCmsSessionId() { - return cmsSessionId; - } - - public void setCmsSessionId(String cmsSessionId) { - this.cmsSessionId = cmsSessionId; - } - - public Boolean isAnonymous() { - return name == null; - } - - public String getLocale() { - return locale; - } - - public void setLocale(String locale) { - this.locale = locale; - } - - @Override - public boolean hasRole(String name) { - return roles.contains(name); - } - - @Override - public String[] getRoles() { - return roles.toArray(new String[roles.size()]); - } - - public void setRoles(String[] roles) { - this.roles = Collections.unmodifiableSortedSet(new TreeSet<>(Arrays.asList(roles))); - } - - @Override - public int hashCode() { - return cmsSessionId != null ? cmsSessionId.hashCode() : super.hashCode(); - } - - @Override - public String toString() { - return displayName != null ? displayName : name != null ? name : super.toString(); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/CmsTokenServlet.java b/org.argeo.cms/src/org/argeo/cms/integration/CmsTokenServlet.java deleted file mode 100644 index 11a6944b2..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/CmsTokenServlet.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.IOException; -import java.time.ZonedDateTime; -import java.util.Set; -import java.util.UUID; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.argeo.api.NodeConstants; -import org.argeo.cms.CmsUserManager; -import org.argeo.cms.auth.HttpRequestCallback; -import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.argeo.naming.NamingUtils; -import org.osgi.service.useradmin.Authorization; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** Provides access to tokens. */ -public class CmsTokenServlet extends HttpServlet { - private static final long serialVersionUID = 302918711430864140L; - - public final static String PARAM_EXPIRY_DATE = "expiryDate"; - public final static String PARAM_TOKEN = "token"; - - private final static int DEFAULT_HOURS = 24; - - private CmsUserManager userManager; - private ObjectMapper objectMapper = new ObjectMapper(); - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - LoginContext lc = null; - try { - lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request, response) { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof HttpRequestCallback) { - ((HttpRequestCallback) callback).setRequest(request); - ((HttpRequestCallback) callback).setResponse(response); - } - } - } - }); - lc.login(); - } catch (LoginException e) { - // ignore - } - - try { - Subject subject = lc.getSubject(); - Authorization authorization = extractFrom(subject.getPrivateCredentials(Authorization.class)); - String token = UUID.randomUUID().toString(); - String expiryDateStr = request.getParameter(PARAM_EXPIRY_DATE); - ZonedDateTime expiryDate; - if (expiryDateStr != null) { - expiryDate = NamingUtils.ldapDateToZonedDateTime(expiryDateStr); - } else { - expiryDate = ZonedDateTime.now().plusHours(DEFAULT_HOURS); - expiryDateStr = NamingUtils.instantToLdapDate(expiryDate); - } - userManager.addAuthToken(authorization.getName(), token, expiryDate); - - TokenDescriptor tokenDescriptor = new TokenDescriptor(); - tokenDescriptor.setUsername(authorization.getName()); - tokenDescriptor.setToken(token); - tokenDescriptor.setExpiryDate(expiryDateStr); -// tokenDescriptor.setRoles(Collections.unmodifiableSortedSet(new TreeSet<>(Arrays.asList(roles)))); - - response.setContentType("application/json"); - JsonGenerator jg = objectMapper.getFactory().createGenerator(response.getWriter()); - jg.writeObject(tokenDescriptor); - } catch (Exception e) { - new CmsExceptionsChain(e).writeAsJson(objectMapper, response); - } - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - // temporarily wrap POST for ease of testing - doPost(req, resp); - } - - @Override - protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - try { - String token = req.getParameter(PARAM_TOKEN); - userManager.expireAuthToken(token); - } catch (Exception e) { - new CmsExceptionsChain(e).writeAsJson(objectMapper, resp); - } - } - - protected T extractFrom(Set creds) { - if (creds.size() > 0) - return creds.iterator().next(); - else - return null; - } - - public void setUserManager(CmsUserManager userManager) { - this.userManager = userManager; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/JcrReadServlet.java b/org.argeo.cms/src/org/argeo/cms/integration/JcrReadServlet.java deleted file mode 100644 index 83393ec8e..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/JcrReadServlet.java +++ /dev/null @@ -1,319 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.security.AccessControlContext; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.PropertyType; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.Value; -import javax.jcr.nodetype.NodeType; -import javax.security.auth.Subject; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitNode; -import org.apache.jackrabbit.api.JackrabbitValue; -import org.argeo.jcr.JcrUtils; -import org.osgi.service.http.context.ServletContextHelper; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** Access a JCR repository via web services. */ -public class JcrReadServlet extends HttpServlet { - private static final long serialVersionUID = 6536175260540484539L; - private final static Log log = LogFactory.getLog(JcrReadServlet.class); - - protected final static String ACCEPT_HTTP_HEADER = "Accept"; - protected final static String CONTENT_DISPOSITION_HTTP_HEADER = "Content-Disposition"; - - protected final static String OCTET_STREAM_CONTENT_TYPE = "application/octet-stream"; - protected final static String XML_CONTENT_TYPE = "application/xml"; - protected final static String JSON_CONTENT_TYPE = "application/json"; - - private final static String PARAM_VERBOSE = "verbose"; - private final static String PARAM_DEPTH = "depth"; - - protected final static String JCR_NODES = "jcr:nodes"; - // cf. javax.jcr.Property - protected final static String JCR_PATH = "path"; - protected final static String JCR_NAME = "name"; - - protected final static String _JCR = "_jcr"; - protected final static String JCR_PREFIX = "jcr:"; - protected final static String REP_PREFIX = "rep:"; - - private Repository repository; - private Integer maxDepth = 8; - - private ObjectMapper objectMapper = new ObjectMapper(); - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (log.isTraceEnabled()) - log.trace("Data service: " + req.getPathInfo()); - - String dataWorkspace = getWorkspace(req); - String jcrPath = getJcrPath(req); - - boolean verbose = req.getParameter(PARAM_VERBOSE) != null && !req.getParameter(PARAM_VERBOSE).equals("false"); - int depth = 1; - if (req.getParameter(PARAM_DEPTH) != null) { - depth = Integer.parseInt(req.getParameter(PARAM_DEPTH)); - if (depth > maxDepth) - throw new RuntimeException("Depth " + depth + " is higher than maximum " + maxDepth); - } - - Session session = null; - try { - // authentication - session = openJcrSession(req, resp, getRepository(), dataWorkspace); - if (!session.itemExists(jcrPath)) - throw new RuntimeException("JCR node " + jcrPath + " does not exist"); - Node node = session.getNode(jcrPath); - - List acceptHeader = readAcceptHeader(req); - if (!acceptHeader.isEmpty() && node.isNodeType(NodeType.NT_FILE)) { - resp.setContentType(OCTET_STREAM_CONTENT_TYPE); - resp.addHeader(CONTENT_DISPOSITION_HTTP_HEADER, "attachment; filename='" + node.getName() + "'"); - IOUtils.copy(JcrUtils.getFileAsStream(node), resp.getOutputStream()); - resp.flushBuffer(); - } else { - if (!acceptHeader.isEmpty() && acceptHeader.get(0).equals(XML_CONTENT_TYPE)) { - // TODO Use req.startAsync(); ? - resp.setContentType(XML_CONTENT_TYPE); - session.exportSystemView(node.getPath(), resp.getOutputStream(), false, depth <= 1); - return; - } - if (!acceptHeader.isEmpty() && !acceptHeader.contains(JSON_CONTENT_TYPE)) { - if (log.isTraceEnabled()) - log.warn("Content type " + acceptHeader + " in Accept header is not supported. Supported: " - + JSON_CONTENT_TYPE + " (default), " + XML_CONTENT_TYPE); - } - resp.setContentType(JSON_CONTENT_TYPE); - JsonGenerator jsonGenerator = getObjectMapper().getFactory().createGenerator(resp.getWriter()); - jsonGenerator.writeStartObject(); - writeNodeChildren(node, jsonGenerator, depth, verbose); - writeNodeProperties(node, jsonGenerator, verbose); - jsonGenerator.writeEndObject(); - jsonGenerator.flush(); - } - } catch (Exception e) { - new CmsExceptionsChain(e).writeAsJson(getObjectMapper(), resp); - } finally { - JcrUtils.logoutQuietly(session); - } - } - - protected Session openJcrSession(HttpServletRequest req, HttpServletResponse resp, Repository repository, - String workspace) throws RepositoryException { - AccessControlContext acc = (AccessControlContext) req.getAttribute(ServletContextHelper.REMOTE_USER); - Subject subject = Subject.getSubject(acc); - try { - return Subject.doAs(subject, new PrivilegedExceptionAction() { - - @Override - public Session run() throws RepositoryException { - return repository.login(workspace); - } - - }); - } catch (PrivilegedActionException e) { - if (e.getException() instanceof RepositoryException) - throw (RepositoryException) e.getException(); - else - throw new RuntimeException(e.getException()); - } -// return workspace != null ? repository.login(workspace) : repository.login(); - } - - protected String getWorkspace(HttpServletRequest req) { - String path = req.getPathInfo(); - try { - path = URLDecoder.decode(path, StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(e); - } - String[] pathTokens = path.split("/"); - return pathTokens[1]; - } - - protected String getJcrPath(HttpServletRequest req) { - String path = req.getPathInfo(); - try { - path = URLDecoder.decode(path, StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(e); - } - String[] pathTokens = path.split("/"); - String domain = pathTokens[1]; - String jcrPath = path.substring(domain.length() + 1); - return jcrPath; - } - - protected List readAcceptHeader(HttpServletRequest req) { - List lst = new ArrayList<>(); - String acceptHeader = req.getHeader(ACCEPT_HTTP_HEADER); - if (acceptHeader == null) - return lst; -// Enumeration acceptHeader = req.getHeaders(ACCEPT_HTTP_HEADER); -// while (acceptHeader.hasMoreElements()) { - String[] arr = acceptHeader.split("\\."); - for (int i = 0; i < arr.length; i++) { - String str = arr[i].trim(); - if (!"".equals(str)) - lst.add(str); - } -// } - return lst; - } - - protected void writeNodeProperties(Node node, JsonGenerator jsonGenerator, boolean verbose) - throws RepositoryException, IOException { - String jcrPath = node.getPath(); - Map> namespaces = new TreeMap<>(); - - PropertyIterator pit = node.getProperties(); - properties: while (pit.hasNext()) { - Property property = pit.nextProperty(); - - final String propertyName = property.getName(); - int columnIndex = propertyName.indexOf(':'); - if (columnIndex > 0) { - // mark prefix with a '_' before the name of the object, according to JSON - // conventions to indicate a special value - String prefix = "_" + propertyName.substring(0, columnIndex); - String unqualifiedName = propertyName.substring(columnIndex + 1); - if (!namespaces.containsKey(prefix)) - namespaces.put(prefix, new LinkedHashMap()); - Map map = namespaces.get(prefix); - assert !map.containsKey(unqualifiedName); - map.put(unqualifiedName, property); - continue properties; - } - - if (property.getType() == PropertyType.BINARY) { - if (!(node instanceof JackrabbitNode)) { - continue properties;// skip - } - } - - writeProperty(propertyName, property, jsonGenerator); - } - - for (String prefix : namespaces.keySet()) { - Map map = namespaces.get(prefix); - jsonGenerator.writeFieldName(prefix); - jsonGenerator.writeStartObject(); - if (_JCR.equals(prefix)) { - jsonGenerator.writeStringField(JCR_NAME, node.getName()); - jsonGenerator.writeStringField(JCR_PATH, jcrPath); - } - properties: for (String unqualifiedName : map.keySet()) { - Property property = map.get(unqualifiedName); - if (property.getType() == PropertyType.BINARY) { - if (!(node instanceof JackrabbitNode)) { - continue properties;// skip - } - } - writeProperty(unqualifiedName, property, jsonGenerator); - } - jsonGenerator.writeEndObject(); - } - } - - protected void writeProperty(String fieldName, Property property, JsonGenerator jsonGenerator) - throws RepositoryException, IOException { - if (!property.isMultiple()) { - jsonGenerator.writeFieldName(fieldName); - writePropertyValue(property.getType(), property.getValue(), jsonGenerator); - } else { - jsonGenerator.writeFieldName(fieldName); - jsonGenerator.writeStartArray(); - Value[] values = property.getValues(); - for (Value value : values) { - writePropertyValue(property.getType(), value, jsonGenerator); - } - jsonGenerator.writeEndArray(); - } - } - - protected void writePropertyValue(int type, Value value, JsonGenerator jsonGenerator) - throws RepositoryException, IOException { - if (type == PropertyType.DOUBLE) - jsonGenerator.writeNumber(value.getDouble()); - else if (type == PropertyType.LONG) - jsonGenerator.writeNumber(value.getLong()); - else if (type == PropertyType.BINARY) { - if (value instanceof JackrabbitValue) { - String contentIdentity = ((JackrabbitValue) value).getContentIdentity(); - jsonGenerator.writeString("SHA256:" + contentIdentity); - } else { - // TODO write Base64 ? - jsonGenerator.writeNull(); - } - } else - jsonGenerator.writeString(value.getString()); - } - - protected void writeNodeChildren(Node node, JsonGenerator jsonGenerator, int depth, boolean verbose) - throws RepositoryException, IOException { - if (!node.hasNodes()) - return; - if (depth <= 0) - return; - NodeIterator nit; - - nit = node.getNodes(); - children: while (nit.hasNext()) { - Node child = nit.nextNode(); - if (!verbose && child.getName().startsWith(REP_PREFIX)) { - continue children;// skip Jackrabbit auth metadata - } - - jsonGenerator.writeFieldName(child.getName()); - jsonGenerator.writeStartObject(); - writeNodeChildren(child, jsonGenerator, depth - 1, verbose); - writeNodeProperties(child, jsonGenerator, verbose); - jsonGenerator.writeEndObject(); - } - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setMaxDepth(Integer maxDepth) { - this.maxDepth = maxDepth; - } - - protected Repository getRepository() { - return repository; - } - - protected ObjectMapper getObjectMapper() { - return objectMapper; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/JcrWriteServlet.java b/org.argeo.cms/src/org/argeo/cms/integration/JcrWriteServlet.java deleted file mode 100644 index 71d915674..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/JcrWriteServlet.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.IOException; - -import javax.jcr.ImportUUIDBehavior; -import javax.jcr.Node; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.jcr.JcrUtils; - -/** Access a JCR repository via web services. */ -public class JcrWriteServlet extends JcrReadServlet { - private static final long serialVersionUID = 17272653843085492L; - private final static Log log = LogFactory.getLog(JcrWriteServlet.class); - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (log.isDebugEnabled()) - log.debug("Data service POST: " + req.getPathInfo()); - - String dataWorkspace = getWorkspace(req); - String jcrPath = getJcrPath(req); - - Session session = null; - try { - // authentication - session = openJcrSession(req, resp, getRepository(), dataWorkspace); - - if (req.getContentType() != null && req.getContentType().equals(XML_CONTENT_TYPE)) { -// resp.setContentType(XML_CONTENT_TYPE); - session.getWorkspace().importXML(jcrPath, req.getInputStream(), - ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING); - return; - } - - if (!session.itemExists(jcrPath)) { - String parentPath = FilenameUtils.getFullPathNoEndSeparator(jcrPath); - String fileName = FilenameUtils.getName(jcrPath); - Node folderNode = JcrUtils.mkfolders(session, parentPath); - byte[] bytes = IOUtils.toByteArray(req.getInputStream()); - JcrUtils.copyBytesAsFile(folderNode, fileName, bytes); - } else { - Node node = session.getNode(jcrPath); - if (!node.isNodeType(NodeType.NT_FILE)) - throw new IllegalArgumentException("Node " + jcrPath + " exists but is not a file"); - byte[] bytes = IOUtils.toByteArray(req.getInputStream()); - JcrUtils.copyBytesAsFile(node.getParent(), node.getName(), bytes); - } - session.save(); - } catch (Exception e) { - new CmsExceptionsChain(e).writeAsJson(getObjectMapper(), resp); - } finally { - JcrUtils.logoutQuietly(session); - } - } - - @Override - protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (log.isDebugEnabled()) - log.debug("Data service DELETE: " + req.getPathInfo()); - - String dataWorkspace = getWorkspace(req); - String jcrPath = getJcrPath(req); - - Session session = null; - try { - // authentication - session = openJcrSession(req, resp, getRepository(), dataWorkspace); - if (!session.itemExists(jcrPath)) { - // ignore - return; - } else { - Node node = session.getNode(jcrPath); - node.remove(); - } - session.save(); - } catch (Exception e) { - new CmsExceptionsChain(e).writeAsJson(getObjectMapper(), resp); - } finally { - JcrUtils.logoutQuietly(session); - } - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/TokenDescriptor.java b/org.argeo.cms/src/org/argeo/cms/integration/TokenDescriptor.java deleted file mode 100644 index 1541b4f29..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/TokenDescriptor.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.Serializable; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** A serializable descriptor of a token. */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class TokenDescriptor implements Serializable { - private static final long serialVersionUID = -6607393871416803324L; - - private String token; - private String username; - private String expiryDate; -// private Set roles; - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - -// public Set getRoles() { -// return roles; -// } -// -// public void setRoles(Set roles) { -// this.roles = roles; -// } - - public String getExpiryDate() { - return expiryDate; - } - - public void setExpiryDate(String expiryDate) { - this.expiryDate = expiryDate; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/XslTemplate.java b/org.argeo.cms/src/org/argeo/cms/integration/XslTemplate.java deleted file mode 100644 index c9802a2f5..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/XslTemplate.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.argeo.cms.integration; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -public class XslTemplate { - private Transformer transformer; - - public XslTemplate(InputStream in, String systemId) { - this(loadTransformer(in, systemId)); - } - - public XslTemplate(Transformer transformer) { - this.transformer = transformer; - } - - private static Transformer loadTransformer(InputStream in, String systemId) { - try { - TransformerFactory tFactory = TransformerFactory.newInstance(); - StreamSource stylesource = new StreamSource(in, systemId); - return tFactory.newTransformer(stylesource); - } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) { - throw new IllegalArgumentException("Cannot initialise stylesheet with systemId " + systemId, e); - } - } - - public synchronized void apply(Node node, OutputStream out) { - // TODO use a pool of Transformer instead of synchronized - try (ByteArrayOutputStream xml = new ByteArrayOutputStream()) { - node.getSession().exportDocumentView(node.getPath(), xml, true, false); - try (ByteArrayInputStream xmlIn = new ByteArrayInputStream(xml.toByteArray())) { - Source source = new StreamSource(xmlIn); - Result results = new StreamResult(out); - transformer.transform(source, results); - } - } catch (IOException | RepositoryException | TransformerException e) { - throw new RuntimeException("Cannot process XSL template on " + node, e); - } - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/integration/package-info.java b/org.argeo.cms/src/org/argeo/cms/integration/package-info.java deleted file mode 100644 index 1405737ee..000000000 --- a/org.argeo.cms/src/org/argeo/cms/integration/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Argeo CMS integration (JSON, web services). */ -package org.argeo.cms.integration; \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java index 2bbd8f219..0a7d26584 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java @@ -16,14 +16,11 @@ import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttributes; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; -import javax.websocket.server.ServerEndpointConfig; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeConstants; import org.argeo.cms.CmsException; -import org.argeo.cms.internal.http.InternalHttpConstants; -import org.argeo.cms.websocket.CmsWebSocketConfigurator; import org.argeo.naming.AttributesDictionary; import org.argeo.naming.LdifParser; import org.argeo.naming.LdifWriter; @@ -147,16 +144,16 @@ class DeployConfig implements ConfigurationListener { // activator of the Equinox Jetty bundle. Dictionary webServerConfig = InitUtils .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, NodeConstants.DEFAULT)); - if (!webServerConfig.isEmpty()) { - webServerConfig.put("customizer.class", KernelConstants.CMS_JETTY_CUSTOMIZER_CLASS); - - // TODO centralise with Jetty extender - Object webSocketEnabled = webServerConfig.get(InternalHttpConstants.WEBSOCKET_ENABLED); - if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) { - bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null); - webServerConfig.put(InternalHttpConstants.WEBSOCKET_ENABLED, "true"); - } - } +// if (!webServerConfig.isEmpty()) { +// webServerConfig.put("customizer.class", KernelConstants.CMS_JETTY_CUSTOMIZER_CLASS); +// +// // TODO centralise with Jetty extender +// Object webSocketEnabled = webServerConfig.get(InternalHttpConstants.WEBSOCKET_ENABLED); +// if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) { +// bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null); +// webServerConfig.put(InternalHttpConstants.WEBSOCKET_ENABLED, "true"); +// } +// } int tryCount = 60; try { diff --git a/org.argeo.cms/src/org/argeo/cms/websocket/CmsWebSocketConfigurator.java b/org.argeo.cms/src/org/argeo/cms/websocket/CmsWebSocketConfigurator.java deleted file mode 100644 index 652f25298..000000000 --- a/org.argeo.cms/src/org/argeo/cms/websocket/CmsWebSocketConfigurator.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.argeo.cms.websocket; - -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.List; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginContext; -import javax.servlet.http.HttpSession; -import javax.websocket.Extension; -import javax.websocket.HandshakeResponse; -import javax.websocket.server.HandshakeRequest; -import javax.websocket.server.ServerEndpointConfig; -import javax.websocket.server.ServerEndpointConfig.Configurator; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.api.NodeConstants; -import org.argeo.cms.auth.HttpRequestCallbackHandler; -import org.osgi.service.http.context.ServletContextHelper; - -/** Customises the initialisation of a new web socket. */ -public class CmsWebSocketConfigurator extends Configurator { - public final static String WEBSOCKET_SUBJECT = "org.argeo.cms.websocket.subject"; - - private final static Log log = LogFactory.getLog(CmsWebSocketConfigurator.class); - final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate"; - - @Override - public boolean checkOrigin(String originHeaderValue) { - return true; - } - - @Override - public T getEndpointInstance(Class endpointClass) throws InstantiationException { - try { - return endpointClass.getDeclaredConstructor().newInstance(); - } catch (Exception e) { - throw new IllegalArgumentException("Cannot get endpoint instance", e); - } - } - - @Override - public List getNegotiatedExtensions(List installed, List requested) { - return requested; - } - - @Override - public String getNegotiatedSubprotocol(List supported, List requested) { - if ((requested == null) || (requested.size() == 0)) - return ""; - if ((supported == null) || (supported.isEmpty())) - return ""; - for (String possible : requested) { - if (possible == null) - continue; - if (supported.contains(possible)) - return possible; - } - return ""; - } - - @Override - public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { - HttpSession httpSession = (HttpSession) request.getHttpSession(); - if (log.isDebugEnabled() && httpSession != null) - log.debug("Web socket HTTP session id: " + httpSession.getId()); - - if (httpSession == null) { - rejectResponse(response, null); - } - try { - LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, - new HttpRequestCallbackHandler(httpSession)); - lc.login(); - if (log.isDebugEnabled()) - log.debug("Web socket logged-in as " + lc.getSubject()); - Subject.doAs(lc.getSubject(), new PrivilegedAction() { - - @Override - public Void run() { - sec.getUserProperties().put(ServletContextHelper.REMOTE_USER, AccessController.getContext()); - return null; - } - - }); - } catch (Exception e) { - rejectResponse(response, e); - } - } - - /** - * Behaviour when the web socket could not be authenticated. Throws an - * {@link IllegalStateException} by default. - * - * @param e can be null - */ - protected void rejectResponse(HandshakeResponse response, Exception e) { - // violent implementation, as suggested in - // https://stackoverflow.com/questions/21763829/jsr-356-how-to-abort-a-websocket-connection-during-the-handshake -// throw new IllegalStateException("Web socket cannot be authenticated"); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/websocket/package-info.java b/org.argeo.cms/src/org/argeo/cms/websocket/package-info.java deleted file mode 100644 index 2ab9a679e..000000000 --- a/org.argeo.cms/src/org/argeo/cms/websocket/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Argeo CMS websocket integration. */ -package org.argeo.cms.websocket; \ No newline at end of file diff --git a/org.argeo.core/bnd.bnd b/org.argeo.core/bnd.bnd index 6e0c5458f..bc810ff41 100644 --- a/org.argeo.core/bnd.bnd +++ b/org.argeo.core/bnd.bnd @@ -1,6 +1,4 @@ -Import-Package: com.fasterxml.jackson.annotation;resolution:=optional,\ - com.fasterxml.jackson.core;resolution:=optional,\ - com.fasterxml.jackson.databind;resolution:=optional,\ - org.apache.jackrabbit.api;resolution:=optional,\ - org.apache.jackrabbit.commons;resolution:=optional,\ - *;resolution:=optional \ No newline at end of file +Import-Package:\ +org.apache.jackrabbit.api,\ +org.apache.jackrabbit.commons,\ +* \ No newline at end of file diff --git a/org.argeo.core/build.properties b/org.argeo.core/build.properties index 6562d8309..84397864d 100644 --- a/org.argeo.core/build.properties +++ b/org.argeo.core/build.properties @@ -2,12 +2,9 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ . -additional.bundles = org.apache.sshd.common,\ - org.apache.jackrabbit.data,\ +additional.bundles = org.apache.jackrabbit.data,\ org.slf4j.log4j12,\ org.slf4j.api,\ - org.apache.sshd.core,\ bcprov,\ - org.apache.tomcat.jni,\ org.junit,\ org.hamcrest diff --git a/org.argeo.core/ext/test/org/argeo/json/JacksonTest.java b/org.argeo.core/ext/test/org/argeo/json/JacksonTest.java deleted file mode 100644 index 719f321bd..000000000 --- a/org.argeo.core/ext/test/org/argeo/json/JacksonTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.argeo.json; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.Test; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -public class JacksonTest { - - @Test - public void testSimpleObjectMapping() throws JsonProcessingException { - ObjectMapper om = new ObjectMapper(); - Map map = new HashMap<>(); - map.put("one", 1); - map.put("two", 2); - String s = om.writeValueAsString(map); - System.out.println(s); - } -} diff --git a/org.argeo.core/src/org/argeo/cli/fs/PathSync.java b/org.argeo.core/src/org/argeo/cli/fs/PathSync.java index 85fefe9f5..902318c44 100644 --- a/org.argeo.core/src/org/argeo/cli/fs/PathSync.java +++ b/org.argeo.core/src/org/argeo/cli/fs/PathSync.java @@ -9,7 +9,6 @@ import java.nio.file.spi.FileSystemProvider; import java.util.concurrent.Callable; import org.argeo.jackrabbit.fs.DavexFsProvider; -import org.argeo.ssh.Sftp; import org.argeo.sync.SyncResult; /** Synchronises two paths. */ @@ -52,9 +51,9 @@ public class PathSync implements Callable> { } else if (uri.getScheme().equals("davex")) { FileSystemProvider fsProvider = new DavexFsProvider(); path = fsProvider.getPath(uri); - } else if (uri.getScheme().equals("sftp")) { - Sftp sftp = new Sftp(uri); - path = sftp.getBasePath(); +// } else if (uri.getScheme().equals("sftp")) { +// Sftp sftp = new Sftp(uri); +// path = sftp.getBasePath(); } else throw new IllegalArgumentException("URI scheme not supported for " + uri); return path; diff --git a/org.argeo.core/src/org/argeo/cli/fs/SshSync.java b/org.argeo.core/src/org/argeo/cli/fs/SshSync.java deleted file mode 100644 index 268e7d899..000000000 --- a/org.argeo.core/src/org/argeo/cli/fs/SshSync.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.argeo.cli.fs; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.Scanner; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.sshd.agent.SshAgent; -import org.apache.sshd.agent.SshAgentFactory; -import org.apache.sshd.agent.local.LocalAgentFactory; -import org.apache.sshd.agent.unix.UnixAgentFactory; -import org.apache.sshd.client.SshClient; -import org.apache.sshd.client.future.ConnectFuture; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystem; -import org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystemProvider; - -public class SshSync { - private final static Log log = LogFactory.getLog(SshSync.class); - - public static void main(String[] args) { - - try (SshClient client = SshClient.setUpDefaultClient()) { - client.start(); - boolean osAgent = true; - SshAgentFactory agentFactory = osAgent ? new UnixAgentFactory() : new LocalAgentFactory(); - // SshAgentFactory agentFactory = new LocalAgentFactory(); - client.setAgentFactory(agentFactory); - SshAgent sshAgent = agentFactory.createClient(client); - - String login = System.getProperty("user.name"); - String host = "localhost"; - int port = 22; - - if (!osAgent) { - String keyPath = "/home/" + login + "/.ssh/id_rsa"; - System.out.print(keyPath + ": "); - Scanner s = new Scanner(System.in); - String password = s.next(); -// KeyPair keyPair = ClientIdentityLoader.DEFAULT.loadClientIdentity(keyPath, -// FilePasswordProvider.of(password)); -// sshAgent.addIdentity(keyPair, "NO COMMENT"); - } - -// List> identities = sshAgent.getIdentities(); -// for (Map.Entry entry : identities) { -// System.out.println(entry.getValue() + " : " + entry.getKey()); -// } - - ConnectFuture connectFuture = client.connect(login, host, port); - connectFuture.await(); - ClientSession session = connectFuture.getSession(); - - try { - -// session.addPasswordIdentity(new String(password)); - session.auth().verify(1000l); - - SftpFileSystemProvider fsProvider = new SftpFileSystemProvider(client); - - SftpFileSystem fs = fsProvider.newFileSystem(session); - Path testPath = fs.getPath("/home/" + login + "/tmp"); - Files.list(testPath).forEach(System.out::println); - test(testPath); - - } finally { - client.stop(); - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - static void test(Path testBase) { - try { - Path testPath = testBase.resolve("ssh-test.txt"); - Files.createFile(testPath); - log.debug("Created file " + testPath); - Files.delete(testPath); - log.debug("Deleted " + testPath); - String txt = "TEST\nTEST2\n"; - byte[] arr = txt.getBytes(); - Files.write(testPath, arr); - log.debug("Wrote " + testPath); - byte[] read = Files.readAllBytes(testPath); - log.debug("Read " + testPath); - Path testDir = testBase.resolve("testDir"); - log.debug("Resolved " + testDir); - // Copy - Files.createDirectory(testDir); - log.debug("Created directory " + testDir); - Path subsubdir = Files.createDirectories(testDir.resolve("subdir/subsubdir")); - log.debug("Created sub directories " + subsubdir); - Path copiedFile = testDir.resolve("copiedFile.txt"); - log.debug("Resolved " + copiedFile); - Path relativeCopiedFile = testDir.relativize(copiedFile); - log.debug("Relative copied file " + relativeCopiedFile); - try (OutputStream out = Files.newOutputStream(copiedFile); - InputStream in = Files.newInputStream(testPath)) { - IOUtils.copy(in, out); - } - log.debug("Copied " + testPath + " to " + copiedFile); - Files.delete(testPath); - log.debug("Deleted " + testPath); - byte[] copiedRead = Files.readAllBytes(copiedFile); - log.debug("Read " + copiedFile); - // Browse directories - DirectoryStream files = Files.newDirectoryStream(testDir); - int fileCount = 0; - Path listedFile = null; - for (Path file : files) { - fileCount++; - if (!Files.isDirectory(file)) - listedFile = file; - } - log.debug("Listed " + testDir); - // Generic attributes - Map attrs = Files.readAttributes(copiedFile, "*"); - log.debug("Read attributes of " + copiedFile + ": " + attrs.keySet()); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - -} diff --git a/org.argeo.core/src/org/argeo/ssh/AbstractSsh.java b/org.argeo.core/src/org/argeo/ssh/AbstractSsh.java deleted file mode 100644 index 261ac2460..000000000 --- a/org.argeo.core/src/org/argeo/ssh/AbstractSsh.java +++ /dev/null @@ -1,189 +0,0 @@ -package org.argeo.ssh; - -import java.io.Console; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Scanner; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.sshd.client.SshClient; -import org.apache.sshd.client.channel.ClientChannel; -import org.apache.sshd.client.channel.ClientChannelEvent; -import org.apache.sshd.client.future.ConnectFuture; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystemProvider; -import org.apache.sshd.common.util.io.NoCloseInputStream; -import org.apache.sshd.common.util.io.NoCloseOutputStream; - -@SuppressWarnings("restriction") -abstract class AbstractSsh { - private final static Log log = LogFactory.getLog(AbstractSsh.class); - - private static SshClient sshClient; - private static SftpFileSystemProvider sftpFileSystemProvider; - - private boolean passwordSet = false; - private ClientSession session; - - private SshKeyPair sshKeyPair; - - synchronized SshClient getSshClient() { - if (sshClient == null) { - long begin = System.currentTimeMillis(); - sshClient = SshClient.setUpDefaultClient(); - sshClient.start(); - long duration = System.currentTimeMillis() - begin; - if (log.isDebugEnabled()) - log.debug("SSH client started in " + duration + " ms"); - Runtime.getRuntime().addShutdownHook(new Thread(() -> sshClient.stop(), "Stop SSH client")); - } - return sshClient; - } - - synchronized SftpFileSystemProvider getSftpFileSystemProvider() { - if (sftpFileSystemProvider == null) { - sftpFileSystemProvider = new SftpFileSystemProvider(sshClient); - } - return sftpFileSystemProvider; - } - - void authenticate() { - try { - if (sshKeyPair != null) { - session.addPublicKeyIdentity(sshKeyPair.asKeyPair()); - } else { - - if (!passwordSet) { - String password; - Console console = System.console(); - if (console == null) {// IDE - System.out.print("Password: "); - try (Scanner s = new Scanner(System.in)) { - password = s.next(); - } - } else { - console.printf("Password: "); - char[] pwd = console.readPassword(); - password = new String(pwd); - Arrays.fill(pwd, ' '); - } - session.addPasswordIdentity(password); - passwordSet = true; - } - } - session.auth().verify(1000l); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - void addPassword(String password) { - session.addPasswordIdentity(password); - } - - void loadKey(String password) { - loadKey(password, System.getProperty("user.home") + "/.ssh/id_rsa"); - } - - void loadKey(String password, String keyPath) { -// try { -// KeyPair keyPair = ClientIdentityLoader.DEFAULT.loadClientIdentity(keyPath, -// FilePasswordProvider.of(password)); -// session.addPublicKeyIdentity(keyPair); -// } catch (IOException | GeneralSecurityException e) { -// throw new IllegalStateException(e); -// } - } - - void openSession(URI uri) { - openSession(uri.getUserInfo(), uri.getHost(), uri.getPort() > 0 ? uri.getPort() : null); - } - - void openSession(String login, String host, Integer port) { - if (session != null) - throw new IllegalStateException("Session is already open"); - - if (host == null) - host = "localhost"; - if (port == null) - port = 22; - if (login == null) - login = System.getProperty("user.name"); - String password = null; - int sepIndex = login.indexOf(':'); - if (sepIndex > 0) - if (sepIndex + 1 < login.length()) { - password = login.substring(sepIndex + 1); - login = login.substring(0, sepIndex); - } else { - throw new IllegalArgumentException("Illegal authority: " + login); - } - try { - ConnectFuture connectFuture = getSshClient().connect(login, host, port); - connectFuture.await(); - ClientSession session = connectFuture.getSession(); - if (password != null) { - session.addPasswordIdentity(password); - passwordSet = true; - } - this.session = session; - } catch (IOException e) { - throw new IllegalStateException("Cannot connect to " + host + ":" + port); - } - } - - void closeSession() { - if (session == null) - throw new IllegalStateException("No session is open"); - try { - session.close(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - session = null; - } - } - - ClientSession getSession() { - return session; - } - - public void setSshKeyPair(SshKeyPair sshKeyPair) { - this.sshKeyPair = sshKeyPair; - } - - public static void openShell(ClientSession session) { - try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) { - channel.setIn(new NoCloseInputStream(System.in)); - channel.setOut(new NoCloseOutputStream(System.out)); - channel.setErr(new NoCloseOutputStream(System.err)); - channel.open(); - - Set events = new HashSet<>(); - events.add(ClientChannelEvent.CLOSED); - channel.waitFor(events, 0); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } finally { - session.close(false); - } - } - - static URI toUri(String username, String host, int port) { - try { - if (username == null) - username = "root"; - return new URI("ssh://" + username + "@" + host + ":" + port); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Cannot generate SSH URI to " + host + ":" + port + " for " + username, - e); - } - } - -} diff --git a/org.argeo.core/src/org/argeo/ssh/BasicSshServer.java b/org.argeo.core/src/org/argeo/ssh/BasicSshServer.java deleted file mode 100644 index e763140bc..000000000 --- a/org.argeo.core/src/org/argeo/ssh/BasicSshServer.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.argeo.ssh; - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.apache.sshd.server.SshServer; -import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; -import org.apache.sshd.server.scp.ScpCommandFactory; -import org.apache.sshd.server.shell.ProcessShellFactory; -import org.argeo.util.OS; - -/** A simple SSH server with some defaults. Supports SCP. */ -@SuppressWarnings("restriction") -public class BasicSshServer { - private Integer port; - private Path hostKeyPath; - - private SshServer sshd = null; - - public BasicSshServer(Integer port, Path hostKeyPath) { - this.port = port; - this.hostKeyPath = hostKeyPath; - } - - public void init() { - try { - sshd = SshServer.setUpDefaultServer(); - sshd.setPort(port); - if (hostKeyPath == null) - throw new IllegalStateException("An SSH server key must be set"); - sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKeyPath)); - // sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", - // "-l" })); - String[] shellCommand = OS.LOCAL.getDefaultShellCommand(); - sshd.setShellFactory(new ProcessShellFactory(shellCommand)); - sshd.setCommandFactory(new ScpCommandFactory()); - sshd.start(); - } catch (Exception e) { - throw new RuntimeException("Cannot start SSH server on port " + port, e); - } - } - - public void destroy() { - try { - sshd.stop(); - } catch (IOException e) { - throw new RuntimeException("Cannot stop SSH server on port " + port, e); - } - } - - public Integer getPort() { - return port; - } - - public void setPort(Integer port) { - this.port = port; - } - - public Path getHostKeyPath() { - return hostKeyPath; - } - - public void setHostKeyPath(Path hostKeyPath) { - this.hostKeyPath = hostKeyPath; - } - - public static void main(String[] args) { - int port = 2222; - Path hostKeyPath = Paths.get("hostkey.ser"); - try { - if (args.length > 0) - port = Integer.parseInt(args[0]); - if (args.length > 1) - hostKeyPath = Paths.get(args[1]); - } catch (Exception e1) { - printUsage(); - } - - BasicSshServer sshServer = new BasicSshServer(port, hostKeyPath); - sshServer.init(); - Runtime.getRuntime().addShutdownHook(new Thread("Shutdown SSH server") { - - @Override - public void run() { - sshServer.destroy(); - } - }); - try { - synchronized (sshServer) { - sshServer.wait(); - } - } catch (InterruptedException e) { - sshServer.destroy(); - } - - } - - public static void printUsage() { - System.out.println("java " + BasicSshServer.class.getName() + " [port] [server key path]"); - } - -} diff --git a/org.argeo.core/src/org/argeo/ssh/Sftp.java b/org.argeo.core/src/org/argeo/ssh/Sftp.java deleted file mode 100644 index da10b961f..000000000 --- a/org.argeo.core/src/org/argeo/ssh/Sftp.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.argeo.ssh; - -import java.io.IOException; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.Path; - -import org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystem; - -/** Create an SFTP {@link FileSystem}. */ -public class Sftp extends AbstractSsh { - private URI uri; - - private SftpFileSystem fileSystem; - - public Sftp(String username, String host, int port) { - this(AbstractSsh.toUri(username, host, port)); - } - - public Sftp(URI uri) { - this.uri = uri; - openSession(uri); - } - - public FileSystem getFileSystem() { - if (fileSystem == null) { - try { - authenticate(); - fileSystem = getSftpFileSystemProvider().newFileSystem(getSession()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - return fileSystem; - } - - public Path getBasePath() { - String p = uri.getPath() != null ? uri.getPath() : "/"; - return getFileSystem().getPath(p); - } - -} diff --git a/org.argeo.core/src/org/argeo/ssh/Ssh.java b/org.argeo.core/src/org/argeo/ssh/Ssh.java deleted file mode 100644 index 68dd912ec..000000000 --- a/org.argeo.core/src/org/argeo/ssh/Ssh.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.argeo.ssh; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; - -/** Create an SSH shell. */ -public class Ssh extends AbstractSsh { - private final URI uri; - - public Ssh(String username, String host, int port) { - this(AbstractSsh.toUri(username, host, port)); - } - - public Ssh(URI uri) { - this.uri = uri; - openSession(uri); - } - - public static void main(String[] args) { - Options options = getOptions(); - CommandLineParser parser = new DefaultParser(); - try { - CommandLine line = parser.parse(options, args); - List remaining = line.getArgList(); - if (remaining.size() == 0) { - System.err.println("There must be at least one argument"); - printHelp(options); - System.exit(1); - } - URI uri = new URI("ssh://" + remaining.get(0)); - List command = new ArrayList<>(); - if (remaining.size() > 1) { - for (int i = 1; i < remaining.size(); i++) { - command.add(remaining.get(i)); - } - } - - // auth - Ssh ssh = new Ssh(uri); - ssh.authenticate(); - - if (command.size() == 0) {// shell - AbstractSsh.openShell(ssh.getSession()); - } else {// execute command - - } - ssh.closeSession(); - } catch (Exception exp) { - exp.printStackTrace(); - printHelp(options); - System.exit(1); - } finally { - - } - } - - public URI getUri() { - return uri; - } - - public static Options getOptions() { - Options options = new Options(); -// options.addOption("p", true, "port"); - options.addOption(Option.builder("p").hasArg().argName("port").desc("port of the SSH server").build()); - - return options; - } - - public static void printHelp(Options options) { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("ssh [username@]hostname", options, true); - } -} diff --git a/org.argeo.core/src/org/argeo/ssh/SshKeyPair.java b/org.argeo.core/src/org/argeo/ssh/SshKeyPair.java deleted file mode 100644 index f9b348598..000000000 --- a/org.argeo.core/src/org/argeo/ssh/SshKeyPair.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.argeo.ssh; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.spec.RSAPublicKeySpec; - -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.config.keys.PublicKeyEntry; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.PKCS8Generator; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.openssl.jcajce.JcaPEMWriter; -import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator; -import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder; -import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder; -import org.bouncycastle.operator.InputDecryptorProvider; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; - -@SuppressWarnings("restriction") -public class SshKeyPair { - public final static String RSA_KEY_TYPE = "ssh-rsa"; - - private PublicKey publicKey; - private PrivateKey privateKey; - private KeyPair keyPair; - - public SshKeyPair(KeyPair keyPair) { - super(); - this.publicKey = keyPair.getPublic(); - this.privateKey = keyPair.getPrivate(); - this.keyPair = keyPair; - } - - public SshKeyPair(PublicKey publicKey, PrivateKey privateKey) { - super(); - this.publicKey = publicKey; - this.privateKey = privateKey; - this.keyPair = new KeyPair(publicKey, privateKey); - } - - public KeyPair asKeyPair() { - return keyPair; - } - - public String getPublicKeyAsOpenSshString() { - return PublicKeyEntry.toString(publicKey); - } - - public String getPrivateKeyAsPemString(char[] password) { - try { - Object obj; - - if (password != null) { - JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder( - PKCS8Generator.PBE_SHA1_3DES); - encryptorBuilder.setPasssword(password); - OutputEncryptor oe = encryptorBuilder.build(); - JcaPKCS8Generator gen = new JcaPKCS8Generator(privateKey, oe); - obj = gen.generate(); - } else { - obj = privateKey; - } - - StringWriter sw = new StringWriter(); - JcaPEMWriter pemWrt = new JcaPEMWriter(sw); - pemWrt.writeObject(obj); - pemWrt.close(); - return sw.toString(); - } catch (Exception e) { - throw new RuntimeException("Cannot convert private key", e); - } - } - - public static SshKeyPair loadOrGenerate(Path privateKeyPath, int size, char[] password) { - try { - SshKeyPair sshKeyPair; - if (Files.exists(privateKeyPath)) { -// String privateKeyStr = new String(Files.readAllBytes(privateKeyPath), StandardCharsets.US_ASCII); - sshKeyPair = load( - new InputStreamReader(Files.newInputStream(privateKeyPath), StandardCharsets.US_ASCII), - password); - // TOD make sure public key is consistemt - } else { - sshKeyPair = generate(size); - Files.write(privateKeyPath, - sshKeyPair.getPrivateKeyAsPemString(password).getBytes(StandardCharsets.US_ASCII)); - Path publicKeyPath = privateKeyPath.resolveSibling(privateKeyPath.getFileName() + ".pub"); - Files.write(publicKeyPath, - sshKeyPair.getPublicKeyAsOpenSshString().getBytes(StandardCharsets.US_ASCII)); - } - return sshKeyPair; - } catch (IOException e) { - throw new RuntimeException("Cannot read or write private key " + privateKeyPath, e); - } - } - - public static SshKeyPair generate(int size) { - return generate(RSA_KEY_TYPE, size); - } - - public static SshKeyPair generate(String keyType, int size) { - try { - KeyPair keyPair = KeyUtils.generateKeyPair(keyType, size); - PublicKey publicKey = keyPair.getPublic(); - PrivateKey privateKey = keyPair.getPrivate(); - return new SshKeyPair(publicKey, privateKey); - } catch (GeneralSecurityException e) { - throw new RuntimeException("Cannot generate SSH key", e); - } - } - - public static SshKeyPair load(Reader reader, char[] password) { - try (PEMParser pemParser = new PEMParser(reader)) { - Object object = pemParser.readObject(); - JcaPEMKeyConverter converter = new JcaPEMKeyConverter();// .setProvider("BC"); - KeyPair kp; - if (object instanceof PKCS8EncryptedPrivateKeyInfo) { - // Encrypted key - we will use provided password - PKCS8EncryptedPrivateKeyInfo ckp = (PKCS8EncryptedPrivateKeyInfo) object; -// PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password); - InputDecryptorProvider inputDecryptorProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder() - .build(password); - PrivateKeyInfo pkInfo = ckp.decryptPrivateKeyInfo(inputDecryptorProvider); - PrivateKey privateKey = converter.getPrivateKey(pkInfo); - - // generate public key - RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey; - RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(privk.getModulus(), - privk.getPublicExponent()); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); - - kp = new KeyPair(publicKey, privateKey); - } else { - // Unencrypted key - no password needed -// PKCS8EncryptedPrivateKeyInfo ukp = (PKCS8EncryptedPrivateKeyInfo) object; - PEMKeyPair pemKp = (PEMKeyPair) object; - kp = converter.getKeyPair(pemKp); - } - return new SshKeyPair(kp); - } catch (Exception e) { - throw new RuntimeException("Cannot load private key", e); - } - } - - public static void main(String args[]) { - Path privateKeyPath = Paths.get(System.getProperty("user.dir") + "/id_rsa"); - SshKeyPair skp = SshKeyPair.loadOrGenerate(privateKeyPath, 1024, null); - System.out.println("Public:\n" + skp.getPublicKeyAsOpenSshString()); - System.out.println("Private (plain):\n" + skp.getPrivateKeyAsPemString(null)); - System.out.println("Private (encrypted):\n" + skp.getPrivateKeyAsPemString("demo".toCharArray())); - - StringReader reader = new StringReader(skp.getPrivateKeyAsPemString(null)); - skp = SshKeyPair.load(reader, null); - System.out.println("Public:\n" + skp.getPublicKeyAsOpenSshString()); - System.out.println("Private (plain):\n" + skp.getPrivateKeyAsPemString(null)); - System.out.println("Private (encrypted):\n" + skp.getPrivateKeyAsPemString("demo".toCharArray())); - - reader = new StringReader(skp.getPrivateKeyAsPemString("demo".toCharArray())); - skp = SshKeyPair.load(reader, "demo".toCharArray()); - System.out.println("Public:\n" + skp.getPublicKeyAsOpenSshString()); - System.out.println("Private (plain):\n" + skp.getPrivateKeyAsPemString(null)); - System.out.println("Private (encrypted):\n" + skp.getPrivateKeyAsPemString("demo".toCharArray())); - } - -} diff --git a/org.argeo.core/src/org/argeo/ssh/package-info.java b/org.argeo.core/src/org/argeo/ssh/package-info.java deleted file mode 100644 index 8324a7a88..000000000 --- a/org.argeo.core/src/org/argeo/ssh/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** SSH support. */ -package org.argeo.ssh; \ No newline at end of file diff --git a/org.argeo.ext.equinox.jetty/.classpath b/org.argeo.ext.equinox.jetty/.classpath deleted file mode 100644 index eca7bdba8..000000000 --- a/org.argeo.ext.equinox.jetty/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/org.argeo.ext.equinox.jetty/.gitignore b/org.argeo.ext.equinox.jetty/.gitignore deleted file mode 100644 index 09e3bc9b2..000000000 --- a/org.argeo.ext.equinox.jetty/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/target/ diff --git a/org.argeo.ext.equinox.jetty/.project b/org.argeo.ext.equinox.jetty/.project deleted file mode 100644 index 0b9700dd6..000000000 --- a/org.argeo.ext.equinox.jetty/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.ext.equinox.jetty - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/org.argeo.ext.equinox.jetty/META-INF/.gitignore b/org.argeo.ext.equinox.jetty/META-INF/.gitignore deleted file mode 100644 index 4854a41b9..000000000 --- a/org.argeo.ext.equinox.jetty/META-INF/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MANIFEST.MF diff --git a/org.argeo.ext.equinox.jetty/bnd.bnd b/org.argeo.ext.equinox.jetty/bnd.bnd deleted file mode 100644 index 0f21e73c9..000000000 --- a/org.argeo.ext.equinox.jetty/bnd.bnd +++ /dev/null @@ -1,7 +0,0 @@ -Fragment-Host: org.eclipse.equinox.http.jetty - -Import-Package: org.eclipse.jetty.websocket.jsr356,\ -org.eclipse.jetty.websocket.api,\ -org.eclipse.jetty.websocket.common,\ -org.osgi.service.http,\ -* \ No newline at end of file diff --git a/org.argeo.ext.equinox.jetty/build.properties b/org.argeo.ext.equinox.jetty/build.properties deleted file mode 100644 index 34d2e4d2d..000000000 --- a/org.argeo.ext.equinox.jetty/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - . diff --git a/org.argeo.ext.equinox.jetty/pom.xml b/org.argeo.ext.equinox.jetty/pom.xml deleted file mode 100644 index 2052a1c03..000000000 --- a/org.argeo.ext.equinox.jetty/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - org.argeo.commons - argeo-commons - 2.1.89-SNAPSHOT - .. - - org.argeo.ext.equinox.jetty - Extension of Equinox Jetty Integration - - - org.argeo.commons - org.argeo.cms - 2.1.89-SNAPSHOT - - - \ No newline at end of file diff --git a/org.argeo.ext.equinox.jetty/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java b/org.argeo.ext.equinox.jetty/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java deleted file mode 100644 index 46f0280bd..000000000 --- a/org.argeo.ext.equinox.jetty/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.argeo.equinox.jetty; - -import java.util.Dictionary; - -import javax.servlet.ServletContext; -import javax.websocket.DeploymentException; - -import org.eclipse.equinox.http.jetty.JettyCustomizer; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; -import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; -import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.Configurator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; - -/** Customises the Jetty HTTP server. */ -public class CmsJettyCustomizer extends JettyCustomizer { - private BundleContext bc = FrameworkUtil.getBundle(CmsJettyCustomizer.class).getBundleContext(); - - public final static String WEBSOCKET_ENABLED = "websocket.enabled"; - - @Override - public Object customizeContext(Object context, Dictionary settings) { - // WebSocket - Object webSocketEnabled = settings.get(WEBSOCKET_ENABLED); - if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) { - ServletContextHandler servletContextHandler = (ServletContextHandler) context; - WebSocketServerContainerInitializer.configure(servletContextHandler, new Configurator() { - - @Override - public void accept(ServletContext servletContext, ServerContainer serverContainer) - throws DeploymentException { - bc.registerService(javax.websocket.server.ServerContainer.class, serverContainer, null); - } - }); - } - return super.customizeContext(context, settings); - - } -} diff --git a/org.argeo.ext.equinox.jetty/src/org/argeo/equinox/jetty/package-info.java b/org.argeo.ext.equinox.jetty/src/org/argeo/equinox/jetty/package-info.java deleted file mode 100644 index 41c8ce9b0..000000000 --- a/org.argeo.ext.equinox.jetty/src/org/argeo/equinox/jetty/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Equinox Jetty extensions. */ -package org.argeo.equinox.jetty; \ No newline at end of file diff --git a/org.argeo.maintenance/build.properties b/org.argeo.maintenance/build.properties index f3e2c2ccb..ad08d9e7e 100644 --- a/org.argeo.maintenance/build.properties +++ b/org.argeo.maintenance/build.properties @@ -2,7 +2,5 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ . -additional.bundles = org.apache.sshd.common,\ - org.slf4j.log4j12,\ - org.slf4j.api,\ - org.apache.sshd.core +additional.bundles = org.slf4j.log4j12,\ + org.slf4j.api diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/AbstractAtomicBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/AbstractAtomicBackup.java deleted file mode 100644 index 78c0e75dc..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/AbstractAtomicBackup.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; -import org.argeo.maintenance.MaintenanceException; - -/** - * Simplify atomic backups implementation, especially by managing VFS. - */ -public abstract class AbstractAtomicBackup implements AtomicBackup { - private String name; - private String compression = "bz2"; - - protected abstract void writeBackup(FileObject targetFo); - - public AbstractAtomicBackup() { - } - - public AbstractAtomicBackup(String name) { - this.name = name; - } - - public void init() { - if (name == null) - throw new MaintenanceException("Atomic backup name must be set"); - } - - public void destroy() { - - } - - @Override - public String backup(FileSystemManager fileSystemManager, - String backupsBase, BackupContext backupContext, - FileSystemOptions opts) { - if (name == null) - throw new MaintenanceException("Atomic backup name must be set"); - - FileObject targetFo = null; - try { - if (backupsBase.startsWith("sftp:")) - SftpFileSystemConfigBuilder.getInstance() - .setStrictHostKeyChecking(opts, "no"); - if (compression == null || compression.equals("none")) - targetFo = fileSystemManager.resolveFile(backupsBase + '/' - + backupContext.getRelativeFolder() + '/' + name, opts); - else if (compression.equals("bz2")) - targetFo = fileSystemManager.resolveFile("bz2:" + backupsBase - + '/' + backupContext.getRelativeFolder() + '/' + name - + ".bz2" + "!" + name, opts); - else if (compression.equals("gz")) - targetFo = fileSystemManager.resolveFile("gz:" + backupsBase - + '/' + backupContext.getRelativeFolder() + '/' + name - + ".gz" + "!" + name, opts); - else - throw new MaintenanceException("Unsupported compression " - + compression); - - writeBackup(targetFo); - - return targetFo.toString(); - } catch (Exception e) { - throw new MaintenanceException("Cannot backup " + name + " to " - + targetFo, e); - } finally { - BackupUtils.closeFOQuietly(targetFo); - } - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setCompression(String compression) { - this.compression = compression; - } -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/AtomicBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/AtomicBackup.java deleted file mode 100644 index db437e479..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/AtomicBackup.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; - -/** Performs the backup of a single component, typically a database dump */ -public interface AtomicBackup { - /** Name identifiying this backup */ - public String getName(); - - /** - * Retrieves the data of the component in a format that allows to restore - * the component - * - * @param backupContext - * the context of this backup - * @return the VFS URI of the generated file or directory - */ - public String backup(FileSystemManager fileSystemManager, - String backupsBase, BackupContext backupContext, - FileSystemOptions opts); -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupContext.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupContext.java deleted file mode 100644 index d5eefb3b9..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupContext.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.text.DateFormat; -import java.util.Date; - -/** - * Transient information of a given backup, centralizing common information such - * as timestamp and location. - */ -public interface BackupContext { - /** Backup date */ - public Date getTimestamp(); - - /** Formatted backup date */ - public String getTimestampAsString(); - - /** System name */ - public String getSystemName(); - - /** Local base */ - public String getRelativeFolder(); - - /** Date format */ - public DateFormat getDateFormat(); -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupFileSystemManager.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupFileSystemManager.java deleted file mode 100644 index 9c5f2f09a..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupFileSystemManager.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.impl.DefaultFileSystemManager; -import org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider; -import org.apache.commons.vfs2.provider.ftp.FtpFileProvider; -import org.apache.commons.vfs2.provider.gzip.GzipFileProvider; -import org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider; -import org.apache.commons.vfs2.provider.ram.RamFileProvider; -import org.apache.commons.vfs2.provider.sftp.SftpFileProvider; -import org.apache.commons.vfs2.provider.url.UrlFileProvider; -import org.argeo.maintenance.MaintenanceException; - -/** - * Programatically configured VFS file system manager which can be declared as a - * bean and associated with a life cycle (methods - * {@link DefaultFileSystemManager#init()} and - * {@link DefaultFileSystemManager#close()}). Supports bz2, file, ram, gzip, - * ftp, sftp - */ -public class BackupFileSystemManager extends DefaultFileSystemManager { - - public BackupFileSystemManager() { - super(); - try { - addProvider("file", new DefaultLocalFileProvider()); - addProvider("bz2", new Bzip2FileProvider()); - addProvider("ftp", new FtpFileProvider()); - addProvider("sftp", new SftpFileProvider()); - addProvider("gzip", new GzipFileProvider()); - addProvider("ram", new RamFileProvider()); - setDefaultProvider(new UrlFileProvider()); - } catch (FileSystemException e) { - throw new MaintenanceException("Cannot configure backup file provider", e); - } - } -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupPurge.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupPurge.java deleted file mode 100644 index e769da264..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupPurge.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.text.DateFormat; - -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; - -/** Purges previous backups */ -public interface BackupPurge { - /** - * Purge the backups identified by these arguments. Although these are the - * same fields as a {@link BackupContext} we don't pass it as argument since - * we want to use this interface to purge remote backups as well (that is, - * with a different base), or outside the scope of a running backup. - */ - public void purge(FileSystemManager fileSystemManager, String base, - String name, DateFormat dateFormat, FileSystemOptions opts); -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupUtils.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupUtils.java deleted file mode 100644 index d9f7b5a9b..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/BackupUtils.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileObject; - -/** Backup utilities */ -public class BackupUtils { - /** Close a file object quietly even if it is null or throws an exception. */ - public static void closeFOQuietly(FileObject fo) { - if (fo != null) { - try { - fo.close(); - } catch (Exception e) { - // silent - } - } - } - - /** Prevents instantiation */ - private BackupUtils() { - } -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/MySqlBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/MySqlBackup.java deleted file mode 100644 index 7d1cce45e..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/MySqlBackup.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileObject; - -/** Backups a MySQL database using mysqldump. */ -public class MySqlBackup extends OsCallBackup { - private String mysqldumpLocation = "/usr/bin/mysqldump"; - - private String dbUser; - private String dbPassword; - private String dbName; - - public MySqlBackup() { - } - - public MySqlBackup(String dbUser, String dbPassword, String dbName) { - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbName = dbName; - init(); - } - - @Override - public void init() { - if (getName() == null) - setName(dbName + ".mysql"); - super.init(); - } - - @Override - public void writeBackup(FileObject targetFo) { - if (getCommand() == null) - setCommand(mysqldumpLocation - + " --lock-tables --add-locks --add-drop-table" - + " -u ${dbUser} --password=${dbPassword} --databases ${dbName}"); - getVariables().put("dbUser", dbUser); - getVariables().put("dbPassword", dbPassword); - getVariables().put("dbName", dbName); - - super.writeBackup(targetFo); - } - - public void setDbUser(String dbUser) { - this.dbUser = dbUser; - } - - public void setDbPassword(String dbPassword) { - this.dbPassword = dbPassword; - } - - public void setDbName(String dbName) { - this.dbName = dbName; - } - - public void setMysqldumpLocation(String mysqldumpLocation) { - this.mysqldumpLocation = mysqldumpLocation; - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/OpenLdapBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/OpenLdapBackup.java deleted file mode 100644 index 60e17a98c..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/OpenLdapBackup.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileObject; -import org.argeo.maintenance.MaintenanceException; - -/** Backups an OpenLDAP server using slapcat */ -public class OpenLdapBackup extends OsCallBackup { - private String slapcatLocation = "/usr/sbin/slapcat"; - private String slapdConfLocation = "/etc/openldap/slapd.conf"; - private String baseDn; - - public OpenLdapBackup() { - super(); - } - - public OpenLdapBackup(String baseDn) { - super(); - this.baseDn = baseDn; - } - - @Override - public void writeBackup(FileObject targetFo) { - if (baseDn == null) - throw new MaintenanceException("Base DN must be set"); - - if (getCommand() == null) - setCommand(slapcatLocation - + " -f ${slapdConfLocation} -b '${baseDn}'"); - getVariables().put("slapdConfLocation", slapdConfLocation); - getVariables().put("baseDn", baseDn); - - super.writeBackup(targetFo); - } - - public void setSlapcatLocation(String slapcatLocation) { - this.slapcatLocation = slapcatLocation; - } - - public void setSlapdConfLocation(String slapdConfLocation) { - this.slapdConfLocation = slapdConfLocation; - } - - public void setBaseDn(String baseDn) { - this.baseDn = baseDn; - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/OsCallBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/OsCallBackup.java deleted file mode 100644 index afd4783fd..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/OsCallBackup.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.io.ByteArrayOutputStream; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.ExecuteException; -import org.apache.commons.exec.ExecuteStreamHandler; -import org.apache.commons.exec.Executor; -import org.apache.commons.exec.PumpStreamHandler; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs2.FileContent; -import org.apache.commons.vfs2.FileObject; -import org.argeo.maintenance.MaintenanceException; - -/** - * Runs an OS command and save its standard output as a file. Typically used for - * MySQL or OpenLDAP dumps. - */ -public class OsCallBackup extends AbstractAtomicBackup { - private final static Log log = LogFactory.getLog(OsCallBackup.class); - - private String command; - private Map variables = new HashMap(); - private Executor executor = new DefaultExecutor(); - - private Map environment = new HashMap(); - - /** Name of the sudo user, root if "", not sudo if null */ - private String sudo = null; - - public OsCallBackup() { - } - - public OsCallBackup(String name) { - super(name); - } - - public OsCallBackup(String name, String command) { - super(name); - this.command = command; - } - - @Override - public void writeBackup(FileObject targetFo) { - String commandToUse = command; - - // sudo - if (sudo != null) { - if (sudo.equals("")) - commandToUse = "sudo " + commandToUse; - else - commandToUse = "sudo -u " + sudo + " " + commandToUse; - } - - CommandLine commandLine = CommandLine.parse(commandToUse, variables); - ByteArrayOutputStream errBos = new ByteArrayOutputStream(); - if (log.isTraceEnabled()) - log.trace(commandLine.toString()); - - try { - // stdout - FileContent targetContent = targetFo.getContent(); - // stderr - ExecuteStreamHandler streamHandler = new PumpStreamHandler(targetContent.getOutputStream(), errBos); - executor.setStreamHandler(streamHandler); - executor.execute(commandLine, environment); - } catch (ExecuteException e) { - byte[] err = errBos.toByteArray(); - String errStr = new String(err); - throw new MaintenanceException("Process " + commandLine + " failed (" + e.getExitValue() + "): " + errStr, e); - } catch (Exception e) { - byte[] err = errBos.toByteArray(); - String errStr = new String(err); - throw new MaintenanceException("Process " + commandLine + " failed: " + errStr, e); - } finally { - IOUtils.closeQuietly(errBos); - } - } - - public void setCommand(String command) { - this.command = command; - } - - protected String getCommand() { - return command; - } - - /** - * A reference to the environment variables that will be passed to the - * process. Empty by default. - */ - protected Map getEnvironment() { - return environment; - } - - protected Map getVariables() { - return variables; - } - - public void setVariables(Map variables) { - this.variables = variables; - } - - public void setExecutor(Executor executor) { - this.executor = executor; - } - - public void setSudo(String sudo) { - this.sudo = sudo; - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/PostgreSqlBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/PostgreSqlBackup.java deleted file mode 100644 index 5a00c24e0..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/PostgreSqlBackup.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import org.apache.commons.vfs2.FileObject; - -/** Backups a PostgreSQL database using pg_dump. */ -public class PostgreSqlBackup extends OsCallBackup { - /** - * PostgreSQL password environment variable (see - * http://stackoverflow.com/questions - * /2893954/how-to-pass-in-password-to-pg-dump) - */ - protected final static String PGPASSWORD = "PGPASSWORD"; - - private String pgDumpLocation = "/usr/bin/pg_dump"; - - private String dbUser; - private String dbPassword; - private String dbName; - - public PostgreSqlBackup() { - super(); - } - - public PostgreSqlBackup(String dbUser, String dbPassword, String dbName) { - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbName = dbName; - init(); - } - - @Override - public void init() { - // disable compression since pg_dump is used with -Fc option - setCompression(null); - - if (getName() == null) - setName(dbName + ".pgdump"); - super.init(); - } - - @Override - public void writeBackup(FileObject targetFo) { - if (getCommand() == null) { - getEnvironment().put(PGPASSWORD, dbPassword); - setCommand(pgDumpLocation + " -Fc" + " -U ${dbUser} ${dbName}"); - } - getVariables().put("dbUser", dbUser); - getVariables().put("dbPassword", dbPassword); - getVariables().put("dbName", dbName); - - super.writeBackup(targetFo); - } - - public void setDbUser(String dbUser) { - this.dbUser = dbUser; - } - - public void setDbPassword(String dbPassword) { - this.dbPassword = dbPassword; - } - - public void setDbName(String dbName) { - this.dbName = dbName; - } - - public void setPgDumpLocation(String mysqldumpLocation) { - this.pgDumpLocation = mysqldumpLocation; - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SimpleBackupContext.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SimpleBackupContext.java deleted file mode 100644 index 257b20f32..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SimpleBackupContext.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -import org.apache.commons.vfs2.FileSystemManager; - -/** Simple implementation of a backup context */ -public class SimpleBackupContext implements BackupContext { - private DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmm"); - private final Date timestamp; - private final String name; - - private final FileSystemManager fileSystemManager; - - public SimpleBackupContext(FileSystemManager fileSystemManager, - String backupsBase, String name) { - this.name = name; - this.timestamp = new Date(); - this.fileSystemManager = fileSystemManager; - } - - public Date getTimestamp() { - return timestamp; - } - - public String getTimestampAsString() { - return dateFormat.format(timestamp); - } - - public String getSystemName() { - return name; - } - - public String getRelativeFolder() { - return name + '/' + getTimestampAsString(); - } - - public DateFormat getDateFormat() { - return dateFormat; - } - - public FileSystemManager getFileSystemManager() { - return fileSystemManager; - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SimpleBackupPurge.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SimpleBackupPurge.java deleted file mode 100644 index 2d4abaa97..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SimpleBackupPurge.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.text.DateFormat; -import java.time.Period; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.Date; -import java.util.SortedMap; -import java.util.TreeMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.Selectors; -import org.argeo.maintenance.MaintenanceException; - -/** Simple backup purge which keeps backups only for a given number of days */ -public class SimpleBackupPurge implements BackupPurge { - private final static Log log = LogFactory.getLog(SimpleBackupPurge.class); - - private Integer daysKept = 30; - - @Override - public void purge(FileSystemManager fileSystemManager, String base, String name, DateFormat dateFormat, - FileSystemOptions opts) { - try { - ZonedDateTime nowDt = ZonedDateTime.now(); - FileObject baseFo = fileSystemManager.resolveFile(base + '/' + name, opts); - - SortedMap toDelete = new TreeMap(); - int backupCount = 0; - - // make sure base dir exists - baseFo.createFolder(); - - // scan backups and list those which should be deleted - for (FileObject backupFo : baseFo.getChildren()) { - String backupName = backupFo.getName().getBaseName(); - Date backupDate = dateFormat.parse(backupName); - backupCount++; - ZonedDateTime backupDt = ZonedDateTime.ofInstant(backupDate.toInstant(), ZoneId.systemDefault()); - Period sinceThen = Period.between(backupDt.toLocalDate(), nowDt.toLocalDate()); - // new Period(backupDt, nowDt); - int days = sinceThen.getDays(); - // int days = sinceThen.getMinutes(); - if (days > daysKept) { - toDelete.put(backupDt, backupFo); - } - } - - if (toDelete.size() != 0 && toDelete.size() == backupCount) { - // all backups would be deleted - // but we want to keep at least one - ZonedDateTime lastBackupDt = toDelete.firstKey(); - FileObject keptFo = toDelete.remove(lastBackupDt); - log.warn("Backup " + keptFo + " kept although it is older than " + daysKept + " days."); - } - - // delete old backups - for (FileObject backupFo : toDelete.values()) { - backupFo.delete(Selectors.SELECT_ALL); - if (log.isDebugEnabled()) - log.debug("Deleted backup " + backupFo); - } - } catch (Exception e) { - throw new MaintenanceException("Could not purge previous backups", e); - } - - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SvnBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SvnBackup.java deleted file mode 100644 index 711f51831..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SvnBackup.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.io.File; - -import org.apache.commons.vfs2.FileObject; - -/** Backups a Subversion repository using svnadmin. */ -public class SvnBackup extends OsCallBackup { - private String svnadminLocation = "/usr/bin/svnadmin"; - - private String repoLocation; - private String repoName; - - public SvnBackup() { - } - - public SvnBackup(String repoLocation) { - this.repoLocation = repoLocation; - init(); - } - - @Override - public void init() { - // use directory as repo name - if (repoName == null) - repoName = new File(repoLocation).getName(); - - if (getName() == null) - setName(repoName + ".svndump"); - super.init(); - } - - @Override - public void writeBackup(FileObject targetFo) { - if (getCommand() == null) { - setCommand(svnadminLocation + " dump " + " ${repoLocation}"); - } - getVariables().put("repoLocation", repoLocation); - - super.writeBackup(targetFo); - } - - public void setRepoLocation(String repoLocation) { - this.repoLocation = repoLocation; - } - - public void setRepoName(String repoName) { - this.repoName = repoName; - } - - public void setSvnadminLocation(String mysqldumpLocation) { - this.svnadminLocation = mysqldumpLocation; - } - -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SystemBackup.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SystemBackup.java deleted file mode 100644 index 331b77613..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/SystemBackup.java +++ /dev/null @@ -1,201 +0,0 @@ -package org.argeo.maintenance.backup.vfs; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.Selectors; -import org.apache.commons.vfs2.UserAuthenticator; -import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder; -import org.argeo.maintenance.MaintenanceException; -import org.argeo.util.LangUtils; - -/** - * Combines multiple backups and transfer them to a remote location. Purges - * remote and local data based on certain criteria. - */ -public class SystemBackup implements Runnable { - private final static Log log = LogFactory.getLog(SystemBackup.class); - - private FileSystemManager fileSystemManager; - private UserAuthenticator userAuthenticator = null; - - private String backupsBase; - private String systemName; - - private List atomicBackups = new ArrayList(); - private BackupPurge backupPurge = new SimpleBackupPurge(); - - private Map remoteBases = new HashMap(); - - @Override - public void run() { - if (atomicBackups.size() == 0) - throw new MaintenanceException("No atomic backup listed"); - List failures = new ArrayList(); - - SimpleBackupContext backupContext = new SimpleBackupContext(fileSystemManager, backupsBase, systemName); - - // purge older backups - FileSystemOptions opts = new FileSystemOptions(); - try { - DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, userAuthenticator); - } catch (FileSystemException e) { - throw new MaintenanceException("Cannot create authentication", e); - } - - try { - - backupPurge.purge(fileSystemManager, backupsBase, systemName, backupContext.getDateFormat(), opts); - } catch (Exception e) { - failures.add("Purge " + backupsBase + " failed: " + e.getMessage()); - log.error("Purge of " + backupsBase + " failed", e); - } - - // perform backup - for (AtomicBackup atomickBackup : atomicBackups) { - try { - String target = atomickBackup.backup(fileSystemManager, backupsBase, backupContext, opts); - if (log.isDebugEnabled()) - log.debug("Performed backup " + target); - } catch (Exception e) { - String msg = "Atomic backup " + atomickBackup.getName() + " failed: " - + LangUtils.chainCausesMessages(e); - failures.add(msg); - log.error(msg); - if (log.isTraceEnabled()) - log.trace("Stacktrace of atomic backup " + atomickBackup.getName() + " failure.", e); - } - } - - // dispatch to remote - for (String remoteBase : remoteBases.keySet()) { - FileObject localBaseFo = null; - FileObject remoteBaseFo = null; - UserAuthenticator auth = remoteBases.get(remoteBase); - - // authentication - FileSystemOptions remoteOpts = new FileSystemOptions(); - try { - DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(remoteOpts, auth); - backupPurge.purge(fileSystemManager, remoteBase, systemName, backupContext.getDateFormat(), remoteOpts); - } catch (Exception e) { - failures.add("Purge " + remoteBase + " failed: " + e.getMessage()); - log.error("Cannot purge " + remoteBase, e); - } - - try { - localBaseFo = fileSystemManager.resolveFile(backupsBase + '/' + backupContext.getRelativeFolder(), - opts); - remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/' + backupContext.getRelativeFolder(), - remoteOpts); - remoteBaseFo.copyFrom(localBaseFo, Selectors.SELECT_ALL); - if (log.isDebugEnabled()) - log.debug("Copied backup to " + remoteBaseFo + " from " + localBaseFo); - // } - } catch (Exception e) { - failures.add("Dispatch to " + remoteBase + " failed: " + e.getMessage()); - log.error("Cannot dispatch backups from " + backupContext.getRelativeFolder() + " to " + remoteBase, e); - } - BackupUtils.closeFOQuietly(localBaseFo); - BackupUtils.closeFOQuietly(remoteBaseFo); - } - - int failureCount = 0; - if (failures.size() > 0) { - StringBuffer buf = new StringBuffer(); - for (String failure : failures) { - buf.append('\n').append(failureCount).append(" - ").append(failure); - failureCount++; - } - throw new MaintenanceException(failureCount + " error(s) when running the backup," - + " check the logs and the backups as soon as possible." + buf); - } - } - - public void setFileSystemManager(FileSystemManager fileSystemManager) { - this.fileSystemManager = fileSystemManager; - } - - public void setBackupsBase(String backupsBase) { - this.backupsBase = backupsBase; - } - - public void setSystemName(String name) { - this.systemName = name; - } - - public void setAtomicBackups(List atomicBackups) { - this.atomicBackups = atomicBackups; - } - - public void setBackupPurge(BackupPurge backupPurge) { - this.backupPurge = backupPurge; - } - - public void setUserAuthenticator(UserAuthenticator userAuthenticator) { - this.userAuthenticator = userAuthenticator; - } - - public void setRemoteBases(Map remoteBases) { - this.remoteBases = remoteBases; - } - - // public static void main(String args[]) { - // while (true) { - // try { - // StandardFileSystemManager fsm = new StandardFileSystemManager(); - // fsm.init(); - // - // SystemBackup systemBackup = new SystemBackup(); - // systemBackup.setSystemName("mySystem"); - // systemBackup - // .setBackupsBase("/home/mbaudier/dev/src/commons/server/runtime/org.argeo.server.core/target"); - // systemBackup.setFileSystemManager(fsm); - // - // List atomicBackups = new ArrayList(); - // - // MySqlBackup mySqlBackup = new MySqlBackup("root", "", "test"); - // atomicBackups.add(mySqlBackup); - // PostgreSqlBackup postgreSqlBackup = new PostgreSqlBackup( - // "argeo", "argeo", "gis_template"); - // atomicBackups.add(postgreSqlBackup); - // SvnBackup svnBackup = new SvnBackup( - // "/home/mbaudier/tmp/testsvnrepo"); - // atomicBackups.add(svnBackup); - // - // systemBackup.setAtomicBackups(atomicBackups); - // - // Map remoteBases = new HashMap(); - // StaticUserAuthenticator userAuthenticator = new StaticUserAuthenticator( - // null, "demo", "demo"); - // remoteBases.put("sftp://localhost/home/mbaudier/test", - // userAuthenticator); - // systemBackup.setRemoteBases(remoteBases); - // - // systemBackup.run(); - // - // fsm.close(); - // } catch (FileSystemException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // System.exit(1); - // } - // - // // wait - // try { - // Thread.sleep(120 * 1000); - // } catch (InterruptedException e) { - // e.printStackTrace(); - // } - // } - // } -} diff --git a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/package-info.java b/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/package-info.java deleted file mode 100644 index f5d714212..000000000 --- a/org.argeo.maintenance/src/org/argeo/maintenance/backup/vfs/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Argeo Node backup utilities based on Apache Commons VFS. */ -package org.argeo.maintenance.backup.vfs; \ No newline at end of file diff --git a/pom.xml b/pom.xml index 04395f9fc..e143ba9e9 100644 --- a/pom.xml +++ b/pom.xml @@ -41,9 +41,6 @@ org.argeo.cms.e4 org.argeo.cms.e4.rap - - - org.argeo.ext.equinox.jetty dep demo