X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Fauth%2FUserAdminLoginModule.java;h=4057b26af800e042d6fc1076ec89ad2f5ee7be63;hb=73a89e099608a51d9aef814a3f85a62947275f59;hp=ebe81b6714c49feffbcdae26aceb4b901c6b8a61;hpb=8fe4f3585ddeb9f3d044aa77de07b4fdc0151a3b;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java index ebe81b671..4057b26af 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java @@ -1,5 +1,7 @@ package org.argeo.cms.auth; +import static org.argeo.naming.LdapAttrs.cn; + import java.io.IOException; import java.security.PrivilegedAction; import java.util.Arrays; @@ -25,16 +27,26 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsException; +import org.argeo.api.NodeConstants; +import org.argeo.api.security.CryptoKeyring; +import org.argeo.cms.internal.kernel.Activator; import org.argeo.naming.LdapAttrs; import org.argeo.osgi.useradmin.AuthenticatingUser; import org.argeo.osgi.useradmin.IpaUtils; +import org.argeo.osgi.useradmin.OsUserUtils; +import org.argeo.osgi.useradmin.TokenUtils; 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; +/** + * Use the {@link UserAdmin} in the OSGi registry as the basis for + * authentication. + */ public class UserAdminLoginModule implements LoginModule { private final static Log log = LogFactory.getLog(UserAdminLoginModule.class); @@ -52,6 +64,8 @@ public class UserAdminLoginModule implements LoginModule { private Authorization bindAuthorization = null; + private boolean singleUser = Activator.isSingleUser(); + @SuppressWarnings("unchecked") @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, @@ -62,22 +76,50 @@ public class UserAdminLoginModule implements LoginModule { this.callbackHandler = callbackHandler; this.sharedState = (Map) sharedState; } catch (Exception e) { - throw new CmsException("Cannot initialize login module", e); + throw new IllegalStateException("Cannot initialize login module", e); } } @Override public boolean login() throws LoginException { - UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class)); + UserAdmin userAdmin = Activator.getUserAdmin(); final String username; final char[] password; + Object certificateChain = null; + boolean preauth = false; if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME) && sharedState.containsKey(CmsAuthUtils.SHARED_STATE_PWD)) { // NB: required by Basic http auth username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME); password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_PWD); // // TODO locale? + } else if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME) + && sharedState.containsKey(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN)) { + String certDn = (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(); + username = certDn; + certificateChain = sharedState.get(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN); + password = null; + } else if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME) + && sharedState.containsKey(CmsAuthUtils.SHARED_STATE_REMOTE_ADDR) + && sharedState.containsKey(CmsAuthUtils.SHARED_STATE_REMOTE_PORT)) {// ident + username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME); + password = null; + preauth = true; + } else if (singleUser) { + username = OsUserUtils.getOsUsername(); + password = null; + // TODO retrieve from http session + locale = Locale.getDefault(); } else { + // ask for username and password NameCallback nameCallback = new NameCallback("User"); PasswordCallback passwordCallback = new PasswordCallback("Password", false); @@ -95,7 +137,7 @@ public class UserAdminLoginModule implements LoginModule { if (locale == null) locale = Locale.getDefault(); // FIXME add it to Subject -// Locale.setDefault(locale); + // Locale.setDefault(locale); username = nameCallback.getName(); if (username == null || username.trim().equals("")) { @@ -106,38 +148,73 @@ public class UserAdminLoginModule implements LoginModule { 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 - - // try bind first - try { - AuthenticatingUser authenticatingUser = new AuthenticatingUser(user.getName(), password); - bindAuthorization = userAdmin.getAuthorization(authenticatingUser); - // TODO check tokens as well - if (bindAuthorization != null) { - authenticatedUser = user; - return true; + + if (password != null) { + // try bind first + try { + AuthenticatingUser authenticatingUser = new AuthenticatingUser(user.getName(), password); + bindAuthorization = userAdmin.getAuthorization(authenticatingUser); + // TODO check tokens as well + if (bindAuthorization != null) { + authenticatedUser = user; + return true; + } + } catch (Exception e) { + // silent + if (log.isTraceEnabled()) + log.trace("Bind failed", e); } - } catch (Exception e) { - // silent - if(log.isTraceEnabled()) - log.trace("Bind failed", e); - } - - // works only if a connection password is provided - if (!user.hasCredential(null, password)) { - return false; + + // works only if a connection password is provided + if (!user.hasCredential(null, password)) { + return false; + } + } else if (certificateChain != null) { + // TODO check CRLs/OSCP validity? + // NB: authorization in commit() will work only if an LDAP connection password + // is provided + } else if (singleUser) { + // TODO verify IP address? + } else if (preauth) { + // ident + } else { + throw new CredentialNotFoundException("No credentials provided"); } + authenticatedUser = user; return true; } @Override public boolean commit() throws LoginException { - UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class)); + if (locale != null) + subject.getPublicCredentials().add(locale); + + if (singleUser) { + OsUserUtils.loginAsSystemUser(subject); + } + UserAdmin userAdmin = Activator.getUserAdmin(); Authorization authorization; if (callbackHandler == null) {// anonymous authorization = userAdmin.getAuthorization(null); @@ -150,7 +227,7 @@ public class UserAdminLoginModule implements LoginModule { if (authenticatedUser == null) { if (log.isTraceEnabled()) log.trace("Neither kerberos nor user admin login succeeded. Login failed."); - return false; + throw new CredentialNotFoundException("Bad credentials."); } else { authenticatingUser = authenticatedUser; } @@ -175,9 +252,38 @@ public class UserAdminLoginModule implements LoginModule { 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); + + // Unlock keyring (underlying login to the JCR repository) + char[] password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_PWD); + if (password != null) { + ServiceReference keyringSr = bc.getServiceReference(CryptoKeyring.class); + if (keyringSr != null) { + CryptoKeyring keyring = bc.getService(keyringSr); + Subject.doAs(subject, new PrivilegedAction() { + + @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; @@ -192,8 +298,6 @@ public class UserAdminLoginModule implements LoginModule { public boolean logout() throws LoginException { if (log.isTraceEnabled()) log.trace("Logging out from CMS... " + subject); - // boolean httpSessionLogoutOk = CmsAuthUtils.logoutSession(bc, - // subject); CmsAuthUtils.cleanUp(subject); return true; } @@ -204,6 +308,7 @@ public class UserAdminLoginModule implements LoginModule { Set collectedUsers = new HashSet<>(); // try dn User user = null; + user = null; // try all indexes for (String attr : indexedUserProperties) { user = userAdmin.getUser(attr, providedUsername); @@ -232,4 +337,28 @@ public class UserAdminLoginModule implements LoginModule { } } + + 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) { + if (TokenUtils.isExpired(tokenGroup)) + return null; +// 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; +// } +// } + String userDn = TokenUtils.userDn(tokenGroup); + User user = (User) userAdmin.getRole(userDn); + Authorization auth = userAdmin.getAuthorization(user); + return auth; + } }