/*
* Copyright (C) 2003-2007 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.etk.core.security.jaas;
import java.util.Map;
import javax.security.auth.Subject;
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.LoginException;
import javax.security.auth.spi.LoginModule;
import org.etk.common.logging.Logger;
import org.etk.core.security.Authenticator;
import org.etk.core.security.Credential;
import org.etk.core.security.Identity;
import org.etk.core.security.IdentityRegistry;
import org.etk.core.security.PasswordCredential;
import org.etk.core.security.UsernameCredential;
import org.etk.kernel.container.KernelContainer;
import org.etk.kernel.container.KernelContainerContext;
import org.etk.kernel.container.RootContainer;
/**
* Created by The eXo Platform SAS .
*
* @author Gennady Azarenkov
* @version $Id: $
*/
public class DefaultLoginModule implements LoginModule {
/**
* The name of the option to use in order to specify the name of the portal
* container
*/
private static final String OPTION_PORTAL_CONTAINER_NAME = "portalContainerName";
/**
* The default name of the portal container
*/
private static final String DEFAULT_PORTAL_CONTAINER_NAME = "portal";
/**
* Logger.
*/
protected Logger log = Logger.getLogger(DefaultLoginModule.class);
/**
* @see {@link Subject} .
*/
protected Subject subject;
/**
* @see {@link CallbackHandler}
*/
private CallbackHandler callbackHandler;
/**
* encapsulates user's principals such as name, groups, etc .
*/
protected Identity identity;
/**
* Shared state.
*/
@SuppressWarnings("unchecked")
protected Map sharedState;
/**
* The name of the portal container.
*/
private String portalContainerName;
/**
* Is allowed for one user login again if he already login. If must set in LM
* options.
*/
protected boolean singleLogin = false;
/**
* Default constructor.
*/
public DefaultLoginModule() {
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map sharedState,
Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.portalContainerName = getPortalContainerName(options);
String sl = (String) options.get("singleLogin");
if (sl != null && (sl.equalsIgnoreCase("yes") || sl.equalsIgnoreCase("true"))) {
this.singleLogin = true;
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public boolean login() throws LoginException {
if (log.isDebugEnabled())
log.debug("In login of DefaultLoginModule.");
try {
if (sharedState.containsKey("exo.security.identity")) {
if (log.isDebugEnabled())
log.debug("Use Identity from previous LoginModule");
identity = (Identity) sharedState.get("exo.security.identity");
} else {
if (log.isDebugEnabled())
log.debug("Try create identity");
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("Username");
callbacks[1] = new PasswordCallback("Password", false);
callbackHandler.handle(callbacks);
String username = ((NameCallback) callbacks[0]).getName();
String password = new String(((PasswordCallback) callbacks[1]).getPassword());
((PasswordCallback) callbacks[1]).clearPassword();
if (username == null || password == null)
return false;
Authenticator authenticator = (Authenticator) getContainer().getComponentInstanceOfType(Authenticator.class);
if (authenticator == null)
throw new LoginException("No Authenticator component found, check your configuration");
Credential[] credentials = new Credential[] { new UsernameCredential(username),
new PasswordCredential(password) };
String userId = authenticator.validateUser(credentials);
identity = authenticator.createIdentity(userId);
sharedState.put("javax.security.auth.login.name", userId);
// TODO use PasswordCredential wrapper
subject.getPrivateCredentials().add(password);
subject.getPublicCredentials().add(new UsernameCredential(username));
}
return true;
} catch (final Throwable e) {
log.error(e.getLocalizedMessage());
throw new LoginException(e.getMessage());
}
}
/**
* {@inheritDoc}
*/
public boolean commit() throws LoginException {
try {
IdentityRegistry identityRegistry = (IdentityRegistry) getContainer().getComponentInstanceOfType(IdentityRegistry.class);
if (singleLogin && identityRegistry.getIdentity(identity.getUserId()) != null)
throw new LoginException("User " + identity.getUserId() + " already logined.");
identity.setSubject(subject);
identityRegistry.register(identity);
} catch (final Throwable e) {
log.error(e.getLocalizedMessage());
throw new LoginException(e.getMessage());
}
return true;
}
/**
* {@inheritDoc}
*/
public boolean abort() throws LoginException {
if (log.isDebugEnabled())
log.debug("In abort of DefaultLoginModule.");
return true;
}
/**
* {@inheritDoc}
*/
public boolean logout() throws LoginException {
if (log.isDebugEnabled())
log.debug("In logout of DefaultLoginModule.");
return true;
}
/**
* @return actual ExoContainer instance.
*/
protected KernelContainer getContainer() {
KernelContainer container = KernelContainerContext.getCurrentContainer();
if (container instanceof RootContainer) {
container = RootContainer.getInstance().getPortalContainer(portalContainerName);
}
return container;
}
/**
* Return portal container name if it provide with options,
* DEFAULT_PORTAL_CONTAINER_NAME otherwise.
*
* @param options
* @return
*/
@SuppressWarnings("unchecked")
private String getPortalContainerName(Map options) {
if (options != null) {
String optionValue = (String) options.get(OPTION_PORTAL_CONTAINER_NAME);
if (optionValue != null && optionValue.length() > 0) {
if (log.isDebugEnabled())
log.debug("The DefaultLoginModule will use the portal container " + optionValue);
return optionValue;
}
}
return DEFAULT_PORTAL_CONTAINER_NAME;
}
}