package org.argeo.cms.auth;
+import static org.argeo.naming.LdapAttrs.cn;
+import static org.argeo.naming.LdapAttrs.description;
+
import java.io.IOException;
import java.security.PrivilegedAction;
-import java.security.cert.X509Certificate;
+import java.time.Instant;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.kernel.Activator;
import org.argeo.naming.LdapAttrs;
+import org.argeo.naming.NamingUtils;
+import org.argeo.node.NodeConstants;
+import org.argeo.node.security.CryptoKeyring;
import org.argeo.osgi.useradmin.AuthenticatingUser;
import org.argeo.osgi.useradmin.IpaUtils;
import org.argeo.osgi.useradmin.OsUserUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.User;
import org.osgi.service.useradmin.UserAdmin;
@Override
public boolean login() throws LoginException {
- UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
+ UserAdmin userAdmin = Activator.getUserAdmin();
final String username;
final char[] password;
- X509Certificate[] certificateChain = null;
+ Object certificateChain = null;
if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME)
&& sharedState.containsKey(CmsAuthUtils.SHARED_STATE_PWD)) {
// NB: required by Basic http auth
// // TODO locale?
} else if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME)
&& sharedState.containsKey(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN)) {
- // NB: required by Basic http auth
- username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
- certificateChain = (X509Certificate[]) sharedState.get(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN);
+ String certificateName = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
+ LdapName ldapName;
+ try {
+ ldapName = new LdapName(certificateName);
+ } catch (InvalidNameException e) {
+ e.printStackTrace();
+ return false;
+ }
+ username = ldapName.getRdn(ldapName.size() - 1).getValue().toString();
+ certificateChain = sharedState.get(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN);
password = null;
} else if (singleUser) {
username = OsUserUtils.getOsUsername();
password = passwordCallback.getPassword();
else
throw new CredentialNotFoundException("No credentials provided");
+ sharedState.put(CmsAuthUtils.SHARED_STATE_NAME, username);
+ sharedState.put(CmsAuthUtils.SHARED_STATE_PWD, password);
}
User user = searchForUser(userAdmin, username);
+
+ // Tokens
+ if (user == null) {
+ String token = username;
+ Group tokenGroup = searchForToken(userAdmin, token);
+ if (tokenGroup != null) {
+ Authorization tokenAuthorization = getAuthorizationFromToken(userAdmin, tokenGroup);
+ if (tokenAuthorization != null) {
+ bindAuthorization = tokenAuthorization;
+ authenticatedUser = (User) userAdmin.getRole(bindAuthorization.getName());
+ return true;
+ }
+ }
+ }
+
if (user == null)
return true;// expect Kerberos
@Override
public boolean commit() throws LoginException {
+ if (locale == null)
+ subject.getPublicCredentials().add(Locale.getDefault());
+ else
+ subject.getPublicCredentials().add(locale);
+
if (singleUser) {
OsUserUtils.loginAsSystemUser(subject);
}
- UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
+ UserAdmin userAdmin = Activator.getUserAdmin();
Authorization authorization;
if (callbackHandler == null) {// anonymous
authorization = userAdmin.getAuthorization(null);
throw new LoginException(
"User admin found no authorization for authenticated user " + authenticatingUser.getName());
}
+
// Log and monitor new login
- CmsAuthUtils.addAuthorization(subject, authorization, locale,
- (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST));
+ HttpServletRequest request = (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST);
+ CmsAuthUtils.addAuthorization(subject, authorization, locale, request);
+
+ // Unlock keyring (underlying login to the JCR repository)
+ char[] password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_PWD);
+ if (password != null) {
+ ServiceReference<CryptoKeyring> keyringSr = bc.getServiceReference(CryptoKeyring.class);
+ if (keyringSr != null) {
+ CryptoKeyring keyring = bc.getService(keyringSr);
+ Subject.doAs(subject, new PrivilegedAction<Void>() {
+
+ @Override
+ public Void run() {
+ try {
+ keyring.unlock(password);
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.warn("Could not unlock keyring with the password provided by " + authorization.getName()
+ + ": " + e.getMessage());
+ }
+ return null;
+ }
+
+ });
+ }
+ }
+
+ // Register CmsSession with initial subject
+ CmsAuthUtils.registerSessionAuthorization(request, subject, authorization, locale);
+
if (log.isDebugEnabled())
log.debug("Logged in to CMS: " + subject);
return true;
}
}
+
+ protected Group searchForToken(UserAdmin userAdmin, String token) {
+ String dn = cn + "=" + token + "," + NodeConstants.TOKENS_BASEDN;
+ Group tokenGroup = (Group) userAdmin.getRole(dn);
+ return tokenGroup;
+ }
+
+ protected Authorization getAuthorizationFromToken(UserAdmin userAdmin, Group tokenGroup) {
+ String expiryDateStr = (String) tokenGroup.getProperties().get(description.name());
+ if (expiryDateStr != null) {
+ Instant expiryDate = NamingUtils.ldapDateToInstant(expiryDateStr);
+ if (expiryDate.isBefore(Instant.now())) {
+ if (log.isDebugEnabled())
+ log.debug("Token " + tokenGroup.getName() + " has expired.");
+ return null;
+ }
+ }
+ Authorization auth = userAdmin.getAuthorization(tokenGroup);
+ return auth;
+ }
}