package org.argeo.cms.ui;
+import static org.argeo.naming.SharedSecret.X_SHARED_SECRET;
+
+import java.io.IOException;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
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.http.HttpServletRequest;
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.auth.CurrentUser;
+import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
import org.argeo.eclipse.ui.specific.UiContext;
import org.argeo.jcr.JcrUtils;
-import org.argeo.node.NodeConstants;
-import org.argeo.node.security.NodeAuthenticated;
+import org.argeo.naming.AuthPassword;
+import org.argeo.naming.SharedSecret;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.application.AbstractEntryPoint;
import org.eclipse.rap.rwt.client.WebClient;
private Node node;
private String nodePath;// useful when changing auth
private String state;
- private String page;
private Throwable exception;
// Client services
// subject = new Subject();
// Initial login
+ LoginContext lc;
try {
- loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
new HttpRequestCallbackHandler(UiContext.getHttpRequest(), UiContext.getHttpResponse()));
- loginContext.login();
+ lc.login();
} catch (LoginException e) {
try {
- loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
- loginContext.login();
+ lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS);
+ lc.login();
} catch (LoginException e1) {
throw new CmsException("Cannot log in as anonymous", e1);
}
}
- authChange(loginContext);
+ authChange(lc);
jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
@Override
protected final void createContents(final Composite parent) {
- UiContext.setData(NodeAuthenticated.KEY, this);
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ UiContext.setData(CmsView.KEY, this);
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
* The node to return when no node was found (for authenticated users and
* anonymous)
*/
- protected Node getDefaultNode(Session session) throws RepositoryException {
- if (!session.hasPermission(defaultPath, "read")) {
- String userId = session.getUserID();
- if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
- // TODO throw a special exception
- throw new CmsException("Login required");
- else
- throw new CmsException("Unauthorized");
- }
- return session.getNode(defaultPath);
- }
+// private Node getDefaultNode(Session session) throws RepositoryException {
+// if (!session.hasPermission(defaultPath, "read")) {
+// String userId = session.getUserID();
+// if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
+// // TODO throw a special exception
+// throw new CmsException("Login required");
+// else
+// throw new CmsException("Unauthorized");
+// }
+// return session.getNode(defaultPath);
+// }
protected String getBaseTitle() {
return factoryProperties.get(WebClient.PAGE_TITLE);
// return subject;
// }
+ // @Override
+ // public LoginContext getLoginContext() {
+ // return loginContext;
+ // }
+ protected Subject getSubject() {
+ return loginContext.getSubject();
+ }
+
@Override
- public LoginContext getLoginContext() {
- return loginContext;
+ public boolean isAnonymous() {
+ return CurrentUser.isAnonymous(getSubject());
}
@Override
}
@Override
- public synchronized void authChange(LoginContext loginContext) {
- if (loginContext == null)
+ public synchronized void authChange(LoginContext lc) {
+ if (lc == null)
throw new CmsException("Login context cannot be null");
- this.loginContext = loginContext;
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ // logout previous login context
+ if (this.loginContext != null)
+ try {
+ this.loginContext.logout();
+ } catch (LoginException e1) {
+ log.warn("Could not log out: " + e1);
+ }
+ this.loginContext = lc;
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
@Override
public Void run() {
}
});
-
}
@Override
}
protected synchronized void doRefresh() {
- Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Void>() {
+ Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
@Override
public Void run() {
refresh();
protected synchronized String setState(String newState) {
String previousState = this.state;
- Node node = null;
- page = null;
+ String newNodePath = null;
+ String prefix = null;
this.state = newState;
if (newState.equals("~"))
this.state = "";
try {
int firstSlash = state.indexOf('/');
if (firstSlash == 0) {
- node = session.getNode(state);
- page = "";
+ newNodePath = state;
+ prefix = "";
} else if (firstSlash > 0) {
- String prefix = state.substring(0, firstSlash);
- String path = state.substring(firstSlash);
- if (session.nodeExists(path))
- node = session.getNode(path);
- else
- throw new CmsException("Data " + path + " does not exist");
- page = prefix;
+ prefix = state.substring(0, firstSlash);
+ newNodePath = state.substring(firstSlash);
} else {
- node = getDefaultNode(session);
- page = state;
+ newNodePath = defaultPath;
+ prefix = state;
+
+ }
+
+ // auth
+ int colonIndex = prefix.indexOf('$');
+ if (colonIndex > 0) {
+ SharedSecret token = new SharedSecret(new AuthPassword(X_SHARED_SECRET + '$' + prefix)) {
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ super.handle(callbacks);
+ // handle HTTP context
+ for (Callback callback : callbacks) {
+ if (callback instanceof HttpRequestCallback) {
+ ((HttpRequestCallback) callback).setRequest(UiContext.getHttpRequest());
+ ((HttpRequestCallback) callback).setResponse(UiContext.getHttpResponse());
+ }
+ }
+ }
+ };
+ LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, token);
+ lc.login();
+ authChange(lc);// sets the node as well
+ // } else {
+ // // TODO check consistency
+ // }
+ } else {
+ Node newNode = null;
+ if (session.nodeExists(newNodePath))
+ newNode = session.getNode(newNodePath);
+ else {
+// throw new CmsException("Data " + newNodePath + " does not exist");
+ newNode = null;
+ }
+ setNode(newNode);
}
- setNode(node);
- String title = publishMetaData(node);
+ String title = publishMetaData(getNode());
if (log.isTraceEnabled())
- log.trace("node=" + node + ", state=" + state + " (page=" + page + ")");
+ log.trace("node=" + newNodePath + ", state=" + state + " (prefix=" + prefix + ")");
return title;
} catch (Exception e) {
private String publishMetaData(Node node) throws RepositoryException {
// Title
String title;
- if (node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
+ if (node != null && node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
title = node.getProperty(Property.JCR_TITLE).getString() + " - " + getBaseTitle();
else
title = getBaseTitle();
return null;
StringBuilder js = new StringBuilder();
+ if (title == null)
+ title = "";
title = title.replace("'", "\\'");// sanitize
js.append("document.title = '" + title + "';");
jsExecutor.execute(js.toString());
@Override
public void navigated(BrowserNavigationEvent event) {
setState(event.getState());
- refresh();
+ doRefresh();
}
}
}
\ No newline at end of file