X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2FAbstractCmsEntryPoint.java;h=0a988a63e99d6087ea70490f977984b3aa1fe407;hb=871dd95ada4cf946c8d51d3a2546c817238ad08c;hp=00db13443b0cb44d6845f288471c4d53014e45eb;hpb=24c63057592c8ef8a161f3f37bbdafd0cd475dd5;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java index 00db13443..0a988a63e 100644 --- a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java +++ b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java @@ -1,25 +1,28 @@ package org.argeo.cms; +import java.security.PrivilegedAction; import java.util.HashMap; -import java.util.Locale; import java.util.Map; -import java.util.ResourceBundle; import javax.jcr.Node; +import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import javax.security.auth.Subject; +import javax.security.auth.login.CredentialNotFoundException; +import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; -import org.argeo.cms.auth.ArgeoLoginContext; -import org.argeo.cms.auth.LoginRequiredException; -import org.argeo.cms.i18n.Msg; +import org.argeo.cms.auth.AuthConstants; +import org.argeo.cms.auth.HttpRequestCallbackHandler; +import org.argeo.eclipse.ui.specific.UiContext; import org.argeo.jcr.JcrUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.AbstractEntryPoint; @@ -34,10 +37,11 @@ import org.eclipse.swt.widgets.Shell; /** Manages history and navigation */ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint - implements CmsSession { + implements CmsView { private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class); - private final Subject subject = new Subject(); + private final Subject subject; + private LoginContext loginContext; private final Repository repository; private final String workspace; @@ -47,6 +51,7 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint // Current state private Session session; private Node node; + private String nodePath;// useful when changing auth private String state; private String page; private Throwable exception; @@ -61,23 +66,26 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint this.workspace = workspace; this.defaultPath = defaultPath; this.factoryProperties = new HashMap(factoryProperties); + subject = new Subject(); // Initial login try { - new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_USER, subject) - .login(); - } catch (LoginException e) { - // if (log.isTraceEnabled()) - // log.trace("Cannot authenticate user", e); + loginContext = new LoginContext(AuthConstants.LOGIN_CONTEXT_USER, + subject, new HttpRequestCallbackHandler( + UiContext.getHttpRequest())); + loginContext.login(); + } catch (CredentialNotFoundException e) { try { - new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS, - subject).login(); - } catch (LoginException eAnonymous) { - throw new ArgeoException("Cannot initialize subject", - eAnonymous); + loginContext = new LoginContext( + AuthConstants.LOGIN_CONTEXT_ANONYMOUS, subject); + loginContext.login(); + } catch (LoginException e1) { + throw new ArgeoException("Cannot log as anonymous", e); } + } catch (LoginException e) { + throw new ArgeoException("Cannot initialize subject", e); } - authChange(); + authChange(loginContext); jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class); browserNavigation = RWT.getClient().getService(BrowserNavigation.class); @@ -103,18 +111,24 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint } @Override - protected final void createContents(Composite parent) { - try { - getShell().getDisplay().setData(CmsSession.KEY, this); - - createUi(parent); - } catch (Exception e) { - throw new CmsException("Cannot create entrypoint contents", e); - } + protected final void createContents(final Composite parent) { + UiContext.setData(CmsView.KEY, this); + Subject.doAs(subject, new PrivilegedAction() { + @Override + public Void run() { + try { + initUi(parent); + } catch (Exception e) { + throw new CmsException("Cannot create entrypoint contents", + e); + } + return null; + } + }); } /** Create UI */ - protected abstract void createUi(Composite parent); + protected abstract void initUi(Composite parent); /** Recreate UI after navigation or auth change */ protected abstract void refresh(); @@ -125,8 +139,9 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint */ protected Node getDefaultNode(Session session) throws RepositoryException { if (!session.hasPermission(defaultPath, "read")) { - if (session.getUserID().equals("anonymous")) - throw new LoginRequiredException(); + if (session.getUserID().equals(AuthConstants.ROLE_ANONYMOUS)) + // TODO throw a special exception + throw new CmsException("Login required"); else throw new CmsException("Unauthorized"); } @@ -140,79 +155,87 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint public void navigateTo(String state) { exception = null; String title = setState(state); - refresh(); + doRefresh(); if (browserNavigation != null) browserNavigation.pushState(state, title); } @Override - public Subject getSubject() { + public synchronized Subject getSubject() { return subject; } @Override - public void authChange() { + public synchronized void logout() { + if (loginContext == null) + throw new CmsException("Login context should not be null"); try { - String currentPath = null; - if (node != null) - currentPath = node.getPath(); - JcrUtils.logoutQuietly(session); + loginContext.logout(); + LoginContext anonymousLc = new LoginContext( + AuthConstants.LOGIN_CONTEXT_ANONYMOUS, subject); + anonymousLc.login(); + authChange(anonymousLc); + } catch (LoginException e) { + throw new CmsException("Cannot logout", e); + } + } + + @Override + public synchronized void authChange(LoginContext loginContext) { + if (loginContext == null) + throw new CmsException("Login context cannot be null"); + this.loginContext = loginContext; + Subject.doAs(loginContext.getSubject(), new PrivilegedAction() { - session = repository.login(workspace); - if (currentPath != null) + @Override + public Void run() { try { - node = session.getNode(currentPath); - } catch (Exception e) { - try { - // TODO find a less hacky way to log out - new ArgeoLoginContext( - KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject) - .logout(); - new ArgeoLoginContext( - KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject) - .login(); - } catch (LoginException eAnonymous) { - throw new ArgeoException("Cannot reset to anonymous", - eAnonymous); - } JcrUtils.logoutQuietly(session); session = repository.login(workspace); - navigateTo("~"); - throw e; + if (nodePath != null) + try { + node = session.getNode(nodePath); + } catch (PathNotFoundException e) { + // logout(); + // session = repository.login(workspace); + navigateTo("~"); + throw e; + } + + // refresh UI + doRefresh(); + } catch (RepositoryException e) { + throw new CmsException("Cannot perform auth change", e); } + return null; + } - // refresh UI - refresh(); - } catch (RepositoryException e) { - throw new CmsException("Cannot perform auth change", e); - } + }); } @Override - public void exception(Throwable e) { - this.exception = e; + public void exception(final Throwable e) { + AbstractCmsEntryPoint.this.exception = e; log.error("Unexpected exception in CMS", e); - refresh(); + doRefresh(); } - @Override - public Object local(Msg msg) { - String key = msg.getId(); - int lastDot = key.lastIndexOf('.'); - String className = key.substring(0, lastDot); - String fieldName = key.substring(lastDot + 1); - Locale locale = RWT.getLocale(); - ResourceBundle rb = ResourceBundle.getBundle(className, locale, - msg.getClassLoader()); - return rb.getString(fieldName); + protected synchronized void doRefresh() { + Subject.doAs(subject, new PrivilegedAction() { + @Override + public Void run() { + refresh(); + return null; + } + }); } /** Sets the state of the entry point and retrieve the related JCR node. */ protected synchronized String setState(String newState) { String previousState = this.state; - node = null; + Node node = null; page = null; this.state = newState; if (newState.equals("~")) @@ -238,20 +261,12 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint node = getDefaultNode(session); page = state; } - - // Title - String title; - if (node.isNodeType(NodeType.MIX_TITLE) - && node.hasProperty(Property.JCR_TITLE)) - title = node.getProperty(Property.JCR_TITLE).getString() - + " - " + getBaseTitle(); - else - title = getBaseTitle(); - jsExecutor.execute("document.title = \"" + title + "\""); + setNode(node); + String title = publishMetaData(node); if (log.isTraceEnabled()) log.trace("node=" + node + ", state=" + state + " (page=" - + page + ", title=" + title + ")"); + + page + ")"); return title; } catch (Exception e) { @@ -264,10 +279,71 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint } } - protected Node getNode() { + private String publishMetaData(Node node) throws RepositoryException { + // Title + String title; + if (node.isNodeType(NodeType.MIX_TITLE) + && node.hasProperty(Property.JCR_TITLE)) + title = node.getProperty(Property.JCR_TITLE).getString() + " - " + + getBaseTitle(); + else + title = getBaseTitle(); + + HttpServletRequest request = UiContext.getHttpRequest(); + if (request == null) + return null; + // String url = CmsUtils.getCanonicalUrl(node, request); + // String desc = node.hasProperty(JCR_DESCRIPTION) ? node.getProperty( + // JCR_DESCRIPTION).getString() : null; + // String imgUrl = null; + // for (NodeIterator it = node.getNodes(); it.hasNext();) { + // Node child = it.nextNode(); + // if (child.isNodeType(CmsTypes.CMS_IMAGE)) + // imgUrl = CmsUtils.getDataUrl(child, request); + // } + + StringBuilder js = new StringBuilder(); + js.append("document.title = '" + title + "';"); + // js.append("var metas = document.getElementsByTagName('meta');"); + // js.append("for (var i=0; i