001: /**
002: * Copyright (c) 2003-2007, David A. Czarnecki
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * Redistributions of source code must retain the above copyright notice, this list of conditions and the
009: * following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
011: * following disclaimer in the documentation and/or other materials provided with the distribution.
012: * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
013: * endorse or promote products derived from this software without specific prior written permission.
014: * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
015: * without prior written permission of David A. Czarnecki.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
018: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
019: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
021: * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
022: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
025: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
029: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030: */package org.blojsom.plugin.admin;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.blojsom.authorization.AuthorizationException;
035: import org.blojsom.authorization.AuthorizationProvider;
036: import org.blojsom.blog.Blog;
037: import org.blojsom.blog.Entry;
038: import org.blojsom.plugin.Plugin;
039: import org.blojsom.plugin.PluginException;
040: import org.blojsom.plugin.permission.PermissionChecker;
041: import org.blojsom.util.BlojsomConstants;
042: import org.blojsom.util.BlojsomUtils;
043: import org.blojsom.util.resources.ResourceManager;
044:
045: import javax.servlet.ServletConfig;
046: import javax.servlet.http.HttpServletRequest;
047: import javax.servlet.http.HttpServletResponse;
048: import javax.servlet.http.HttpSession;
049: import java.io.IOException;
050: import java.util.HashMap;
051: import java.util.Locale;
052: import java.util.Map;
053:
054: /**
055: * BaseAdminPlugin
056: *
057: * @author David Czarnecki
058: * @version $Id: BaseAdminPlugin.java,v 1.4 2007/01/17 02:35:04 czarneckid Exp $
059: * @since blojsom 3.0
060: */
061: public class BaseAdminPlugin implements Plugin, PermissionedPlugin {
062:
063: protected static final Log _logger = LogFactory
064: .getLog(BaseAdminPlugin.class);
065:
066: // Constants
067: protected static final String BLOJSOM_ADMIN_PLUGIN_AUTHENTICATED_KEY = "org.blojsom.plugin.admin.Authenticated";
068: protected static final String BLOJSOM_ADMIN_PLUGIN_USERNAME_KEY = "org.blojsom.plugin.admin.Username";
069: protected static final String BLOJSOM_ADMIN_PLUGIN_USERNAME = "BLOJSOM_ADMIN_PLUGIN_USERNAME";
070: protected static final String BLOJSOM_ADMIN_PLUGIN_USERNAME_PARAM = "username";
071: protected static final String BLOJSOM_ADMIN_PLUGIN_PASSWORD_PARAM = "password";
072: protected static final String ACTION_PARAM = "action";
073: protected static final String SUBACTION_PARAM = "subaction";
074: protected static final String BLOJSOM_ADMIN_PLUGIN_OPERATION_RESULT = "BLOJSOM_ADMIN_PLUGIN_OPERATION_RESULT";
075: protected static final String BLOJSOM_USER_AUTHENTICATED = "BLOJSOM_USER_AUTHENTICATED";
076: protected static final String BLOJSOM_ADMIN_MESSAGES_RESOURCE = "org.blojsom.plugin.admin.resources.messages";
077: protected static final String BLOJSOM_PERMISSION_CHECKER = "BLOJSOM_PERMISSION_CHECKER";
078: protected static final String PLUGIN_ADMIN_INHERIT_APACHE_CREDENTIALS = "plugin-admin-inherit-apache-credentials";
079:
080: // Localization constants
081: protected static final String LOGIN_ERROR_TEXT_KEY = "login.error.text";
082:
083: // Pages
084: protected static final String ADMIN_ADMINISTRATION_PAGE = "/org/blojsom/plugin/admin/templates/admin";
085: protected static final String ADMIN_LOGIN_PAGE = "/org/blojsom/plugin/admin/templates/admin-login";
086: protected static final String ADMIN_AJAX_RESPONSE = "/org/blojsom/plugin/admin/templates/admin-ajax-response";
087:
088: // Actions
089: protected static final String LOGIN_ACTION = "login";
090: protected static final String LOGOUT_ACTION = "logout";
091: protected static final String PAGE_ACTION = "page";
092:
093: protected ServletConfig _servletConfig;
094: protected AuthorizationProvider _authorizationProvider;
095: protected ResourceManager _resourceManager;
096: protected Map _ignoreParams;
097:
098: /**
099: * Default constructor.
100: */
101: public BaseAdminPlugin() {
102: }
103:
104: /**
105: * Set the {@link ServletConfig} for the fetcher to grab initialization parameters
106: *
107: * @param servletConfig {@link ServletConfig}
108: */
109: public void setServletConfig(ServletConfig servletConfig) {
110: _servletConfig = servletConfig;
111: }
112:
113: /**
114: * Set the authorization provider for use by this plugin
115: *
116: * @param authorizationProvider {@link AuthorizationProvider}
117: */
118: public void setAuthorizationProvider(
119: AuthorizationProvider authorizationProvider) {
120: _authorizationProvider = authorizationProvider;
121: }
122:
123: /**
124: * Set the resource manager for use by this plugin
125: *
126: * @param resourceManager {@link ResourceManager}
127: */
128: public void setResourceManager(ResourceManager resourceManager) {
129: _resourceManager = resourceManager;
130: }
131:
132: /**
133: * Initialize this plugin. This method only called when the plugin is instantiated.
134: *
135: * @throws PluginException If there is an error initializing the plugin
136: */
137: public void init() throws PluginException {
138: _ignoreParams = new HashMap();
139: _ignoreParams.put(BLOJSOM_ADMIN_PLUGIN_USERNAME_PARAM,
140: BLOJSOM_ADMIN_PLUGIN_USERNAME_PARAM);
141: _ignoreParams.put(BLOJSOM_ADMIN_PLUGIN_PASSWORD_PARAM,
142: BLOJSOM_ADMIN_PLUGIN_PASSWORD_PARAM);
143: _ignoreParams.put("submit", "submit");
144: _ignoreParams.put("reset", "reset");
145: }
146:
147: /**
148: * Authenticate the user if their authentication session variable is not present
149: *
150: * @param httpServletRequest Request
151: * @param httpServletResponse Response
152: * @param context Context
153: * @param blog {@link Blog} information
154: * @return <code>true</code> if the user is authenticated, <code>false</code> otherwise
155: */
156: protected boolean authenticateUser(
157: HttpServletRequest httpServletRequest,
158: HttpServletResponse httpServletResponse, Map context,
159: Blog blog) {
160: BlojsomUtils.setNoCacheControlHeaders(httpServletResponse);
161: HttpSession httpSession = httpServletRequest.getSession();
162: boolean logout = false;
163:
164: // Check first to see if someone has requested to logout
165: String action = BlojsomUtils.getRequestValue(ACTION_PARAM,
166: httpServletRequest);
167: if (action != null && LOGOUT_ACTION.equals(action)) {
168: httpSession.removeAttribute(blog.getBlogAdminURL() + "_"
169: + BLOJSOM_ADMIN_PLUGIN_AUTHENTICATED_KEY);
170: httpSession.removeAttribute(BLOJSOM_USER_AUTHENTICATED);
171: httpSession
172: .removeAttribute(BlojsomConstants.REDIRECT_TO_PARAM);
173: logout = true;
174: }
175:
176: StringBuffer redirectURL = new StringBuffer();
177: redirectURL.append(httpServletRequest.getRequestURI());
178: if (!redirectURL.toString().endsWith("/")) {
179: redirectURL.append("/");
180: }
181: if (httpServletRequest.getParameterMap().size() > 0) {
182: redirectURL.append("?");
183: redirectURL.append(BlojsomUtils.convertRequestParams(
184: httpServletRequest, _ignoreParams));
185: }
186:
187: if (Boolean
188: .valueOf(
189: blog
190: .getProperty(PLUGIN_ADMIN_INHERIT_APACHE_CREDENTIALS))
191: .booleanValue()
192: && !BlojsomUtils.checkNullOrBlank(httpServletRequest
193: .getRemoteUser())) {
194: String remoteUsername = httpServletRequest.getRemoteUser();
195: _logger.debug("Retrieved remote_user from server: "
196: + remoteUsername);
197:
198: httpSession.setAttribute(blog.getBlogAdminURL() + "_"
199: + BLOJSOM_ADMIN_PLUGIN_AUTHENTICATED_KEY,
200: Boolean.TRUE);
201: httpSession
202: .setAttribute(blog.getBlogAdminURL() + "_"
203: + BLOJSOM_ADMIN_PLUGIN_USERNAME_KEY,
204: remoteUsername);
205: httpSession.setAttribute(BLOJSOM_ADMIN_PLUGIN_USERNAME,
206: remoteUsername);
207: httpSession.setAttribute(BLOJSOM_USER_AUTHENTICATED,
208: Boolean.TRUE);
209: _logger
210: .debug("Passed remote_user authentication for username: "
211: + remoteUsername);
212: }
213:
214: // Otherwise, check for the authenticated key and if not authenticated, look for a "username" and "password" parameter
215: if (httpSession.getAttribute(blog.getBlogAdminURL() + "_"
216: + BLOJSOM_ADMIN_PLUGIN_AUTHENTICATED_KEY) == null) {
217: String username = httpServletRequest
218: .getParameter(BLOJSOM_ADMIN_PLUGIN_USERNAME_PARAM);
219: String password = httpServletRequest
220: .getParameter(BLOJSOM_ADMIN_PLUGIN_PASSWORD_PARAM);
221:
222: if (username == null || password == null
223: || "".equals(username) || "".equals(password)) {
224: _logger
225: .debug("No username/password provided or username/password was empty");
226: _logger.debug("Setting redirect_to attribute to: "
227: + redirectURL.toString());
228: if (!logout) {
229: httpServletRequest.getSession().setAttribute(
230: BlojsomConstants.REDIRECT_TO_PARAM,
231: redirectURL.toString());
232: }
233:
234: return false;
235: }
236:
237: // Check the username and password against the blog authorization
238: try {
239: _authorizationProvider.authorize(blog, null, username,
240: password);
241: httpSession.setAttribute(blog.getBlogAdminURL() + "_"
242: + BLOJSOM_ADMIN_PLUGIN_AUTHENTICATED_KEY,
243: Boolean.TRUE);
244: httpSession.setAttribute(blog.getBlogAdminURL() + "_"
245: + BLOJSOM_ADMIN_PLUGIN_USERNAME_KEY, username);
246: httpSession.setAttribute(BLOJSOM_ADMIN_PLUGIN_USERNAME,
247: username);
248: httpSession.setAttribute(BLOJSOM_USER_AUTHENTICATED,
249: Boolean.TRUE);
250: _logger.debug("Passed authentication for username: "
251: + username);
252:
253: return true;
254: } catch (AuthorizationException e) {
255: _logger.debug("Failed authentication for username: "
256: + username);
257: addOperationResultMessage(context, formatAdminResource(
258: LOGIN_ERROR_TEXT_KEY, LOGIN_ERROR_TEXT_KEY,
259: blog.getBlogAdministrationLocale(),
260: new Object[] { username }));
261: _logger.debug("Setting redirect_to attribute to: "
262: + redirectURL.toString());
263: if (!logout) {
264: httpServletRequest.getSession().setAttribute(
265: BlojsomConstants.REDIRECT_TO_PARAM,
266: redirectURL.toString());
267: }
268:
269: return false;
270: }
271: } else {
272: context.put(BLOJSOM_PERMISSION_CHECKER,
273: new PermissionChecker(blog, _authorizationProvider,
274: context));
275:
276: return ((Boolean) httpSession.getAttribute(blog
277: .getBlogAdminURL()
278: + "_" + BLOJSOM_ADMIN_PLUGIN_AUTHENTICATED_KEY))
279: .booleanValue();
280: }
281: }
282:
283: /**
284: * Retrieve the current authorized username for this session
285: *
286: * @param httpServletRequest Request
287: * @param blog {@link Blog}
288: * @return Authorized username for this session or <code>null</code> if no user is currently authorized
289: */
290: protected String getUsernameFromSession(
291: HttpServletRequest httpServletRequest, Blog blog) {
292: return (String) httpServletRequest.getSession().getAttribute(
293: blog.getBlogAdminURL() + "_"
294: + BLOJSOM_ADMIN_PLUGIN_USERNAME_KEY);
295: }
296:
297: /**
298: * Check the permission for a given username and permission
299: *
300: * @param blog {@link Blog} information
301: * @param permissionContext {@link java.util.Map} containing context information for checking permission
302: * @param username Username
303: * @param permission Permission
304: * @return <code>true</code> if the username has the required permission, <code>false</code> otherwise
305: */
306: public boolean checkPermission(Blog blog, Map permissionContext,
307: String username, String permission) {
308: try {
309: _authorizationProvider.checkPermission(blog,
310: permissionContext, username, permission);
311: } catch (AuthorizationException e) {
312: _logger.error(e);
313: return false;
314: }
315:
316: return true;
317: }
318:
319: /**
320: * Adds a message to the context under the <code>BLOJSOM_ADMIN_PLUGIN_OPERATION_RESULT</code> key
321: *
322: * @param context Context
323: * @param message Message to add
324: */
325: protected void addOperationResultMessage(Map context, String message) {
326: context.put(BLOJSOM_ADMIN_PLUGIN_OPERATION_RESULT, message);
327: }
328:
329: /**
330: * Retrieve a resource from the administration resource bundle
331: *
332: * @param resourceID ID of resource to retrieve
333: * @param fallbackText Text to use as fallback if resource ID is not found
334: * @param locale {@link Locale} to use when retrieving resource
335: * @return Text from administration resource bundle given by <code>resourceID</code> or <code>fallbackText</code> if the resource ID is not found
336: */
337: protected String getAdminResource(String resourceID,
338: String fallbackText, Locale locale) {
339: return _resourceManager.getString(resourceID,
340: BLOJSOM_ADMIN_MESSAGES_RESOURCE, fallbackText, locale);
341: }
342:
343: /**
344: * Retrieve a resource from the administration resource bundle and pass it through the {@link ResourceManager#format(String, Object[])} method
345: *
346: * @param resourceID ID of resource to retrieve
347: * @param fallbackText Text to use as fallback if resource ID is not found
348: * @param locale {@link Locale} to use when retrieving resource
349: * @param arguments Arguments for {@link ResourceManager#format(String, Object[])}
350: * @return Text from administration resource bundle given by <code>resourceID</code> formatted appropriately or <code>fallbackText</code> if the resource ID could not be formatted
351: */
352: protected String formatAdminResource(String resourceID,
353: String fallbackText, Locale locale, Object[] arguments) {
354: String resourceText = getAdminResource(resourceID,
355: fallbackText, locale);
356:
357: String formattedText = _resourceManager.format(resourceText,
358: arguments);
359: if (formattedText == null) {
360: formattedText = fallbackText;
361: }
362:
363: return formattedText;
364: }
365:
366: /**
367: * Process the blog entries
368: *
369: * @param httpServletRequest Request
370: * @param httpServletResponse Response
371: * @param blog {@link Blog} instance
372: * @param context Context
373: * @param entries Blog entries retrieved for the particular request
374: * @return Modified set of blog entries
375: * @throws PluginException If there is an error processing the blog entries
376: */
377: public Entry[] process(HttpServletRequest httpServletRequest,
378: HttpServletResponse httpServletResponse, Blog blog,
379: Map context, Entry[] entries) throws PluginException {
380: if (!authenticateUser(httpServletRequest, httpServletResponse,
381: context, blog)) {
382: httpServletRequest.setAttribute(
383: BlojsomConstants.PAGE_PARAM, ADMIN_LOGIN_PAGE);
384: } else {
385: String page = BlojsomUtils.getRequestValue(
386: BlojsomConstants.PAGE_PARAM, httpServletRequest);
387: if (!BlojsomUtils.checkNullOrBlank(page)) {
388: httpServletRequest.setAttribute(
389: BlojsomConstants.PAGE_PARAM, page);
390: } else {
391: httpServletRequest.setAttribute(
392: BlojsomConstants.PAGE_PARAM,
393: ADMIN_ADMINISTRATION_PAGE);
394: }
395:
396: if (httpServletRequest.getSession().getAttribute(
397: BlojsomConstants.REDIRECT_TO_PARAM) != null) {
398: String redirectURL = (String) httpServletRequest
399: .getSession().getAttribute(
400: BlojsomConstants.REDIRECT_TO_PARAM);
401:
402: try {
403: httpServletRequest.getSession().removeAttribute(
404: BlojsomConstants.REDIRECT_TO_PARAM);
405: httpServletResponse.sendRedirect(redirectURL);
406: } catch (IOException e) {
407: _logger.error(e);
408: }
409: }
410: }
411:
412: return entries;
413: }
414:
415: /**
416: * Perform any cleanup for the plugin. Called after {@link #process}.
417: *
418: * @throws PluginException If there is an error performing cleanup for this plugin
419: */
420: public void cleanup() throws PluginException {
421: }
422:
423: /**
424: * Called when BlojsomServlet is taken out of service
425: *
426: * @throws PluginException If there is an error in finalizing this plugin
427: */
428: public void destroy() throws PluginException {
429: }
430: }
|