From 0af549d05ec45b5e31df9026b6627de9038d39eb Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 17 Oct 2015 11:52:16 +0000 Subject: [PATCH] Improve authentication and logging. git-svn-id: https://svn.argeo.org/commons/trunk@8501 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- demo/argeo_node_cms.properties | 12 ++--- demo/log4j.properties | 2 +- dep/org.argeo.dep.cms/pom.xml | 5 ++ .../argeo/cms/auth/HttpRequestCallback.java | 8 ++++ .../argeo/cms/internal/kernel/DataHttp.java | 27 +++-------- .../org/argeo/cms/internal/kernel/Kernel.java | 15 +++++- .../cms/internal/kernel/KernelUtils.java | 1 + .../argeo/cms/internal/kernel/NodeLogger.java | 42 ++++++++++++++++- .../org/argeo/cms/internal/kernel/UserUi.java | 26 ++++++++++ .../org/argeo/cms/util/LoginEntryPoint.java | 41 +++++----------- .../argeo/eclipse/ui/specific/UiContext.java | 3 +- .../security/ui/rap/RapWorkbenchLogin.java | 47 ++++++++++++++++--- 12 files changed, 163 insertions(+), 66 deletions(-) create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/UserUi.java rename org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java => org.argeo.cms/src/org/argeo/cms/util/LoginEntryPoint.java (80%) diff --git a/demo/argeo_node_cms.properties b/demo/argeo_node_cms.properties index 899bb1201..1ccc216ab 100644 --- a/demo/argeo_node_cms.properties +++ b/demo/argeo_node_cms.properties @@ -9,14 +9,14 @@ argeo.osgi.start.4.node=\ org.eclipse.rap.rwt.osgi,\ org.eclipse.gemini.blueprint.extender -argeo.osgi.start.4.cms=\ -org.argeo.cms.core +#argeo.osgi.start.4.cms=\ +#org.argeo.cms.core -argeo.osgi.start.4.workbench=\ -org.eclipse.equinox.http.registry,\ +#argeo.osgi.start.4.workbench=\ +#org.eclipse.equinox.http.registry,\ -argeo.osgi.start.5.cms=\ -org.argeo.cms.demo +#argeo.osgi.start.5.cms=\ +#org.argeo.cms.demo org.osgi.service.http.port=7070 #org.osgi.service.http.port.secure=7073 diff --git a/demo/log4j.properties b/demo/log4j.properties index 62d1c06e9..94c48c3d7 100644 --- a/demo/log4j.properties +++ b/demo/log4j.properties @@ -1,4 +1,4 @@ -log4j.rootLogger=WARN, development +log4j.rootLogger=WARN, console log4j.logger.org.argeo=DEBUG log4j.logger.org.argeo.cms.internal.kernel=TRACE diff --git a/dep/org.argeo.dep.cms/pom.xml b/dep/org.argeo.dep.cms/pom.xml index 602ffabea..b55e3ae52 100644 --- a/dep/org.argeo.dep.cms/pom.xml +++ b/dep/org.argeo.dep.cms/pom.xml @@ -20,6 +20,11 @@ org.argeo.util 2.1.29-SNAPSHOT + + org.argeo.commons + org.argeo.eclipse.ui.rap + 2.1.29-SNAPSHOT + diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java index eb3368d05..dbc2aeee9 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/HttpRequestCallback.java @@ -13,5 +13,13 @@ public class HttpRequestCallback implements Callback { public void setRequest(HttpServletRequest request) { this.request = request; } + // private X509Certificate extractCertificate(HttpServletRequest req) { + // X509Certificate[] certs = (X509Certificate[]) req + // .getAttribute("javax.servlet.request.X509Certificate"); + // if (null != certs && certs.length > 0) { + // return certs[0]; + // } + // return null; + // } } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java index ab9211a54..ebf483a7a 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DataHttp.java @@ -21,7 +21,6 @@ import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.CredentialNotFoundException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; -import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -65,11 +64,11 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { DataHttp(HttpService httpService, NodeRepository node) { this.httpService = httpService; sessionProvider = new OpenInViewSessionProvider(); - registerRepositoryServlets(ALIAS_NODE, node); + // registerRepositoryServlets(ALIAS_NODE, node); } public void destroy() { - unregisterRepositoryServlets(ALIAS_NODE); + // unregisterRepositoryServlets(ALIAS_NODE); } void registerRepositoryServlets(String alias, Repository repository) { @@ -97,10 +96,7 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { Properties ip = new Properties(); ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, WEBDAV_CONFIG); ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path); - // httpService.registerFilter(path, anonymous ? new AnonymousFilter() - // : new DavFilter(), null, null); - // Cast to servlet because of a weird behaviour in Eclipse - httpService.registerServlet(path, (Servlet) webdavServlet, ip, + httpService.registerServlet(path, webdavServlet, ip, new DataHttpContext(anonymous)); } @@ -119,22 +115,10 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting"); // in order to avoid annoying warning. ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, ""); - // Cast to servlet because of a weird behaviour in Eclipse - // httpService.registerFilter(path, anonymous ? new AnonymousFilter() - // : new DavFilter(), null, null); - httpService.registerServlet(path, (Servlet) remotingServlet, ip, + httpService.registerServlet(path, remotingServlet, ip, new DataHttpContext(anonymous)); } -// private X509Certificate extractCertificate(HttpServletRequest req) { -// X509Certificate[] certs = (X509Certificate[]) req -// .getAttribute("javax.servlet.request.X509Certificate"); -// if (null != certs && certs.length > 0) { -// return certs[0]; -// } -// return null; -// } - private Subject subjectFromRequest(HttpServletRequest request) { Authorization authorization = (Authorization) request .getAttribute(HttpContext.AUTHORIZATION); @@ -172,7 +156,8 @@ class DataHttp implements KernelConstants, ArgeoJcrConstants { return true; } - KernelUtils.logRequestHeaders(log, request); + if (log.isTraceEnabled()) + KernelUtils.logRequestHeaders(log, request); try { new LoginContext(LOGIN_CONTEXT_USER, new HttpRequestCallbackHandler(request)).login(); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index 100230400..8a1cf8e96 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -40,6 +40,7 @@ import org.argeo.jcr.ArgeoJcrConstants; import org.eclipse.equinox.http.jetty.JettyConfigurator; import org.eclipse.equinox.http.jetty.JettyConstants; import org.eclipse.equinox.http.servlet.ExtendedHttpService; +import org.eclipse.rap.rwt.application.ApplicationConfiguration; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; @@ -47,7 +48,9 @@ import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.log.LogReaderService; import org.osgi.service.useradmin.UserAdmin; +import org.osgi.util.tracker.ServiceTracker; import bitronix.tm.BitronixTransactionManager; import bitronix.tm.BitronixTransactionSynchronizationRegistry; @@ -133,7 +136,12 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { defaultLocale = new Locale(getFrameworkProp(I18N_DEFAULT_LOCALE, ENGLISH.getLanguage())); locales = asLocaleList(getFrameworkProp(I18N_LOCALES)); - logger = new NodeLogger(); + + ServiceTracker logReaderService = new ServiceTracker( + bc, LogReaderService.class, null); + logReaderService.open(); + logger = new NodeLogger(logReaderService.getService()); + logReaderService.close(); // Initialise services initTransactionManager(); @@ -148,6 +156,11 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener { if (sr != null) addHttpService(sr); + UserUi userUi = new UserUi(); + Hashtable props = new Hashtable(); + props.put("contextName", "user"); + bc.registerService(ApplicationConfiguration.class, userUi, props); + // Kernel thread kernelThread = new KernelThread(this); kernelThread.setContextClassLoader(Kernel.class.getClassLoader()); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java index 1d15e2a3a..cce1c4ff9 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -139,6 +139,7 @@ class KernelUtils implements KernelConstants { Object headerValue = request.getHeader(headerName); log.debug(headerName + ": " + headerValue); } + log.debug(""); } static void logFrameworkProperties(Log log) { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java index 1264b2452..ac0c8469f 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java @@ -15,8 +15,10 @@ */ package org.argeo.cms.internal.kernel; +import java.security.SignatureException; import java.util.ArrayList; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -27,6 +29,8 @@ import java.util.Properties; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.Level; import org.apache.log4j.LogManager; @@ -37,9 +41,13 @@ import org.argeo.ArgeoException; import org.argeo.ArgeoLogListener; import org.argeo.ArgeoLogger; import org.argeo.cms.auth.CurrentUser; +import org.osgi.service.log.LogEntry; +import org.osgi.service.log.LogListener; +import org.osgi.service.log.LogReaderService; +import org.osgi.service.log.LogService; /** Not meant to be used directly in standard log4j config */ -class NodeLogger implements ArgeoLogger { +class NodeLogger implements ArgeoLogger, LogListener { private Boolean disabled = false; @@ -73,6 +81,14 @@ class NodeLogger implements ArgeoLogger { } }; + @SuppressWarnings("unchecked") + public NodeLogger(LogReaderService lrs) { + Enumeration logEntries = lrs.getLog(); + while (logEntries.hasMoreElements()) + logged(logEntries.nextElement()); + lrs.addLogListener(this); + } + public void init() { try { events = new LinkedBlockingQueue(); @@ -108,6 +124,30 @@ class NodeLogger implements ArgeoLogger { // this.layout = layout; // } + // + // OSGi LOGGER + // + @Override + public void logged(LogEntry status) { + Log pluginLog = LogFactory.getLog(status.getBundle().getSymbolicName()); + Integer severity = status.getLevel(); + if (severity == LogService.LOG_ERROR) { + // FIXME Fix Argeo TP + if (status.getException() instanceof SignatureException) + return; + pluginLog.error(status.getMessage(), status.getException()); + } else if (severity == LogService.LOG_WARNING) + pluginLog.warn(status.getMessage(), status.getException()); + else if (severity == LogService.LOG_INFO && pluginLog.isDebugEnabled()) + pluginLog.debug(status.getMessage(), status.getException()); + else if (severity == LogService.LOG_DEBUG && pluginLog.isTraceEnabled()) + pluginLog.trace(status.getMessage(), status.getException()); + } + + // + // ARGEO LOGGER + // + public synchronized void register(ArgeoLogListener listener, Integer numberOfPreviousEvents) { String username = CurrentUser.getUsername(); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/UserUi.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/UserUi.java new file mode 100644 index 000000000..936882a0f --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/UserUi.java @@ -0,0 +1,26 @@ +package org.argeo.cms.internal.kernel; + +import org.argeo.cms.util.LoginEntryPoint; +import org.eclipse.rap.rwt.application.Application; +import org.eclipse.rap.rwt.application.ApplicationConfiguration; +import org.eclipse.rap.rwt.application.EntryPoint; +import org.eclipse.rap.rwt.application.EntryPointFactory; +import org.eclipse.rap.rwt.application.Application.OperationMode; + +public class UserUi implements ApplicationConfiguration { + + @Override + public void configure(Application application) { + application.setOperationMode(OperationMode.SWT_COMPATIBILITY); + application.addEntryPoint("/login", LoginEntryPoint.class, null); + } + + private class LoginEpf implements EntryPointFactory { + + @Override + public EntryPoint create() { + return new LoginEntryPoint(); + } + + } +} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java b/org.argeo.cms/src/org/argeo/cms/util/LoginEntryPoint.java similarity index 80% rename from org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java rename to org.argeo.cms/src/org/argeo/cms/util/LoginEntryPoint.java index a074ed956..4ccedd19b 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/WorkbenchLogin.java +++ b/org.argeo.cms/src/org/argeo/cms/util/LoginEntryPoint.java @@ -1,6 +1,5 @@ -package org.argeo.security.ui.rap; +package org.argeo.cms.util; -import java.security.PrivilegedAction; import java.util.Locale; import javax.security.auth.Subject; @@ -14,7 +13,6 @@ import org.argeo.cms.CmsException; import org.argeo.cms.CmsImageManager; import org.argeo.cms.CmsView; import org.argeo.cms.auth.AuthConstants; -import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.auth.HttpRequestCallbackHandler; import org.argeo.cms.widgets.auth.CmsLogin; import org.argeo.cms.widgets.auth.CmsLoginShell; @@ -25,16 +23,15 @@ import org.eclipse.rap.rwt.application.EntryPoint; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.PlatformUI; -abstract class WorkbenchLogin implements EntryPoint, CmsView { +public class LoginEntryPoint implements EntryPoint, CmsView { // private final static Log log = LogFactory.getLog(WorkbenchLogin.class); private final Subject subject = new Subject(); private LoginContext loginContext; @Override public int createUI() { - final Display display = PlatformUI.createDisplay(); + final Display display = createDisplay(); UiContext.setData(CmsView.KEY, this); try { // try pre-auth @@ -61,28 +58,16 @@ abstract class WorkbenchLogin implements EntryPoint, CmsView { } catch (LoginException e) { throw new ArgeoException("Cannot log in", e); } - // - // RUN THE WORKBENCH - // - Integer returnCode = null; - try { - returnCode = Subject.doAs(subject, new PrivilegedAction() { - public Integer run() { - int result = createAndRunWorkbench(display, - CurrentUser.getUsername(subject)); - return new Integer(result); - } - }); - // explicit workbench closing - logout(); - } finally { - display.dispose(); - } - return returnCode; + return postLogin(); } - protected abstract int createAndRunWorkbench(Display display, - String username); + protected Display createDisplay() { + return new Display(); + } + + protected int postLogin() { + return 0; + } protected HttpServletRequest getRequest() { return RWT.getRequest(); @@ -93,14 +78,14 @@ abstract class WorkbenchLogin implements EntryPoint, CmsView { @Override public void createContents(Composite parent) { - WorkbenchLogin.this.createLoginPage(parent, this); + LoginEntryPoint.this.createLoginPage(parent, this); } @Override protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale, SelectionListener loginSelectionListener) { - WorkbenchLogin.this.extendsCredentialsBlock(credentialsBlock, + LoginEntryPoint.this.extendsCredentialsBlock(credentialsBlock, selectedLocale, loginSelectionListener); } diff --git a/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/specific/UiContext.java b/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/specific/UiContext.java index 82b606124..ebececf15 100644 --- a/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/specific/UiContext.java +++ b/org.argeo.eclipse.ui.rap/src/org/argeo/eclipse/ui/specific/UiContext.java @@ -19,7 +19,8 @@ public class UiContext { } public static void setLocale(Locale locale) { - RWT.getUISession().setLocale(locale); + if (Display.getCurrent() != null) + RWT.getUISession().setLocale(locale); } /** Can always be null */ diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java index 789874ae3..790e6175d 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWorkbenchLogin.java @@ -1,9 +1,14 @@ package org.argeo.security.ui.rap; +import java.security.PrivilegedAction; import java.util.Locale; +import javax.security.auth.Subject; + import org.argeo.cms.CmsMsg; +import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.util.CmsUtils; +import org.argeo.cms.util.LoginEntryPoint; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.client.service.JavaScriptExecutor; import org.eclipse.swt.SWT; @@ -13,16 +18,10 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; -public class RapWorkbenchLogin extends WorkbenchLogin { +public class RapWorkbenchLogin extends LoginEntryPoint { // private final static Log log = // LogFactory.getLog(RapWorkbenchLogin.class); - @Override - protected int createAndRunWorkbench(Display display, String username) { - RapWorkbenchAdvisor workbenchAdvisor = createRapWorkbenchAdvisor(username); - return PlatformUI.createAndRunWorkbench(display, workbenchAdvisor); - } - /** Override to provide an application specific workbench advisor */ protected RapWorkbenchAdvisor createRapWorkbenchAdvisor(String username) { return new RapWorkbenchAdvisor(username); @@ -42,6 +41,35 @@ public class RapWorkbenchLogin extends WorkbenchLogin { return returnCode; } + @Override + protected int postLogin() { + final Display display = Display.getCurrent(); + // + // RUN THE WORKBENCH + // + Integer returnCode = null; + try { + returnCode = Subject.doAs(getSubject(), + new PrivilegedAction() { + public Integer run() { + int result = createAndRunWorkbench(display, + CurrentUser.getUsername(getSubject())); + return new Integer(result); + } + }); + // explicit workbench closing + logout(); + } finally { + display.dispose(); + } + return returnCode; + } + + protected int createAndRunWorkbench(Display display, String username) { + RapWorkbenchAdvisor workbenchAdvisor = createRapWorkbenchAdvisor(username); + return PlatformUI.createAndRunWorkbench(display, workbenchAdvisor); + } + @Override protected void extendsCredentialsBlock(Composite credentialsBlock, Locale selectedLocale, SelectionListener loginSelectionListener) { @@ -51,4 +79,9 @@ public class RapWorkbenchLogin extends WorkbenchLogin { loginButton.addSelectionListener(loginSelectionListener); } + @Override + protected Display createDisplay() { + return PlatformUI.createDisplay(); + } + } -- 2.30.2