blob: 1b2a6550915a54a4654de65bc2fdc5cebce91130 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.auth.impl;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import org.apache.avalon.framework.CascadingRuntimeException;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.servlet.CocoonServlet;
import org.apache.commons.lang.ObjectUtils;
import org.apache.cocoon.auth.Application;
import org.apache.cocoon.auth.ApplicationManager;
import org.apache.cocoon.auth.ApplicationUtil;
import org.apache.cocoon.auth.User;
/**
* This is the default implementation of the
* {@link org.apache.cocoon.auth.ApplicationManager}.
*
* @version $Id$
*/
public class StandardApplicationManager
extends AbstractLogEnabled
implements ApplicationManager,
Contextualizable,
Serviceable,
ThreadSafe,
Disposable {
/** The key used to store the login information in the session. */
protected static final String LOGIN_INFO_KEY =
StandardApplicationManager.class.getName() + "/logininfo";
/** The prefix used to store the application data object in the session. */
protected static final String APPLICATION_KEY_PREFIX =
StandardApplicationManager.class.getName() + "/app:";
/** The component context. */
protected Context context;
/** The service manager. */
protected ServiceManager manager;
/**
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(final Context aContext) throws ContextException {
this.context = aContext;
try {
ServletConfig config =
(ServletConfig)this.context.get(CocoonServlet.CONTEXT_SERVLET_CONFIG);
config.getServletContext().setAttribute(StandardApplicationManager.class.getName(),
this);
} catch (ContextException ignore) {
// we ignore this if we are not running inside a servlet environment
}
}
/**
* @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
*/
public void service(final ServiceManager aManager) throws ServiceException {
this.manager = aManager;
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
this.manager = null;
}
/**
* Get the application with the given name. This method tries to lookup the
* applicating using the current sitemap service manager.
* @param appName The name of the application.
* @return The application object.
* @throws Exception If the application can't be found.
*/
protected Application getApplication(final String appName)
throws Exception {
final ServiceManager current = (ServiceManager)
this.context.get(ContextHelper.CONTEXT_SITEMAP_SERVICE_MANAGER);
Object o = current.lookup(Application.class.getName() + '/' + appName);
if ( o == null ) {
throw new ConfigurationException(
"Application '" + appName + "' not found."
);
}
// to avoid messy release stuff later on, we just release the app now
// as an application is thread safe this isn't really a problem
current.release(o);
return (Application)o;
}
/**
* @see org.apache.cocoon.auth.ApplicationManager#isLoggedIn(java.lang.String)
*/
public boolean isLoggedIn(final String appName) {
Object appData = null;
final Map objectModel = ContextHelper.getObjectModel( this.context );
final Request req = ObjectModelHelper.getRequest(objectModel);
final Session session = req.getSession(false);
if ( session != null ) {
appData = session.getAttribute(APPLICATION_KEY_PREFIX + appName);
// if the user is logged in, we set the current application, data and user
if ( appData != null ) {
try {
final Application application = this.getApplication(appName);
final User user = (User)session.getAttribute(USER + '-' + appName);
final Application oldApp = (Application)objectModel.get(ApplicationManager.APPLICATION);
objectModel.put(ApplicationManager.APPLICATION, application);
objectModel.put(ApplicationManager.APPLICATION_DATA, appData);
objectModel.put(ApplicationManager.USER, user);
// notify application
// The application is only notified once per request.
if ( oldApp == null || !oldApp.equals(application) ) {
application.userIsAccessing(user);
}
} catch (Exception ignore) {
throw new CascadingRuntimeException("Unable to get application '"
+ appName + "'", ignore);
}
}
}
return (appData != null);
}
/**
* @see org.apache.cocoon.auth.ApplicationManager#login(java.lang.String, java.util.Map)
*/
public User login(final String appName, final Map loginContext) throws Exception {
User user = null;
final Map objectModel = ContextHelper.getObjectModel( this.context );
// first check, if we are already logged in
if ( this.isLoggedIn(appName) ) {
user = ApplicationUtil.getUser(objectModel);
} else {
final Request req = ObjectModelHelper.getRequest(objectModel);
Session session = req.getSession(false);
final Application app = this.getApplication(appName);
LoginInfo info = null;
Map loginInfos = null;
if ( session != null ) {
// is the user already logged in on the security handler?
loginInfos = (Map)session.getAttribute(LOGIN_INFO_KEY);
if ( loginInfos != null
&& loginInfos.containsKey(app.getSecurityHandler().getId()) ) {
info = (LoginInfo)loginInfos.get(app.getSecurityHandler().getId());
user = info.user;
}
}
if ( user == null ) {
user = app.getSecurityHandler().login(loginContext);
if ( user != null ) {
// create new login info
session = req.getSession();
loginInfos = (Map)session.getAttribute(LOGIN_INFO_KEY);
if ( loginInfos == null ) {
loginInfos = new HashMap();
}
info = new LoginInfo(user);
loginInfos.put(app.getSecurityHandler().getId(), info);
}
}
// user can be null, if login failed
if ( user != null ) {
info.incUsageCounter(appName);
session.setAttribute(LOGIN_INFO_KEY, loginInfos);
// set the user in the session
session.setAttribute(USER + '-' + appName, user);
objectModel.put(ApplicationManager.USER, user);
// set the application in the object model
objectModel.put(ApplicationManager.APPLICATION, app);
// notify the application
app.userDidLogin(user, loginContext);
// set the application data in the session
Object data = ObjectUtils.NULL;
if ( app.getApplicationStore() != null ) {
data = app.getApplicationStore().loadApplicationData(user, app);
}
session.setAttribute(APPLICATION_KEY_PREFIX + appName, data);
objectModel.put(ApplicationManager.APPLICATION_DATA, data);
// notify application
app.userIsAccessing(user);
}
}
return user;
}
/**
* @see org.apache.cocoon.auth.ApplicationManager#logout(java.lang.String, java.util.Map)
*/
public void logout(final String appName, final Map logoutContext) {
final Map objectModel = ContextHelper.getObjectModel( this.context );
final Request req = ObjectModelHelper.getRequest(objectModel);
final Session session = req.getSession(false);
if ( session != null ) {
Application app;
try {
app = this.getApplication(appName);
} catch (Exception ignore) {
throw new CascadingRuntimeException("Unable to get application '"
+ appName + "'", ignore);
}
// remove application data from session
session.removeAttribute(APPLICATION_KEY_PREFIX + appName);
// remove application from object model
if ( app.equals( ApplicationUtil.getApplication(objectModel) ) ) {
objectModel.remove(ApplicationManager.APPLICATION);
objectModel.remove(ApplicationManager.APPLICATION_DATA);
objectModel.remove(ApplicationManager.USER);
}
// remove user
session.removeAttribute(USER + '-' + appName);
// decrement logininfo counter
final Map loginInfos = (Map)session.getAttribute(LOGIN_INFO_KEY);
if ( loginInfos != null ) {
final LoginInfo info = (LoginInfo)loginInfos.get(app.getSecurityHandler().getId());
if ( info != null ) {
// notify the application
app.userWillLogout(info.user, logoutContext);
info.decUsageCounter(appName);
if ( info.isUsed() ) {
session.setAttribute(LOGIN_INFO_KEY, loginInfos);
} else {
// logout from security handler
app.getSecurityHandler().logout(logoutContext, info.user);
// remove user info
loginInfos.remove(app.getSecurityHandler().getId());
if ( loginInfos.size() > 0 ) {
session.setAttribute(LOGIN_INFO_KEY, loginInfos);
} else {
session.removeAttribute(LOGIN_INFO_KEY);
// the user has left all applications, test the mode:
String mode = null;
if ( logoutContext != null ) {
mode = (String)logoutContext.get(LOGOUT_CONTEXT_MODE_KEY);
}
if ( mode == null
|| mode.equals(LOGOUT_MODE_TERMINATE_SESSION_IF_UNUSED) ) {
session.invalidate();
}
}
}
}
}
}
}
}