001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.auth.impl;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021:
022: import javax.servlet.ServletConfig;
023:
024: import org.apache.avalon.framework.CascadingRuntimeException;
025: import org.apache.avalon.framework.activity.Disposable;
026: import org.apache.avalon.framework.configuration.ConfigurationException;
027: import org.apache.avalon.framework.context.Context;
028: import org.apache.avalon.framework.context.ContextException;
029: import org.apache.avalon.framework.context.Contextualizable;
030: import org.apache.avalon.framework.logger.AbstractLogEnabled;
031: import org.apache.avalon.framework.service.ServiceException;
032: import org.apache.avalon.framework.service.ServiceManager;
033: import org.apache.avalon.framework.service.Serviceable;
034: import org.apache.avalon.framework.thread.ThreadSafe;
035: import org.apache.cocoon.components.ContextHelper;
036: import org.apache.cocoon.environment.ObjectModelHelper;
037: import org.apache.cocoon.environment.Request;
038: import org.apache.cocoon.environment.Session;
039: import org.apache.cocoon.servlet.CocoonServlet;
040: import org.apache.commons.lang.ObjectUtils;
041: import org.apache.cocoon.auth.Application;
042: import org.apache.cocoon.auth.ApplicationManager;
043: import org.apache.cocoon.auth.ApplicationUtil;
044: import org.apache.cocoon.auth.User;
045:
046: /**
047: * This is the default implementation of the
048: * {@link org.apache.cocoon.auth.ApplicationManager}.
049: *
050: * @version $Id: StandardApplicationManager.java 495912 2007-01-13 15:48:21Z cziegeler $
051: */
052: public class StandardApplicationManager extends AbstractLogEnabled
053: implements ApplicationManager, Contextualizable, Serviceable,
054: ThreadSafe, Disposable {
055:
056: /** The key used to store the login information in the session. */
057: protected static final String LOGIN_INFO_KEY = StandardApplicationManager.class
058: .getName()
059: + "/logininfo";
060:
061: /** The prefix used to store the application data object in the session. */
062: protected static final String APPLICATION_KEY_PREFIX = StandardApplicationManager.class
063: .getName()
064: + "/app:";
065:
066: /** The component context. */
067: protected Context context;
068:
069: /** The service manager. */
070: protected ServiceManager manager;
071:
072: /**
073: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
074: */
075: public void contextualize(final Context aContext)
076: throws ContextException {
077: this .context = aContext;
078: try {
079: ServletConfig config = (ServletConfig) this .context
080: .get(CocoonServlet.CONTEXT_SERVLET_CONFIG);
081: config.getServletContext().setAttribute(
082: StandardApplicationManager.class.getName(), this );
083: } catch (ContextException ignore) {
084: // we ignore this if we are not running inside a servlet environment
085: }
086: }
087:
088: /**
089: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
090: */
091: public void service(final ServiceManager aManager)
092: throws ServiceException {
093: this .manager = aManager;
094: }
095:
096: /**
097: * @see org.apache.avalon.framework.activity.Disposable#dispose()
098: */
099: public void dispose() {
100: this .manager = null;
101: }
102:
103: /**
104: * Get the application with the given name. This method tries to lookup the
105: * applicating using the current sitemap service manager.
106: * @param appName The name of the application.
107: * @return The application object.
108: * @throws Exception If the application can't be found.
109: */
110: protected Application getApplication(final String appName)
111: throws Exception {
112: final ServiceManager current = (ServiceManager) this .context
113: .get(ContextHelper.CONTEXT_SITEMAP_SERVICE_MANAGER);
114: Object o = current.lookup(Application.class.getName() + '/'
115: + appName);
116: if (o == null) {
117: throw new ConfigurationException("Application '" + appName
118: + "' not found.");
119: }
120: // to avoid messy release stuff later on, we just release the app now
121: // as an application is thread safe this isn't really a problem
122: current.release(o);
123: return (Application) o;
124: }
125:
126: /**
127: * @see org.apache.cocoon.auth.ApplicationManager#isLoggedIn(java.lang.String)
128: */
129: public boolean isLoggedIn(final String appName) {
130: Object appData = null;
131: final Map objectModel = ContextHelper
132: .getObjectModel(this .context);
133: final Request req = ObjectModelHelper.getRequest(objectModel);
134: final Session session = req.getSession(false);
135: if (session != null) {
136: appData = session.getAttribute(APPLICATION_KEY_PREFIX
137: + appName);
138:
139: // if the user is logged in, we set the current application, data and user
140: if (appData != null) {
141: try {
142: final Application application = this
143: .getApplication(appName);
144: final User user = (User) session.getAttribute(USER
145: + '-' + appName);
146: final Application oldApp = (Application) objectModel
147: .get(ApplicationManager.APPLICATION);
148: objectModel.put(ApplicationManager.APPLICATION,
149: application);
150: objectModel.put(
151: ApplicationManager.APPLICATION_DATA,
152: appData);
153: objectModel.put(ApplicationManager.USER, user);
154: // notify application
155: // The application is only notified once per request.
156: if (oldApp == null || !oldApp.equals(application)) {
157: application.userIsAccessing(user);
158: }
159: } catch (Exception ignore) {
160: throw new CascadingRuntimeException(
161: "Unable to get application '" + appName
162: + "'", ignore);
163: }
164: }
165: }
166:
167: return (appData != null);
168: }
169:
170: /**
171: * @see org.apache.cocoon.auth.ApplicationManager#login(java.lang.String, java.util.Map)
172: */
173: public User login(final String appName, final Map loginContext)
174: throws Exception {
175: User user = null;
176:
177: final Map objectModel = ContextHelper
178: .getObjectModel(this .context);
179:
180: // first check, if we are already logged in
181: if (this .isLoggedIn(appName)) {
182: user = ApplicationUtil.getUser(objectModel);
183: } else {
184: final Request req = ObjectModelHelper
185: .getRequest(objectModel);
186: Session session = req.getSession(false);
187:
188: final Application app = this .getApplication(appName);
189: LoginInfo info = null;
190: Map loginInfos = null;
191:
192: if (session != null) {
193: // is the user already logged in on the security handler?
194: loginInfos = (Map) session.getAttribute(LOGIN_INFO_KEY);
195: if (loginInfos != null
196: && loginInfos.containsKey(app
197: .getSecurityHandler().getId())) {
198: info = (LoginInfo) loginInfos.get(app
199: .getSecurityHandler().getId());
200: user = info.user;
201: }
202: }
203: if (user == null) {
204: user = app.getSecurityHandler().login(loginContext);
205: if (user != null) {
206: // create new login info
207: session = req.getSession();
208: loginInfos = (Map) session
209: .getAttribute(LOGIN_INFO_KEY);
210: if (loginInfos == null) {
211: loginInfos = new HashMap();
212: }
213: info = new LoginInfo(user);
214: loginInfos.put(app.getSecurityHandler().getId(),
215: info);
216: }
217: }
218:
219: // user can be null, if login failed
220: if (user != null) {
221: info.incUsageCounter(appName);
222: session.setAttribute(LOGIN_INFO_KEY, loginInfos);
223:
224: // set the user in the session
225: session.setAttribute(USER + '-' + appName, user);
226: objectModel.put(ApplicationManager.USER, user);
227:
228: // set the application in the object model
229: objectModel.put(ApplicationManager.APPLICATION, app);
230:
231: // notify the application
232: app.userDidLogin(user, loginContext);
233:
234: // set the application data in the session
235: Object data = ObjectUtils.NULL;
236: if (app.getApplicationStore() != null) {
237: data = app.getApplicationStore()
238: .loadApplicationData(user, app);
239: }
240: session.setAttribute(APPLICATION_KEY_PREFIX + appName,
241: data);
242: objectModel.put(ApplicationManager.APPLICATION_DATA,
243: data);
244: // notify application
245: app.userIsAccessing(user);
246: }
247: }
248:
249: return user;
250: }
251:
252: /**
253: * @see org.apache.cocoon.auth.ApplicationManager#logout(java.lang.String, java.util.Map)
254: */
255: public void logout(final String appName, final Map logoutContext) {
256: final Map objectModel = ContextHelper
257: .getObjectModel(this .context);
258: final Request req = ObjectModelHelper.getRequest(objectModel);
259: final Session session = req.getSession(false);
260: if (session != null) {
261: Application app;
262:
263: try {
264: app = this .getApplication(appName);
265: } catch (Exception ignore) {
266: throw new CascadingRuntimeException(
267: "Unable to get application '" + appName + "'",
268: ignore);
269: }
270:
271: // remove application data from session
272: session.removeAttribute(APPLICATION_KEY_PREFIX + appName);
273:
274: // remove application from object model
275: if (app.equals(ApplicationUtil.getApplication(objectModel))) {
276: objectModel.remove(ApplicationManager.APPLICATION);
277: objectModel.remove(ApplicationManager.APPLICATION_DATA);
278: objectModel.remove(ApplicationManager.USER);
279: }
280:
281: // remove user
282: session.removeAttribute(USER + '-' + appName);
283:
284: // decrement logininfo counter
285: final Map loginInfos = (Map) session
286: .getAttribute(LOGIN_INFO_KEY);
287: if (loginInfos != null) {
288: final LoginInfo info = (LoginInfo) loginInfos.get(app
289: .getSecurityHandler().getId());
290: if (info != null) {
291: // notify the application
292: app.userWillLogout(info.user, logoutContext);
293:
294: info.decUsageCounter(appName);
295: if (info.isUsed()) {
296: session
297: .setAttribute(LOGIN_INFO_KEY,
298: loginInfos);
299: } else {
300: // logout from security handler
301: app.getSecurityHandler().logout(logoutContext,
302: info.user);
303: // remove user info
304: loginInfos.remove(app.getSecurityHandler()
305: .getId());
306: if (loginInfos.size() > 0) {
307: session.setAttribute(LOGIN_INFO_KEY,
308: loginInfos);
309: } else {
310: session.removeAttribute(LOGIN_INFO_KEY);
311: // the user has left all applications, test the mode:
312: String mode = null;
313: if (logoutContext != null) {
314: mode = (String) logoutContext
315: .get(LOGOUT_CONTEXT_MODE_KEY);
316: }
317: if (mode == null
318: || mode
319: .equals(LOGOUT_MODE_TERMINATE_SESSION_IF_UNUSED)) {
320: session.invalidate();
321: }
322: }
323: }
324: }
325: }
326: }
327: }
328: }
|