#argeo.node.useradmin.uris="dc=example,dc=com.ldif dc=example,dc=org.ldif"
-sun.security.krb5.debug=true
+#sun.security.krb5.debug=true
# HTTP
org.osgi.service.http.port=7070
bin.includes = META-INF/,\
.,\
icons/,\
- plugin.xml
\ No newline at end of file
+ plugin.xml
+additional.bundles = org.apache.commons.httpclient
* Connect to a remote repository and, if successful publish it as an OSGi
* service.
*/
-public class AddRemoteRepository extends AbstractHandler implements
- WorkbenchConstants, ArgeoNames {
+public class AddRemoteRepository extends AbstractHandler implements WorkbenchConstants, ArgeoNames {
private RepositoryFactory repositoryFactory;
private Repository nodeRepository;
private Keyring keyring;
public Object execute(ExecutionEvent event) throws ExecutionException {
- RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog(
- Display.getDefault().getActiveShell());
+ RemoteRepositoryLoginDialog dlg = new RemoteRepositoryLoginDialog(Display.getDefault().getActiveShell());
if (dlg.open() == Dialog.OK) {
CommandUtils.callCommand(Refresh.ID);
}
protected Control createDialogArea(Composite parent) {
Composite dialogarea = (Composite) super.createDialogArea(parent);
- dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
- true));
+ dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Composite composite = new Composite(dialogarea, SWT.NONE);
composite.setLayout(new GridLayout(2, false));
- composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
- false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
setMessage("Login to remote repository", IMessageProvider.NONE);
name = createLT(composite, "Name", "remoteRepository");
- uri = createLT(composite, "URI",
- "http://localhost:7070/jcr/node");
+ uri = createLT(composite, "URI", "http://localhost:7070/jcr/node");
username = createLT(composite, "User", "");
password = createLP(composite, "Password");
params.put(NodeConstants.LABELED_URI, checkedUriStr);
Repository repository = repositoryFactory.getRepository(params);
if (username.getText().trim().equals("")) {// anonymous
- session = repository.login();
+ // FIXME make it more generic
+ session = repository.login("main");
} else {
// FIXME use getTextChars() when upgrading to 3.7
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=297412
char[] pwd = password.getText().toCharArray();
- SimpleCredentials sc = new SimpleCredentials(
- username.getText(), pwd);
+ SimpleCredentials sc = new SimpleCredentials(username.getText(), pwd);
session = repository.login(sc, "main");
MessageDialog.openInformation(getParentShell(), "Success",
"Connection to '" + uri.getText() + "' successful");
}
} catch (Exception e) {
- ErrorFeedback.show(
- "Connection test failed for " + uri.getText(), e);
+ ErrorFeedback.show("Connection test failed for " + uri.getText(), e);
} finally {
JcrUtils.logoutQuietly(session);
}
nodeSession = nodeRepository.login();
Node home = NodeUtils.getUserHome(nodeSession);
- Node remote = home.hasNode(ARGEO_REMOTE) ? home
- .getNode(ARGEO_REMOTE) : home.addNode(ARGEO_REMOTE);
+ Node remote = home.hasNode(ARGEO_REMOTE) ? home.getNode(ARGEO_REMOTE) : home.addNode(ARGEO_REMOTE);
if (remote.hasNode(name.getText()))
- throw new EclipseUiException(
- "There is already a remote repository named "
- + name.getText());
- Node remoteRepository = remote.addNode(name.getText(),
- ArgeoTypes.ARGEO_REMOTE_REPOSITORY);
+ throw new EclipseUiException("There is already a remote repository named " + name.getText());
+ Node remoteRepository = remote.addNode(name.getText(), ArgeoTypes.ARGEO_REMOTE_REPOSITORY);
remoteRepository.setProperty(ARGEO_URI, uri.getText());
remoteRepository.setProperty(ARGEO_USER_ID, username.getText());
nodeSession.save();
if (saveInKeyring.getSelection()) {
- String pwdPath = remoteRepository.getPath() + '/'
- + ARGEO_PASSWORD;
+ String pwdPath = remoteRepository.getPath() + '/' + ARGEO_PASSWORD;
keyring.set(pwdPath, password.getText().toCharArray());
}
nodeSession.save();
- MessageDialog.openInformation(
- getParentShell(),
- "Repository Added",
- "Remote repository '" + username.getText() + "@"
- + uri.getText() + "' added");
+ MessageDialog.openInformation(getParentShell(), "Repository Added",
+ "Remote repository '" + username.getText() + "@" + uri.getText() + "' added");
super.okPressed();
} catch (Exception e) {
}
/** Creates label and check. */
- protected Button createLC(Composite parent, String label,
- Boolean initial) {
+ protected Button createLC(Composite parent, String label, Boolean initial) {
new Label(parent, SWT.NONE).setText(label);
Button check = new Button(parent, SWT.CHECK);
check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
protected Text createLP(Composite parent, String label) {
new Label(parent, SWT.NONE).setText(label);
- Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER
- | SWT.PASSWORD);
+ Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER | SWT.PASSWORD);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
return text;
}
private final RepositoryFactory repositoryFactory;
private final String uri;
- public RemoteRepositoryElem(String alias,
- RepositoryFactory repositoryFactory, String uri, TreeParent parent,
+ public RemoteRepositoryElem(String alias, RepositoryFactory repositoryFactory, String uri, TreeParent parent,
Session userSession, Keyring keyring, String remoteNodePath) {
super(alias, null, parent);
this.repositoryFactory = repositoryFactory;
}
@Override
- protected Session repositoryLogin(String workspaceName)
- throws RepositoryException {
+ protected Session repositoryLogin(String workspaceName) throws RepositoryException {
Node remoteRepository = userSession.getNode(remoteNodePath);
- String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID)
- .getString();
- String pwdPath = remoteRepository.getPath() + '/'
- + ArgeoNames.ARGEO_PASSWORD;
- char[] password = keyring.getAsChars(pwdPath);
-
- try {
- SimpleCredentials credentials = new SimpleCredentials(userID,
- password);
- return getRepository().login(credentials, workspaceName);
- } finally {
- Arrays.fill(password, 0, password.length, ' ');
+ String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID).getString();
+ if (userID.trim().equals("")) {
+ return getRepository().login(workspaceName);
+ } else {
+ String pwdPath = remoteRepository.getPath() + '/' + ArgeoNames.ARGEO_PASSWORD;
+ char[] password = keyring.getAsChars(pwdPath);
+ try {
+ SimpleCredentials credentials = new SimpleCredentials(userID, password);
+ return getRepository().login(credentials, workspaceName);
+ } finally {
+ Arrays.fill(password, 0, password.length, ' ');
+ }
}
}
@Override
public Repository getRepository() {
if (repository == null)
- repository = NodeUtils.getRepositoryByUri(repositoryFactory,
- uri);
+ repository = NodeUtils.getRepositoryByUri(repositoryFactory, uri);
return super.getRepository();
}
org.eclipse.equinox.http.jetty,\
org.springframework.context,\
org.springframework.core.io,\
+org.apache.commons.httpclient.cookie;resolution:=optional,\
*
Provide-Capability: cms.datamodel;name=cms;cnd=/org/argeo/cms/cms.cnd;abstract=true
\ No newline at end of file
return true;
}
+ public static <T extends Principal> T getSinglePrincipal(Subject subject, Class<T> clss) {
+ Set<T> principals = subject.getPrincipals(clss);
+ if (principals.isEmpty())
+ return null;
+ if (principals.size() > 1)
+ throw new IllegalStateException("Only one " + clss + " principal expected in " + subject);
+ return principals.iterator().next();
+ }
+
private CmsAuthUtils() {
}
package org.argeo.cms.auth;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.security.Principal;
import java.util.Map;
import java.util.Set;
+import javax.naming.ldap.LdapName;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.security.auth.x500.X500Principal;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.argeo.cms.internal.auth.ImpliedByPrincipal;
+import org.argeo.naming.LdapAttrs;
import org.argeo.node.NodeConstants;
import org.argeo.node.security.DataAdminPrincipal;
+import org.argeo.osgi.useradmin.IpaUtils;
public class SingleUserLoginModule implements LoginModule {
+ private final static Log log = LogFactory.getLog(SingleUserLoginModule.class);
+
private Subject subject;
+ private Map<String, Object> sharedState = null;
+ @SuppressWarnings("unchecked")
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
Map<String, ?> options) {
this.subject = subject;
+ this.sharedState = (Map<String, Object>) sharedState;
}
@Override
public boolean login() throws LoginException {
+ String username = System.getProperty("user.name");
+ if (!sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME))
+ sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, username);
return true;
}
@Override
public boolean commit() throws LoginException {
- String username = System.getProperty("user.name");
- X500Principal principal = new X500Principal("uid=" + username + ",dc=localhost,dc=localdomain");
+ X500Principal principal;
+ KerberosPrincipal kerberosPrincipal = CmsAuthUtils.getSinglePrincipal(subject, KerberosPrincipal.class);
+ if (kerberosPrincipal != null) {
+ LdapName userDn = IpaUtils.kerberosToDn(kerberosPrincipal.getName());
+ principal = new X500Principal(userDn.toString());
+ } else {
+ Object username = sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
+ if (username == null)
+ throw new LoginException("No username available");
+ String hostname;
+ try {
+ hostname = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ log.warn("Using localhost as hostname", e);
+ hostname = "localhost";
+ }
+ String baseDn = ("." + hostname).replaceAll("\\.", ",dc=");
+ principal = new X500Principal(LdapAttrs.uid + "=" + username + baseDn);
+ }
Set<Principal> principals = subject.getPrincipals();
principals.add(principal);
principals.add(new ImpliedByPrincipal(NodeConstants.ROLE_ADMIN, principal));
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
+/** SPNEGO login */
public class SpnegoLoginModule implements LoginModule {
private final static Log log = LogFactory.getLog(SpnegoLoginModule.class);
gssContext = checkToken(spnegoToken);
if (gssContext == null)
return false;
- try {
- String clientName = gssContext.getSrcName().toString();
- String role = clientName.substring(clientName.indexOf('@') + 1);
-
- log.debug("SpnegoUserRealm: established a security context");
- log.debug("Client Principal is: " + gssContext.getSrcName());
- log.debug("Server Principal is: " + gssContext.getTargName());
- log.debug("Client Default Role: " + role);
- } catch (GSSException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- // TODO log in
-
- return false;
+ else
+ return true;
+ // try {
+ // String clientName = gssContext.getSrcName().toString();
+ // String role = clientName.substring(clientName.indexOf('@') + 1);
+ //
+ // log.debug("SpnegoUserRealm: established a security context");
+ // log.debug("Client Principal is: " + gssContext.getSrcName());
+ // log.debug("Server Principal is: " + gssContext.getTargName());
+ // log.debug("Client Default Role: " + role);
+ // } catch (GSSException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
}
@Override
try {
Class<?> gssUtilsClass = Class.forName("com.sun.security.jgss.GSSUtil");
Method createSubjectMethod = gssUtilsClass.getMethod("createSubject", GSSName.class, GSSCredential.class);
- Subject gssSubject = (Subject) createSubjectMethod.invoke(null, gssContext.getSrcName(),
- gssContext.getDelegCred());
+ Subject gssSubject;
+ if (gssContext.getCredDelegState())
+ gssSubject = (Subject) createSubjectMethod.invoke(null, gssContext.getSrcName(),
+ gssContext.getDelegCred());
+ else
+ gssSubject = (Subject) createSubjectMethod.invoke(null, gssContext.getSrcName(), null);
subject.getPrincipals().addAll(gssSubject.getPrincipals());
subject.getPrivateCredentials().addAll(gssSubject.getPrivateCredentials());
return true;
} catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return false;
+ throw new LoginException("Cannot commit SPNEGO " + e);
}
}
@Override
public boolean abort() throws LoginException {
- // TODO Auto-generated method stub
- return false;
+ if (gssContext != null) {
+ try {
+ gssContext.dispose();
+ } catch (GSSException e) {
+ if (log.isTraceEnabled())
+ log.warn("Could not abort", e);
+ }
+ gssContext = null;
+ }
+ return true;
}
@Override
public boolean logout() throws LoginException {
- // TODO Auto-generated method stub
- return false;
+ if (gssContext != null) {
+ try {
+ gssContext.dispose();
+ } catch (GSSException e) {
+ if (log.isTraceEnabled())
+ log.warn("Could not abort", e);
+ }
+ gssContext = null;
+ }
+ return true;
}
private GSSContext checkToken(byte[] authToken) {
@Override
public synchronized Session getDataSession(String cn, String workspace, Repository repository) {
+ // FIXME make it more robust
+ if (workspace == null)
+ workspace = "main";
String path = cn + '/' + workspace;
if (dataSessionsInUse.contains(path)) {
try {
}
public String toString() {
- return "CMS Session #" + localSessionId;
+ return "CMS Session local=" + localSessionId + ", uuid=" + uuid;
}
public static CmsSession getByLocalId(String localId) {
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.apache.jackrabbit.server.SessionProvider;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CmsSession;
class CmsSessionProvider implements SessionProvider, Serializable {
private static final long serialVersionUID = -1358136599534938466L;
- // private final static Log log =
- // LogFactory.getLog(CmsSessionProvider.class);
+ private final static Log log = LogFactory.getLog(CmsSessionProvider.class);
private final String alias;
CmsSession cmsSession = WebCmsSessionImpl.getCmsSession(request);
if (cmsSession == null)
return anonymousSession(request, rep, workspace);
+ if (log.isTraceEnabled()) {
+ log.debug("Get JCR session from " + cmsSession);
+ }
Session session = cmsSession.getDataSession(alias, workspace, rep);
cmsSessions.put(session, cmsSession);
return session;
import java.io.IOException;
import java.net.URL;
-import java.util.StringTokenizer;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.auth.HttpRequestCallbackHandler;
import org.argeo.node.NodeConstants;
-import org.ietf.jgss.GSSContext;
-import org.ietf.jgss.GSSCredential;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSManager;
-import org.ietf.jgss.GSSName;
-import org.ietf.jgss.Oid;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.http.HttpContext;
private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
// FIXME Make it more unique
- private String httpAuthRealm = "Argeo";
+ private final String httpAuthRealm;
+ private final boolean forceBasic;
+
+ public DataHttpContext(String httpAuthrealm, boolean forceBasic) {
+ this.httpAuthRealm = httpAuthrealm;
+ this.forceBasic = forceBasic;
+ }
+
+ public DataHttpContext(String httpAuthrealm) {
+ this(httpAuthrealm, false);
+ }
@Override
public boolean handleSecurity(final HttpServletRequest request, HttpServletResponse response) throws IOException {
lc.login();
// return true;
} catch (LoginException e) {
- CallbackHandler token = extractHttpAuth(request, response);
- if (token != null) {
- try {
- lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, token);
- lc.login();
- } catch (LoginException e1) {
- throw new CmsException("Could not login", e1);
- }
- } else {
- lc = processUnauthorized(request, response);
- if (lc == null)
- return false;
- }
+ // CallbackHandler token = extractHttpAuth(request, response);
+ // String token = request.getHeader(HttpUtils.HEADER_AUTHORIZATION);
+ // if (token != null) {
+ // try {
+ // lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER);
+ // lc.login();
+ // } catch (LoginException e1) {
+ // throw new CmsException("Could not login", e1);
+ // }
+ // } else {
+ lc = processUnauthorized(request, response);
+ if (lc == null)
+ return false;
+ // }
}
+
+ // still required by open session in view
+ // TODO remove it
request.setAttribute(NodeConstants.LOGIN_CONTEXT_USER, lc);
return true;
}
}
}
- protected CallbackHandler extractHttpAuth(final HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
- String authHeader = httpRequest.getHeader(HttpUtils.HEADER_AUTHORIZATION);
- if (authHeader != null) {
- StringTokenizer st = new StringTokenizer(authHeader);
- if (st.hasMoreTokens()) {
- String basic = st.nextToken();
- if (basic.equalsIgnoreCase("Basic")) {
- try {
- // TODO manipulate char[]
- String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
- // log.debug("Credentials: " + credentials);
- int p = credentials.indexOf(":");
- if (p != -1) {
- final String login = credentials.substring(0, p).trim();
- final char[] password = credentials.substring(p + 1).trim().toCharArray();
- return new CallbackHandler() {
- public void handle(Callback[] callbacks) {
- for (Callback cb : callbacks) {
- if (cb instanceof NameCallback)
- ((NameCallback) cb).setName(login);
- else if (cb instanceof PasswordCallback)
- ((PasswordCallback) cb).setPassword(password);
- else if (cb instanceof HttpRequestCallback) {
- ((HttpRequestCallback) cb).setRequest(httpRequest);
- ((HttpRequestCallback) cb).setResponse(httpResponse);
- }
- }
- }
- };
- } else {
- throw new CmsException("Invalid authentication token");
- }
- } catch (Exception e) {
- throw new CmsException("Couldn't retrieve authentication", e);
- }
- } else if (basic.equalsIgnoreCase("Negotiate")) {
- // FIXME generalise
- String _targetName = "HTTP/mostar.desktop.argeo.pro";
- String spnegoToken = st.nextToken();
- byte[] authToken = Base64.decodeBase64(spnegoToken);
- GSSManager manager = GSSManager.getInstance();
- try {
- Oid krb5Oid = new Oid("1.3.6.1.5.5.2"); // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
- GSSName gssName = manager.createName(_targetName, null);
- GSSCredential serverCreds = manager.createCredential(gssName, GSSCredential.INDEFINITE_LIFETIME,
- krb5Oid, GSSCredential.ACCEPT_ONLY);
- GSSContext gContext = manager.createContext(serverCreds);
-
- if (gContext == null) {
- log.debug("SpnegoUserRealm: failed to establish GSSContext");
- } else {
- while (!gContext.isEstablished()) {
- byte[] outToken = gContext.acceptSecContext(authToken, 0, authToken.length);
- String outTokenStr = Base64.encodeBase64String(outToken);
- httpResponse.setHeader("WWW-Authenticate", "Negotiate " + outTokenStr);
- }
- if (gContext.isEstablished()) {
- String clientName = gContext.getSrcName().toString();
- String role = clientName.substring(clientName.indexOf('@') + 1);
-
- log.debug("SpnegoUserRealm: established a security context");
- log.debug("Client Principal is: " + gContext.getSrcName());
- log.debug("Server Principal is: " + gContext.getTargName());
- log.debug("Client Default Role: " + role);
-
- // TODO log in
- }
- }
-
- } catch (GSSException gsse) {
- log.warn(gsse, gsse);
- }
-
- }
- }
- }
- return null;
- }
+ // protected CallbackHandler extractHttpAuth(final HttpServletRequest
+ // httpRequest, HttpServletResponse httpResponse) {
+ // String authHeader =
+ // httpRequest.getHeader(HttpUtils.HEADER_AUTHORIZATION);
+ // if (authHeader != null) {
+ // StringTokenizer st = new StringTokenizer(authHeader);
+ // if (st.hasMoreTokens()) {
+ // String basic = st.nextToken();
+ // if (basic.equalsIgnoreCase("Basic")) {
+ // try {
+ // // TODO manipulate char[]
+ // String credentials = new String(Base64.decodeBase64(st.nextToken()),
+ // "UTF-8");
+ // // log.debug("Credentials: " + credentials);
+ // int p = credentials.indexOf(":");
+ // if (p != -1) {
+ // final String login = credentials.substring(0, p).trim();
+ // final char[] password = credentials.substring(p +
+ // 1).trim().toCharArray();
+ // return new CallbackHandler() {
+ // public void handle(Callback[] callbacks) {
+ // for (Callback cb : callbacks) {
+ // if (cb instanceof NameCallback)
+ // ((NameCallback) cb).setName(login);
+ // else if (cb instanceof PasswordCallback)
+ // ((PasswordCallback) cb).setPassword(password);
+ // else if (cb instanceof HttpRequestCallback) {
+ // ((HttpRequestCallback) cb).setRequest(httpRequest);
+ // ((HttpRequestCallback) cb).setResponse(httpResponse);
+ // }
+ // }
+ // }
+ // };
+ // } else {
+ // throw new CmsException("Invalid authentication token");
+ // }
+ // } catch (Exception e) {
+ // throw new CmsException("Couldn't retrieve authentication", e);
+ // }
+ // } else if (basic.equalsIgnoreCase("Negotiate")) {
+ // // FIXME generalise
+ // String _targetName;
+ // try {
+ // _targetName = NodeHttp.DEFAULT_SERVICE + "@"
+ // + InetAddress.getLocalHost().getCanonicalHostName();
+ // } catch (UnknownHostException e) {
+ // throw new CmsException("Cannot determins target name", e);
+ // }
+ // String spnegoToken = st.nextToken();
+ // byte[] authToken = Base64.decodeBase64(spnegoToken);
+ // GSSManager manager = GSSManager.getInstance();
+ // try {
+ //// Oid krb5Oid = new Oid("1.3.6.1.5.5.2"); //
+ // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
+ //// GSSName gssName = manager.createName(_targetName,
+ // GSSName.NT_HOSTBASED_SERVICE, krb5Oid);
+ //// GSSCredential serverCreds = manager.createCredential(gssName,
+ // GSSCredential.INDEFINITE_LIFETIME,
+ //// krb5Oid, GSSCredential.ACCEPT_ONLY);
+ // GSSCredential serverCreds = Activator.getAcceptorCredentials();
+ // if(serverCreds==null)
+ // throw new CmsException("No GSS server credentials available");
+ // GSSContext gContext = manager.createContext(serverCreds);
+ //
+ // if (gContext == null) {
+ // log.debug("SpnegoUserRealm: failed to establish GSSContext");
+ // } else {
+ // while (!gContext.isEstablished()) {
+ // byte[] outToken = gContext.acceptSecContext(authToken, 0,
+ // authToken.length);
+ // String outTokenStr = Base64.encodeBase64String(outToken);
+ // httpResponse.setHeader("WWW-Authenticate", "Negotiate " + outTokenStr);
+ // }
+ // if (gContext.isEstablished()) {
+ // String clientName = gContext.getSrcName().toString();
+ // String role = clientName.substring(clientName.indexOf('@') + 1);
+ //
+ // log.debug("SpnegoUserRealm: established a security context");
+ // log.debug("Client Principal is: " + gContext.getSrcName());
+ // log.debug("Server Principal is: " + gContext.getTargName());
+ // log.debug("Client Default Role: " + role);
+ //
+ // // TODO log in
+ // }
+ // }
+ //
+ // } catch (GSSException gsse) {
+ // log.warn(gsse, gsse);
+ // }
+ //
+ // }
+ // }
+ // }
+ // return null;
+ // }
protected void askForWwwAuth(HttpServletRequest request, HttpServletResponse response) {
response.setStatus(401);
- response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic realm=\"" + httpAuthRealm + "\"");
+ // response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "basic
+ // realm=\"" + httpAuthRealm + "\"");
+ if (org.argeo.cms.internal.kernel.Activator.getAcceptorCredentials() != null && !forceBasic)// SPNEGO
+ response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Negotiate");
+ else
+ response.setHeader(HttpUtils.HEADER_WWW_AUTHENTICATE, "Basic realm=\"" + httpAuthRealm + "\"");
- // SPNEGO
- // response.setHeader(HEADER_WWW_AUTHENTICATE, "Negotiate");
// response.setDateHeader("Date", System.currentTimeMillis());
// response.setDateHeader("Expires", System.currentTimeMillis() + (24 *
// 60 * 60 * 1000));
public class NodeHttp implements KernelConstants {
private final static Log log = LogFactory.getLog(NodeHttp.class);
- // Filters
- // private final RootFilter rootFilter;
-
- // private final DoSFilter dosFilter;
- // private final QoSFilter qosFilter;
+ public final static String DEFAULT_SERVICE = "HTTP";
private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
private ServiceTracker<Repository, Repository> repositories;
private final ServiceTracker<HttpService, HttpService> httpServiceTracker;
- public NodeHttp() {
- // rootFilter = new RootFilter();
- // dosFilter = new CustomDosFilter();
- // qosFilter = new QoSFilter();
+ private String httpRealm = "Argeo";
+ public NodeHttp() {
httpServiceTracker = new PrepareHttpStc();
httpServiceTracker.open();
}
- // class CustomDosFilter extends DoSFilter {
- // @Override
- // protected String extractUserId(ServletRequest request) {
- // HttpSession httpSession = ((HttpServletRequest) request)
- // .getSession();
- // if (isSessionAuthenticated(httpSession)) {
- // String userId = ((SecurityContext) httpSession
- // .getAttribute(SPRING_SECURITY_CONTEXT_KEY))
- // .getAuthentication().getName();
- // return userId;
- // }
- // return super.extractUserId(request);
- //
- // }
- // }
-
public void destroy() {
repositories.close();
}
Properties ip = new Properties();
ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, HttpUtils.WEBDAV_CONFIG);
ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
- httpService.registerServlet(path, webdavServlet, ip, new DataHttpContext());
+ httpService.registerServlet(path, webdavServlet, ip, new DataHttpContext(httpRealm));
}
void registerFilesServlet(HttpService httpService, String alias, Repository repository)
Properties ip = new Properties();
ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, HttpUtils.WEBDAV_CONFIG);
ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
- httpService.registerServlet(path, filesServlet, ip, new PrivateHttpContext());
+ httpService.registerServlet(path, filesServlet, ip, new PrivateHttpContext(httpRealm, true));
}
void registerRemotingServlet(HttpService httpService, String alias, Repository repository)
String path = remotingPath(alias);
Properties ip = new Properties();
ip.setProperty(JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
+ ip.setProperty(JcrRemotingServlet.INIT_PARAM_AUTHENTICATE_HEADER, "Negotiate");
// Looks like a bug in Jackrabbit remoting init
Path tmpDir;
ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting_" + alias);
ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, HttpUtils.DEFAULT_PROTECTED_HANDLERS);
ip.setProperty(RemotingServlet.INIT_PARAM_CREATE_ABSOLUTE_URI, "false");
- httpService.registerServlet(path, remotingServlet, ip, new PrivateHttpContext());
+ httpService.registerServlet(path, remotingServlet, ip, new PrivateHttpContext(httpRealm));
}
private String webdavPath(String alias) {
}
private class RemotingServlet extends JcrRemotingServlet {
+ private final Log log = LogFactory.getLog(RemotingServlet.class);
private static final long serialVersionUID = 4605238259548058883L;
private final Repository repository;
private final SessionProvider sessionProvider;
// Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
// @Override
// public Void run() throws Exception {
+ if (log.isTraceEnabled())
+ HttpUtils.logRequest(log, request);
RemotingServlet.super.service(request, response);
// return null;
// }
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+/** Requests authorisation */
class PrivateHttpContext extends DataHttpContext {
+ public PrivateHttpContext(String httpAuthrealm, boolean forceBasic) {
+ super(httpAuthrealm, forceBasic);
+ }
+
+ public PrivateHttpContext(String httpAuthrealm) {
+ super(httpAuthrealm);
+ }
+
@Override
protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
askForWwwAuth(request, response);
--- /dev/null
+package org.argeo.cms.internal.http.client;
+
+import java.net.URL;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Base64;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.auth.AuthPolicy;
+import org.apache.commons.httpclient.auth.AuthScheme;
+import org.apache.commons.httpclient.auth.AuthenticationException;
+import org.apache.commons.httpclient.auth.CredentialsProvider;
+import org.apache.commons.httpclient.auth.MalformedChallengeException;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.params.DefaultHttpParams;
+import org.apache.commons.httpclient.params.HttpParams;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+/** Implementation of the SPNEGO auth scheme. */
+public class SpnegoAuthScheme implements AuthScheme {
+ private final static Log log = LogFactory.getLog(SpnegoAuthScheme.class);
+
+ public static final String NAME = "Negotiate";
+ private final static Oid KERBEROS_OID;
+ static {
+ try {
+ KERBEROS_OID = new Oid("1.3.6.1.5.5.2");
+ } catch (GSSException e) {
+ throw new IllegalStateException("Cannot create Kerberos OID", e);
+ }
+ }
+
+ private boolean complete = false;
+ private String realm;
+
+ @Override
+ public void processChallenge(String challenge) throws MalformedChallengeException {
+ log.debug("processChallenge " + challenge);
+
+ }
+
+ @Override
+ public String getSchemeName() {
+ return NAME;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ log.debug("getParameter " + name);
+ return null;
+ }
+
+ @Override
+ public String getRealm() {
+ return realm;
+ }
+
+ @Override
+ public String getID() {
+ return NAME;
+ }
+
+ @Override
+ public boolean isConnectionBased() {
+ return true;
+ }
+
+ @Override
+ public boolean isComplete() {
+ log.debug("isComplete");
+ return complete;
+ }
+
+ @Override
+ public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
+ log.debug("authenticate " + method + " " + uri);
+ return null;
+ }
+
+ @Override
+ public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
+ log.debug("authenticate " + method);
+ GSSContext context = null;
+ String tokenStr = null;
+ String hostname;
+ try {
+ hostname = method.getURI().getHost();
+ } catch (URIException e1) {
+ throw new IllegalStateException("Cannot authenticate", e1);
+ }
+ String serverPrinc = "HTTP@" + hostname;
+
+ try {
+ // Get service's principal name
+ GSSManager manager = GSSManager.getInstance();
+ GSSName serverName = manager.createName(serverPrinc, GSSName.NT_HOSTBASED_SERVICE, KERBEROS_OID);
+
+ // Get the context for authentication
+ context = manager.createContext(serverName, KERBEROS_OID, null, GSSContext.DEFAULT_LIFETIME);
+ // context.requestMutualAuth(true); // Request mutual authentication
+ // context.requestConf(true); // Request confidentiality
+ context.requestCredDeleg(true);
+
+ byte[] token = new byte[0];
+
+ // token is ignored on the first call
+ token = context.initSecContext(token, 0, token.length);
+
+ // Send a token to the server if one was generated by
+ // initSecContext
+ if (token != null) {
+ tokenStr = Base64.getEncoder().encodeToString(token);
+ // complete=true;
+ }
+ return "Negotiate " + tokenStr;
+ } catch (GSSException e) {
+ throw new AuthenticationException("Cannot authenticate to " + serverPrinc, e);
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ System.err.println("usage: java " + SpnegoAuthScheme.class.getName() + " <url>");
+ System.exit(1);
+ return;
+ }
+ String url = args[0];
+
+ URL jaasUrl = SpnegoAuthScheme.class.getResource("jaas.cfg");
+ System.setProperty("java.security.auth.login.config", jaasUrl.toExternalForm());
+ try {
+ LoginContext lc = new LoginContext("SINGLE_USER");
+ lc.login();
+
+ AuthPolicy.registerAuthScheme(SpnegoAuthScheme.NAME, SpnegoAuthScheme.class);
+ HttpParams params = DefaultHttpParams.getDefaultParams();
+ ArrayList<String> schemes = new ArrayList<>();
+ schemes.add(SpnegoAuthScheme.NAME);
+ params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, schemes);
+ params.setParameter(CredentialsProvider.PROVIDER, new SpnegoCredentialProvider());
+
+ int responseCode = Subject.doAs(lc.getSubject(), new PrivilegedExceptionAction<Integer>() {
+ public Integer run() throws Exception {
+ HttpClient httpClient = new HttpClient();
+ return httpClient.executeMethod(new GetMethod(url));
+ }
+ });
+ System.out.println("Reponse code: " + responseCode);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.cms.internal.http.client;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.auth.AuthScheme;
+import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
+import org.apache.commons.httpclient.auth.CredentialsProvider;
+
+/** SPNEGO credential provider */
+public class SpnegoCredentialProvider implements CredentialsProvider {
+
+ @Override
+ public Credentials getCredentials(AuthScheme scheme, String host, int port, boolean proxy)
+ throws CredentialsNotAvailableException {
+ return new Credentials() {
+ };
+ }
+
+}
--- /dev/null
+SINGLE_USER {
+ com.sun.security.auth.module.Krb5LoginModule optional
+ principal="${user.name}"
+ useTicketCache=true;
+};
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
import java.util.Iterator;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
+import org.apache.commons.httpclient.auth.AuthPolicy;
+import org.apache.commons.httpclient.auth.CredentialsProvider;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
+import org.apache.commons.httpclient.params.DefaultHttpParams;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.commons.httpclient.params.HttpParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.http.NodeHttp;
+import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
+import org.argeo.cms.internal.http.client.SpnegoCredentialProvider;
import org.argeo.naming.DnsBrowser;
import org.argeo.node.NodeConstants;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.Oid;
/** Low-level kernel security */
-class CmsSecurity implements KernelConstants {
+public class CmsSecurity implements KernelConstants {
private final static Log log = LogFactory.getLog(CmsSecurity.class);
// http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html
- private final static Oid KERBEROS_OID;
+ public final static Oid KERBEROS_OID;
static {
try {
KERBEROS_OID = new Oid("1.3.6.1.5.5.2");
private Path nodeKeyTab = KernelUtils.getOsgiInstancePath(KernelConstants.NODE_KEY_TAB_PATH);
- public CmsSecurity() {
+ CmsSecurity() {
+ // Register client-side SPNEGO auth scheme
+ AuthPolicy.registerAuthScheme(SpnegoAuthScheme.NAME, SpnegoAuthScheme.class);
+ HttpParams params = DefaultHttpParams.getDefaultParams();
+ ArrayList<String> schemes = new ArrayList<>();
+ schemes.add(SpnegoAuthScheme.NAME);
+ params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, schemes);
+ params.setParameter(CredentialsProvider.PROVIDER, new SpnegoCredentialProvider());
+ params.setParameter(HttpMethodParams.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
+// params.setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
+
if (!DeployConfig.isInitialized()) // first init
FirstInit.prepareInstanceArea();
res = DEPLOYED;
} else {
res = STANDALONE;
- kerberosDomain = null;
+ // kerberosDomain = null;
// FIXME make state more robust
}
} catch (UnknownHostException e) {
CallbackHandler callbackHandler;
if (Files.exists(nodeKeyTab)) {
- service = NodeConstants.NODE_SERVICE;
+ service = NodeHttp.DEFAULT_SERVICE;
+ // service = NodeConstants.NODE_SERVICE;
callbackHandler = new CallbackHandler() {
@Override
// throw new CmsException("Cannot create text callback handler", e);
// }
try {
- LoginContext kernelLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_SINGLE_USER, nodeSubject);
+ LoginContext kernelLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_NODE, nodeSubject);
kernelLc.login();
} catch (LoginException e) {
throw new CmsException("Cannot log in kernel", e);
SINGLE_USER {
com.sun.security.auth.module.Krb5LoginModule optional
+ principal="${user.name}"
storeKey=true
+ useTicketCache=true
debug=true;
org.argeo.cms.auth.SingleUserLoginModule requisite;
};
};
SINGLE_USER {
- com.sun.security.auth.module.UnixLoginModule requisite;
+ com.sun.security.auth.module.Krb5LoginModule optional
+ principal="${user.name}"
+ storeKey=true
+ useTicketCache=true
+ debug=true;
org.argeo.cms.auth.SingleUserLoginModule requisite;
};
throw new UserDirectoryException("Unsupported LDAP type for " + name);
return res;
} catch (NamingException e) {
- log.error("Cannot get role: " + e.getMessage());
+ log.error("Cannot get role: " + name, e);
return null;
}
}