/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nuxeo - initial API and implementation * * $Id$ */ package org.eclipse.ecr.runtime.api.login; import java.io.Serializable; import java.security.AccessController; import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.AppConfigurationEntry; import javax.security.auth.login.Configuration; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.runtime.api.RuntimeInstanceIdentifier; import org.eclipse.ecr.runtime.model.ComponentContext; import org.eclipse.ecr.runtime.model.ComponentInstance; import org.eclipse.ecr.runtime.model.ComponentName; import org.eclipse.ecr.runtime.model.DefaultComponent; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> * @author <a href="mailto:td@nuxeo.com">Thierry Delprat</a> */ public class LoginComponent extends DefaultComponent implements LoginService { public static final ComponentName NAME = new ComponentName( "org.eclipse.ecr.runtime.LoginComponent"); public static final String SYSTEM_LOGIN = "nuxeo-system-login"; public static final String CLIENT_LOGIN = "nuxeo-client-login"; public static final String SYSTEM_USERNAME = "system"; protected static final String instanceId = RuntimeInstanceIdentifier.getId(); protected static final SystemLoginRestrictionManager systemLoginManager = new SystemLoginRestrictionManager(); protected static final Log log = LogFactory.getLog(LoginComponent.class); private LoginConfiguration config; private final Map<String, SecurityDomain> domains = new Hashtable<String, SecurityDomain>(); private SecurityDomain systemLogin; private SecurityDomain clientLogin; @Override public void activate(ComponentContext context) throws Exception { // setup the nuxeo login configuration Configuration parentConfig = null; try { parentConfig = Configuration.getConfiguration(); } catch (Exception e) { // do nothing - this can happen if default configuration provider // is not correctly configured // for examnple FileConfig fails if no config file was defined } config = new LoginConfiguration(this, parentConfig); Configuration.setConfiguration(config); } @Override public void deactivate(ComponentContext context) throws Exception { Configuration.setConfiguration(config.getParent()); config = null; } @Override public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if (extensionPoint.equals("domains")) { SecurityDomain domain = (SecurityDomain) contribution; addSecurityDomain(domain); } } @Override public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if (extensionPoint.equals("domains")) { SecurityDomain domain = (SecurityDomain) contribution; removeSecurityDomain(domain.getName()); } } public AppConfigurationEntry[] getAppConfigurationEntry(String name) { SecurityDomain domain = domains.get(name); if (domain != null) { return domain.getAppConfigurationEntries(); } return null; } @Override @SuppressWarnings("unchecked") public <T> T getAdapter(Class<T> adapter) { if (LoginService.class.isAssignableFrom(adapter)) { return (T) this; } return null; } @Override public SecurityDomain getSecurityDomain(String name) { return domains.get(name); } @Override public void addSecurityDomain(SecurityDomain domain) { domains.put(domain.getName(), domain); if (SYSTEM_LOGIN.equals(domain.getName())) { systemLogin = domain; } else if (CLIENT_LOGIN.equals(domain.getName())) { clientLogin = domain; } } @Override public void removeSecurityDomain(String name) { domains.remove(name); if (SYSTEM_LOGIN.equals(name)) { systemLogin = null; } else if (CLIENT_LOGIN.equals(name)) { clientLogin = null; } } @Override public SecurityDomain[] getSecurityDomains() { return domains.values().toArray(new SecurityDomain[domains.size()]); } @Override public void removeSecurityDomains() { domains.clear(); systemLogin = null; clientLogin = null; } private LoginContext systemLogin(String username) throws LoginException { if (systemLogin != null) { Set<Principal> principals = new HashSet<Principal>(); SystemID sysId = new SystemID(username); principals.add(sysId); Subject subject = new Subject(false, principals, new HashSet<String>(), new HashSet<String>()); return systemLogin.login(subject, new CredentialsCallbackHandler(sysId.getName(), sysId)); } return null; } @Override public LoginContext login() throws LoginException { return loginAs(null); } @Override public LoginContext loginAs(final String username) throws LoginException { // login as system user is a privileged action try { return AccessController.doPrivileged(new PrivilegedExceptionAction<LoginContext>() { @Override public LoginContext run() throws LoginException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new SystemLoginPermission()); } return systemLogin(username); } }); } catch (PrivilegedActionException e) { throw (LoginException) e.getException(); } } @Override public LoginContext login(String username, Object credentials) throws LoginException { if (clientLogin != null) { return clientLogin.login(username, credentials); } return null; } @Override public LoginContext login(CallbackHandler cbHandler) throws LoginException { if (clientLogin != null) { return clientLogin.login(cbHandler); } return null; } @Override public boolean isSystemId(Principal principal) { return isSystemLogin(principal); } public static boolean isSystemLogin(Object principal) { if (principal != null && principal.getClass() == SystemID.class) { if (!systemLoginManager.isRemoteSystemLoginRestricted()) { return true; } else { SystemID sys = (SystemID) principal; String sourceInstanceId = sys.getSourceInstanceId(); if (sourceInstanceId == null) { log.warn("Can not accept a system login without InstanceID of the source : System login is rejected"); return false; } else { if (sourceInstanceId.equals(instanceId)) { return true; } else { if (systemLoginManager.isRemoveSystemLoginAllowedForInstance(sourceInstanceId)) { if (log.isTraceEnabled()) { log.trace("Remote SystemLogin from instance " + sourceInstanceId + " accepted"); } return true; } else { log.warn("Remote SystemLogin attempt from instance " + sourceInstanceId + " was denied"); return false; } } } } } return false; } public static class SystemID implements Principal, Serializable { private static final long serialVersionUID = 2758247997191809993L; private final String userName; protected final String sourceInstanceId = instanceId; public SystemID() { userName = null; } public SystemID(String origUser) { userName = origUser == null ? SYSTEM_USERNAME : origUser; } @Override public String getName() { return userName; } public String getSourceInstanceId() { return sourceInstanceId; } @Override public boolean equals(Object other) { if (other instanceof Principal) { Principal oPal = (Principal) other; String oName = oPal.getName(); if (userName == null && oName != null) { return false; } else if (!userName.equals(oName)) { return false; } if (systemLoginManager.isRemoteSystemLoginRestricted() && (other instanceof LoginComponent.SystemID)) { // compare sourceInstanceId String oSysId = ((LoginComponent.SystemID) other).sourceInstanceId; if (sourceInstanceId == null) { return oSysId == null; } else { return sourceInstanceId.equals(oSysId); } } else { return true; } } return false; } @Override public int hashCode() { if (!systemLoginManager.isRemoteSystemLoginRestricted()) { return userName == null ? 0 : userName.hashCode(); } else { return userName == null ? 0 : userName.hashCode() + sourceInstanceId.hashCode(); } } } }