X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Fauth%2FUserAdminLoginModule.java;h=0f7f0bdeed37c6e489f67cd9a67bd4cd965d99aa;hb=ebd927da42511bb5959000c50a39974c6cfa5f49;hp=3dfbc0ddb194e94bc879d44ba380c6a3f3f4e05a;hpb=fd8f2c91e47d38445ba9702b40559939162f666d;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 3dfbc0ddb..0f7f0bdee 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java @@ -1,9 +1,15 @@ package org.argeo.cms.auth; import java.io.IOException; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; +import javax.naming.ldap.LdapName; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -11,39 +17,55 @@ import javax.security.auth.callback.LanguageCallback; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.kerberos.KerberosPrincipal; import javax.security.auth.login.CredentialNotFoundException; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; +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.eclipse.ui.specific.UiContext; +import org.argeo.naming.LdapAttrs; +import org.argeo.osgi.useradmin.IpaUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; -public class UserAdminLoginModule implements LoginModule, AuthConstants { +public class UserAdminLoginModule implements LoginModule { + private final static Log log = LogFactory.getLog(UserAdminLoginModule.class); + + private Subject subject; private CallbackHandler callbackHandler; private Map sharedState = null; - private boolean isAnonymous = false; + // private boolean isAnonymous = false; + private List indexedUserProperties = Arrays + .asList(new String[] { LdapAttrs.uid.name(), LdapAttrs.mail.name(), LdapAttrs.cn.name() }); + // private state private BundleContext bc; + // private Authorization authorization; + private User authenticatedUser = null; @SuppressWarnings("unchecked") @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { + this.subject = subject; try { bc = FrameworkUtil.getBundle(UserAdminLoginModule.class).getBundleContext(); assert bc != null; // this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = (Map) sharedState; - if (options.containsKey("anonymous")) - isAnonymous = Boolean.parseBoolean(options.get("anonymous").toString()); + // if (options.containsKey("anonymous")) + // isAnonymous = + // Boolean.parseBoolean(options.get("anonymous").toString()); } catch (Exception e) { throw new CmsException("Cannot initialize login module", e); } @@ -51,10 +73,31 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants { @Override public boolean login() throws LoginException { + Authorization sharedAuth = (Authorization) sharedState.get(CmsAuthUtils.SHARED_STATE_AUTHORIZATION); + if (sharedAuth != null) { + if (callbackHandler == null && sharedAuth.getName() != null) + throw new LoginException("Shared authorization should be anonymous"); + return false; + } UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class)); - Authorization authorization = null; - if (isAnonymous) { - authorization = userAdmin.getAuthorization(null); + if (callbackHandler == null) {// anonymous + // authorization = userAdmin.getAuthorization(null); + // sharedState.put(CmsAuthUtils.SHARED_STATE_AUTHORIZATION, + // authorization); + return true; + } + + final String username; + final char[] password; + if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME) + && sharedState.containsKey(CmsAuthUtils.SHARED_STATE_PWD)) { + username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME); + password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_PWD); + // // TODO locale? + // // NB: raw user name is used + // AuthenticatingUser authenticatingUser = new + // AuthenticatingUser(username, password); + // authorization = userAdmin.getAuthorization(authenticatingUser); } else { // ask for username and password NameCallback nameCallback = new NameCallback("User"); @@ -64,8 +107,6 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants { callbackHandler.handle(new Callback[] { nameCallback, passwordCallback, langCallback }); } catch (IOException e) { throw new LoginException("Cannot handle callback: " + e.getMessage()); -// } catch (ThreadDeath e) { -// throw new ThreadDeathLoginException("Callbackhandler thread died", e); } catch (UnsupportedCallbackException e) { return false; } @@ -76,54 +117,134 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants { locale = Locale.getDefault(); UiContext.setLocale(locale); - authorization = (Authorization) sharedState.get(SHARED_STATE_AUTHORIZATION); - - if (authorization == null) { - // create credentials - final String username = nameCallback.getName(); - if (username == null || username.trim().equals("")) { - // authorization = userAdmin.getAuthorization(null); - throw new CredentialNotFoundException("No credentials provided"); - } else { - char[] password = {}; - if (passwordCallback.getPassword() != null) - password = passwordCallback.getPassword(); - else - throw new CredentialNotFoundException("No credentials provided"); - - User user = userAdmin.getUser(null, username); - if (user == null) - throw new FailedLoginException("Invalid credentials"); - if (!user.hasCredential(null, password)) - throw new FailedLoginException("Invalid credentials"); - // return false; - - // Log and monitor new login - // if (log.isDebugEnabled()) - // log.debug("Logged in to CMS with username [" + username + - // "]"); - - authorization = userAdmin.getAuthorization(user); - } + username = nameCallback.getName(); + if (username == null || username.trim().equals("")) { + // authorization = userAdmin.getAuthorization(null); + throw new CredentialNotFoundException("No credentials provided"); } + if (passwordCallback.getPassword() != null) + password = passwordCallback.getPassword(); + else + throw new CredentialNotFoundException("No credentials provided"); + // FIXME move Argeo specific convention from user admin to here } - if (!sharedState.containsKey(SHARED_STATE_AUTHORIZATION)) - sharedState.put(SHARED_STATE_AUTHORIZATION, authorization); + + // User user = userAdmin.getUser(null, username); + User user = searchForUser(userAdmin, username); + if (user == null) + return true;// expect Kerberos + // throw new FailedLoginException("Invalid credentials"); + if (!user.hasCredential(null, password)) + throw new FailedLoginException("Invalid credentials"); + authenticatedUser = user; + // return false; + + // authorization = userAdmin.getAuthorization(user); + // assert authorization != null; + // + // sharedState.put(CmsAuthUtils.SHARED_STATE_AUTHORIZATION, + // authorization); return true; } @Override public boolean commit() throws LoginException { + // if (authorization == null) { + // return false; + // // throw new LoginException("Authorization should not be null"); + // } else { + // CmsAuthUtils.addAuthentication(subject, authorization); + // return true; + // } + UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class)); + Authorization authorization; + if (callbackHandler == null) {// anonymous + authorization = userAdmin.getAuthorization(null); + } else { + User authenticatingUser; + Set kerberosPrincipals = subject.getPrincipals(KerberosPrincipal.class); + if (kerberosPrincipals.isEmpty()) { + if (authenticatedUser == null) { + if(log.isTraceEnabled()) + log.trace("Neither kerberos nor user admin login succeeded. Login failed."); + return false; + } else { + authenticatingUser = authenticatedUser; + } + } else { + KerberosPrincipal kerberosPrincipal = kerberosPrincipals.iterator().next(); + LdapName dn = IpaUtils.kerberosToDn(kerberosPrincipal.getName()); + authenticatingUser = new AuthenticatingUser(dn); + if (authenticatedUser != null && !authenticatingUser.getName().equals(authenticatedUser.getName())) + throw new LoginException("Kerberos login " + authenticatingUser.getName() + + " is inconsistent with user admin login " + authenticatedUser.getName()); + } + authorization = Subject.doAs(subject, new PrivilegedAction() { + + @Override + public Authorization run() { + Authorization authorization = userAdmin.getAuthorization(authenticatingUser); + return authorization; + } + + }); + if (authorization == null) + throw new LoginException("User admin found no authorization for authenticated user "+authenticatingUser.getName()); + } + // Log and monitor new login + CmsAuthUtils.addAuthorization(subject, authorization, (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST)); +// HttpServletRequest request = (HttpServletRequest) sharedState.get(CmsAuthUtils.SHARED_STATE_HTTP_REQUEST); +// if (request != null) { +// CmsAuthUtils.registerSessionAuthorization(bc, request, subject, authorization); +// } + if (log.isDebugEnabled()) + log.debug("Logged in to CMS: " + subject); return true; } @Override public boolean abort() throws LoginException { + // authorization = null; return true; } @Override public boolean logout() throws LoginException { + if (log.isDebugEnabled()) + log.debug("Logging out from CMS... " + subject); + CmsAuthUtils.cleanUp(subject); return true; } + + protected User searchForUser(UserAdmin userAdmin, String providedUsername) { + try { + // TODO check value null or empty + List collectedUsers = new ArrayList(); + // try dn + User user = null; + try { + user = (User) userAdmin.getRole(providedUsername); + if (user != null) + collectedUsers.add(user); + } catch (Exception e) { + // silent + } + // try all indexes + for (String attr : indexedUserProperties) { + user = userAdmin.getUser(attr, providedUsername); + if (user != null) + collectedUsers.add(user); + } + if (collectedUsers.size() == 1) + return collectedUsers.get(0); + else if (collectedUsers.size() > 1) + log.warn(collectedUsers.size() + " users for provided username" + providedUsername); + return null; + } catch (Exception e) { + if (log.isTraceEnabled()) + log.warn("Cannot search for user " + providedUsername, e); + return null; + } + + } }