001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki;
021:
022: import java.io.IOException;
023: import java.security.Permission;
024: import java.security.Principal;
025: import java.text.MessageFormat;
026: import java.util.*;
027:
028: import javax.servlet.http.HttpServletRequest;
029: import javax.servlet.http.HttpServletResponse;
030: import javax.servlet.http.HttpSession;
031: import javax.servlet.jsp.PageContext;
032:
033: import org.apache.log4j.Logger;
034:
035: import com.ecyrd.jspwiki.auth.*;
036: import com.ecyrd.jspwiki.auth.permissions.AllPermission;
037: import com.ecyrd.jspwiki.auth.user.UserDatabase;
038: import com.ecyrd.jspwiki.i18n.InternationalizationManager;
039: import com.ecyrd.jspwiki.tags.WikiTagBase;
040: import com.ecyrd.jspwiki.ui.*;
041:
042: /**
043: * <p>Provides state information throughout the processing of a page. A
044: * WikiContext is born when the JSP pages that are the main entry
045: * points, are invoked. The JSPWiki engine creates the new
046: * WikiContext, which basically holds information about the page, the
047: * handling engine, and in which context (view, edit, etc) the
048: * call was done.</p>
049: * <p>A WikiContext also provides request-specific variables, which can
050: * be used to communicate between plugins on the same page, or
051: * between different instances of the same plugin. A WikiContext
052: * variable is valid until the processing of the page has ended. For
053: * an example, please see the Counter plugin.</p>
054: * <p>When a WikiContext is created, it automatically associates a
055: * {@link WikiSession} object with the user's HttpSession. The
056: * WikiSession contains information about the user's authentication
057: * status, and is consulted by {@link #getCurrentUser()}.
058: * object</p>
059: * <p>Do not cache the page object that you get from the WikiContext; always
060: * use getPage()!</p>
061: *
062: * @see com.ecyrd.jspwiki.plugin.Counter
063: *
064: * @author Janne Jalkanen
065: * @author Andrew R. Jaquith
066: */
067: public class WikiContext implements Cloneable, Command {
068: private Command m_command = null;
069:
070: private WikiPage m_page;
071: private WikiPage m_realPage;
072: private WikiEngine m_engine;
073: private String m_template = "default";
074:
075: private Map m_variableMap = new HashMap();
076:
077: /**
078: * Stores the HttpServletRequest. May be null, if the request did not
079: * come from a servlet.
080: */
081: protected HttpServletRequest m_request = null;
082:
083: private WikiSession m_session = null;
084:
085: /** User is administering JSPWiki (Install, SecurityConfig). */
086: public static final String INSTALL = WikiCommand.INSTALL
087: .getRequestContext();
088:
089: /** The VIEW context - the user just wants to view the page
090: contents. */
091: public static final String VIEW = PageCommand.VIEW
092: .getRequestContext();
093:
094: /** User wants to view or administer workflows. */
095: public static final String WORKFLOW = WikiCommand.WORKFLOW
096: .getRequestContext();
097:
098: /** The EDIT context - the user is editing the page. */
099: public static final String EDIT = PageCommand.EDIT
100: .getRequestContext();
101:
102: /** User is preparing for a login/authentication. */
103: public static final String LOGIN = WikiCommand.LOGIN
104: .getRequestContext();
105:
106: /** User is preparing to log out. */
107: public static final String LOGOUT = WikiCommand.LOGOUT
108: .getRequestContext();
109:
110: /** JSPWiki wants to display a message. */
111: public static final String MESSAGE = WikiCommand.MESSAGE
112: .getRequestContext();
113:
114: /** User is viewing a DIFF between the two versions of the page. */
115: public static final String DIFF = PageCommand.DIFF
116: .getRequestContext();
117:
118: /** User is viewing page history. */
119: public static final String INFO = PageCommand.INFO
120: .getRequestContext();
121:
122: /** User is previewing the changes he just made. */
123: public static final String PREVIEW = PageCommand.PREVIEW
124: .getRequestContext();
125:
126: /** User has an internal conflict, and does quite not know what to
127: do. Please provide some counseling. */
128: public static final String CONFLICT = PageCommand.CONFLICT
129: .getRequestContext();
130:
131: /** An error has been encountered and the user needs to be informed. */
132: public static final String ERROR = WikiCommand.ERROR
133: .getRequestContext();
134:
135: /** User is uploading something. */
136: public static final String UPLOAD = PageCommand.UPLOAD
137: .getRequestContext();
138:
139: /** User is commenting something. */
140: public static final String COMMENT = PageCommand.COMMENT
141: .getRequestContext();
142:
143: /** User is searching for content. */
144: public static final String FIND = WikiCommand.FIND
145: .getRequestContext();
146:
147: /** User wishes to create a new group */
148: public static final String CREATE_GROUP = WikiCommand.CREATE_GROUP
149: .getRequestContext();
150:
151: /** User is deleting an existing group. */
152: public static final String DELETE_GROUP = GroupCommand.DELETE_GROUP
153: .getRequestContext();
154:
155: /** User is editing an existing group. */
156: public static final String EDIT_GROUP = GroupCommand.EDIT_GROUP
157: .getRequestContext();
158:
159: /** User is viewing an existing group */
160: public static final String VIEW_GROUP = GroupCommand.VIEW_GROUP
161: .getRequestContext();
162:
163: /** User is editing preferences */
164: public static final String PREFS = WikiCommand.PREFS
165: .getRequestContext();
166:
167: /** User is renaming a page. */
168: public static final String RENAME = PageCommand.RENAME
169: .getRequestContext();
170:
171: /** User is deleting a page or an attachment. */
172: public static final String DELETE = PageCommand.DELETE
173: .getRequestContext();
174:
175: /** User is downloading an attachment. */
176: public static final String ATTACH = PageCommand.ATTACH
177: .getRequestContext();
178:
179: /** RSS feed is being generated. */
180: public static final String RSS = PageCommand.RSS
181: .getRequestContext();
182:
183: /** This is not a JSPWiki context, use it to access static files. */
184: public static final String NONE = PageCommand.NONE
185: .getRequestContext();
186:
187: /** Same as NONE; this is just a clarification. */
188: public static final String OTHER = PageCommand.OTHER
189: .getRequestContext();
190:
191: /** User is doing administrative things. */
192: public static final String ADMIN = WikiCommand.ADMIN
193: .getRequestContext();
194:
195: private static final Logger log = Logger
196: .getLogger(WikiContext.class);
197:
198: private static final Permission DUMMY_PERMISSION = new java.util.PropertyPermission(
199: "os.name", "read");
200:
201: /**
202: * Create a new WikiContext for the given WikiPage. Delegates to
203: * {@link #WikiContext(WikiEngine, HttpServletRequest, WikiPage)}.
204: * @param engine The WikiEngine that is handling the request.
205: * @param page The WikiPage. If you want to create a
206: * WikiContext for an older version of a page, you must use this
207: * constructor.
208: */
209: public WikiContext(WikiEngine engine, WikiPage page) {
210: this (engine, null, findCommand(engine, null, page));
211: }
212:
213: /**
214: * <p>
215: * Creates a new WikiContext for the given WikiEngine, Command and
216: * HttpServletRequest.
217: * </p>
218: * <p>
219: * This constructor will also look up the HttpSession associated with the
220: * request, and determine if a WikiSession object is present. If not, a new
221: * one is created.
222: * </p>
223: * <p>
224: * After the WikiSession object is obtained, the current authentication
225: * status is checked. If not authenticated, or if the login status reported
226: * by the container has changed, the constructor attempts to log in the user
227: * with
228: * {@link com.ecyrd.jspwiki.auth.AuthenticationManager#login(HttpServletRequest)}.
229: * If an login process throws an exception, this method logs the error but
230: * does not re-throw it.
231: * </p>
232: * @param engine The WikiEngine that is handling the request
233: * @param request The HttpServletRequest that should be associated with this
234: * context. This parameter may be <code>null</code>.
235: * @param command the command
236: * @throws IllegalArgumentException if <code>engine</code> or
237: * <code>command</code> are <code>null</code>
238: */
239: public WikiContext(WikiEngine engine, HttpServletRequest request,
240: Command command) throws IllegalArgumentException {
241: super ();
242: if (engine == null || command == null) {
243: throw new IllegalArgumentException(
244: "Parameter engine and command must not be null.");
245: }
246:
247: m_engine = engine;
248: m_request = request;
249: m_session = WikiSession.getWikiSession(engine, request);
250: m_command = command;
251:
252: // If PageCommand, get the WikiPage
253: if (command instanceof PageCommand) {
254: m_page = (WikiPage) ((PageCommand) command).getTarget();
255: }
256:
257: // If page not supplied, default to front page to avoid NPEs
258: if (m_page == null) {
259: m_page = m_engine.getPage(m_engine.getFrontPage());
260:
261: // Front page does not exist?
262: if (m_page == null) {
263: m_page = new WikiPage(m_engine, m_engine.getFrontPage());
264: }
265: }
266:
267: m_realPage = m_page;
268:
269: // Special case: retarget any empty 'view' PageCommands to the front page
270: if (PageCommand.VIEW.equals(command)
271: && command.getTarget() == null) {
272: m_command = command.targetedCommand(m_page);
273: }
274:
275: // Log in the user if new session or the container status changed
276: boolean doLogin = (request != null) && m_session.isNew();
277:
278: // Debugging...
279: if (log.isDebugEnabled()) {
280: HttpSession session = (request == null) ? null : request
281: .getSession(false);
282: String sid = (session == null) ? "(null)" : session.getId();
283: log.debug("Creating WikiContext for session ID=" + sid
284: + "; target=" + getName());
285: log.debug("Do we need to log the user in? " + doLogin);
286: }
287:
288: if (doLogin || m_session.isContainerStatusChanged(request)) {
289: try {
290: engine.getAuthenticationManager().login(request);
291: } catch (WikiSecurityException e) {
292: // Login failed because config was screwy
293: log.error("Could not log in user: " + e.getMessage());
294: }
295: }
296:
297: // Mark the session as "not new"
298: if (m_session.isNew()) {
299: m_session.setNew(false);
300: }
301:
302: // Figure out what template to use
303: setDefaultTemplate(request);
304: }
305:
306: /**
307: * Creates a new WikiContext for the given WikiEngine, WikiPage and
308: * HttpServletRequest. This method simply looks up the appropriate Command
309: * using {@link #findCommand(WikiEngine, HttpServletRequest, WikiPage)} and
310: * delegates to
311: * {@link #WikiContext(WikiEngine, HttpServletRequest, Command)}.
312: * @param engine The WikiEngine that is handling the request
313: * @param request The HttpServletRequest that should be associated with this
314: * context. This parameter may be <code>null</code>.
315: * @param page The WikiPage. If you want to create a WikiContext for an
316: * older version of a page, you must supply this parameter
317: */
318: public WikiContext(WikiEngine engine, HttpServletRequest request,
319: WikiPage page) {
320: this (engine, request, findCommand(engine, request, page));
321: }
322:
323: /**
324: * {@inheritDoc}
325: * @see com.ecyrd.jspwiki.ui.Command#getContentTemplate()
326: */
327: public String getContentTemplate() {
328: return m_command.getContentTemplate();
329: }
330:
331: /**
332: * {@inheritDoc}
333: * @see com.ecyrd.jspwiki.ui.Command#getJSP()
334: */
335: public String getJSP() {
336: return m_command.getContentTemplate();
337: }
338:
339: /**
340: * Sets a reference to the real page whose content is currently being
341: * rendered.
342: * <p>
343: * Sometimes you may want to render the page using some other page's context.
344: * In those cases, it is highly recommended that you set the setRealPage()
345: * to point at the real page you are rendering. Please see InsertPageTag
346: * for an example.
347: * <p>
348: * Also, if your plugin e.g. does some variable setting, be aware that if it
349: * is embedded in the LeftMenu or some other page added with InsertPageTag,
350: * you should consider what you want to do - do you wish to really reference
351: * the "master" page or the included page.
352: *
353: * @param page The real page which is being rendered.
354: * @return The previous real page
355: * @since 2.3.14
356: * @see com.ecyrd.jspwiki.tags.InsertPageTag
357: */
358: public WikiPage setRealPage(WikiPage page) {
359: WikiPage old = m_realPage;
360: m_realPage = page;
361: updateCommand(m_command.getRequestContext());
362: return old;
363: }
364:
365: /**
366: * Gets a reference to the real page whose content is currently being rendered.
367: * If your plugin e.g. does some variable setting, be aware that if it
368: * is embedded in the LeftMenu or some other page added with InsertPageTag,
369: * you should consider what you want to do - do you wish to really reference
370: * the "master" page or the included page.
371: * <p>
372: * For example, in the default template, there is a page called "LeftMenu".
373: * Whenever you access a page, e.g. "Main", the master page will be Main, and
374: * that's what the getPage() will return - regardless of whether your plugin
375: * resides on the LeftMenu or on the Main page. However, getRealPage()
376: * will return "LeftMenu".
377: *
378: * @return A reference to the real page.
379: * @see com.ecyrd.jspwiki.tags.InsertPageTag
380: * @see com.ecyrd.jspwiki.parser.JSPWikiMarkupParser
381: */
382: public WikiPage getRealPage() {
383: return m_realPage;
384: }
385:
386: /**
387: * Figure out to which page we are really going to. Considers
388: * special page names from the jspwiki.properties, and possible aliases.
389: * This method forwards requests to
390: * {@link com.ecyrd.jspwiki.ui.CommandResolver#getSpecialPageReference(String)}.
391: * @return A complete URL to the new page to redirect to
392: * @since 2.2
393: */
394:
395: public String getRedirectURL() {
396: String pagename = m_page.getName();
397: String redirURL = null;
398:
399: redirURL = m_engine.getCommandResolver()
400: .getSpecialPageReference(pagename);
401:
402: if (redirURL == null) {
403: String alias = (String) m_page.getAttribute(WikiPage.ALIAS);
404:
405: if (alias != null) {
406: redirURL = getViewURL(alias);
407: } else {
408: redirURL = (String) m_page
409: .getAttribute(WikiPage.REDIRECT);
410: }
411: }
412:
413: return redirURL;
414: }
415:
416: /**
417: * Returns the handling engine.
418: *
419: * @return The wikiengine owning this context.
420: */
421: public WikiEngine getEngine() {
422: return m_engine;
423: }
424:
425: /**
426: * Returns the page that is being handled.
427: *
428: * @return the page which was fetched.
429: */
430: public WikiPage getPage() {
431: return m_page;
432: }
433:
434: /**
435: * Sets the page that is being handled.
436: *
437: * @param page The wikipage
438: * @since 2.1.37.
439: */
440: public void setPage(WikiPage page) {
441: m_page = page;
442: updateCommand(m_command.getRequestContext());
443: }
444:
445: /**
446: * Returns the request context.
447: * @return The name of the request context (e.g. VIEW).
448: */
449: public String getRequestContext() {
450: return m_command.getRequestContext();
451: }
452:
453: /**
454: * Sets the request context. See above for the different
455: * request contexts (VIEW, EDIT, etc.)
456: *
457: * @param arg The request context (one of the predefined contexts.)
458: */
459: public void setRequestContext(String arg) {
460: updateCommand(arg);
461: }
462:
463: /**
464: * {@inheritDoc}
465: * @see com.ecyrd.jspwiki.ui.Command#getTarget()
466: */
467: public Object getTarget() {
468: return m_command.getTarget();
469: }
470:
471: /**
472: * {@inheritDoc}
473: * @see com.ecyrd.jspwiki.ui.Command#getURLPattern()
474: */
475: public String getURLPattern() {
476: return m_command.getURLPattern();
477: }
478:
479: /**
480: * Gets a previously set variable.
481: *
482: * @param key The variable name.
483: * @return The variable contents.
484: */
485: public Object getVariable(String key) {
486: return m_variableMap.get(key);
487: }
488:
489: /**
490: * Sets a variable. The variable is valid while the WikiContext is valid,
491: * i.e. while page processing continues. The variable data is discarded
492: * once the page processing is finished.
493: *
494: * @param key The variable name.
495: * @param data The variable value.
496: */
497: public void setVariable(String key, Object data) {
498: m_variableMap.put(key, data);
499: updateCommand(m_command.getRequestContext());
500: }
501:
502: /**
503: * This method will safely return any HTTP parameters that
504: * might have been defined. You should use this method instead
505: * of peeking directly into the result of getHttpRequest(), since
506: * this method is smart enough to do all of the right things,
507: * figure out UTF-8 encoded parameters, etc.
508: *
509: * @since 2.0.13.
510: * @param paramName Parameter name to look for.
511: * @return HTTP parameter, or null, if no such parameter existed.
512: */
513: public String getHttpParameter(String paramName) {
514: String result = null;
515:
516: if (m_request != null) {
517: result = m_request.getParameter(paramName);
518: }
519:
520: return result;
521: }
522:
523: /**
524: * If the request did originate from a HTTP request,
525: * then the HTTP request can be fetched here. However, it the request
526: * did NOT originate from a HTTP request, then this method will
527: * return null, and YOU SHOULD CHECK FOR IT!
528: *
529: * @return Null, if no HTTP request was done.
530: * @since 2.0.13.
531: */
532: public HttpServletRequest getHttpRequest() {
533: return m_request;
534: }
535:
536: /**
537: * Sets the template to be used for this request.
538: *
539: * @param dir The template name
540: * @since 2.1.15.
541: */
542: public void setTemplate(String dir) {
543: m_template = dir;
544: }
545:
546: /**
547: * Returns the target of this wiki context: a page, group name or JSP. If
548: * the associated Command is a PageCommand, this method returns the page's
549: * name. Otherwise, this method delegates to the associated Command's
550: * {@link com.ecyrd.jspwiki.ui.Command#getName()} method. Calling classes
551: * can rely on the results of this method for looking up canonically-correct
552: * page or group names. Because it does not automatically assume that the
553: * wiki context is a PageCommand, calling this method is inherently safer
554: * than calling <code>getPage().getName()</code>.
555: * @return the name of the target of this wiki context
556: * @see com.ecyrd.jspwiki.ui.PageCommand#getName()
557: * @see com.ecyrd.jspwiki.ui.GroupCommand#getName()
558: */
559: public String getName() {
560: if (m_command instanceof PageCommand) {
561: return m_page != null ? m_page.getName() : "<no page>";
562: }
563: return m_command.getName();
564: }
565:
566: /**
567: * Gets the template that is to be used throughout this request.
568: * @since 2.1.15.
569: * @return template name
570: */
571: public String getTemplate() {
572: return m_template;
573: }
574:
575: /**
576: * Convenience method that gets the current user. Delegates the
577: * lookup to the WikiSession associated with this WikiContect.
578: * May return null, in case the current
579: * user has not yet been determined; or this is an internal system.
580: * If the WikiSession has not been set, <em>always</em> returns null.
581: *
582: * @return The current user; or maybe null in case of internal calls.
583: */
584: public Principal getCurrentUser() {
585: if (m_session == null) {
586: // This shouldn't happen, really...
587: return WikiPrincipal.GUEST;
588: }
589: return m_session.getUserPrincipal();
590: }
591:
592: /**
593: * A shortcut to generate a VIEW url.
594: *
595: * @param page The page to which to link.
596: * @return An URL to the page. This honours the current absolute/relative setting.
597: */
598: public String getViewURL(String page) {
599: return getURL(VIEW, page, null);
600: }
601:
602: /**
603: * Creates an URL for the given request context.
604: *
605: * @param context e.g. WikiContext.EDIT
606: * @param page The page to which to link
607: * @return An URL to the page, honours the absolute/relative setting in jspwiki.properties
608: */
609: public String getURL(String context, String page) {
610: return getURL(context, page, null);
611: }
612:
613: /**
614: * Returns an URL from a page. It this WikiContext instance was constructed
615: * with an actual HttpServletRequest, we will attempt to construct the
616: * URL using HttpUtil, which preserves the HTTPS portion if it was used.
617: *
618: * @param context The request context (e.g. WikiContext.UPLOAD)
619: * @param page The page to which to link
620: * @param params A list of parameters, separated with "&"
621: *
622: * @return An URL to the given context and page.
623: */
624: public String getURL(String context, String page, String params) {
625: boolean absolute = "absolute".equals(m_engine.getVariable(this ,
626: WikiEngine.PROP_REFSTYLE));
627:
628: // FIXME: is rather slow
629: return m_engine.getURL(context, page, params, absolute);
630:
631: }
632:
633: /**
634: * Returns the Command associated with this WikiContext.
635: * @return the command
636: */
637: public Command getCommand() {
638: return m_command;
639: }
640:
641: /**
642: * Returns a shallow clone of the WikiContext.
643: *
644: * @since 2.1.37.
645: * @return A shallow clone of the WikiContext
646: */
647: public Object clone() {
648: try {
649: // super.clone() must always be called to make sure that inherited objects
650: // get the right type
651: WikiContext copy = (WikiContext) super .clone();
652:
653: copy.m_engine = m_engine;
654: copy.m_command = m_command;
655:
656: copy.m_template = m_template;
657: copy.m_variableMap = m_variableMap;
658: copy.m_request = m_request;
659: copy.m_session = m_session;
660: copy.m_page = m_page;
661: copy.m_realPage = m_realPage;
662: return copy;
663: } catch (CloneNotSupportedException e) {
664: } // Never happens
665:
666: return null;
667: }
668:
669: /**
670: * Returns the WikiSession associated with the context.
671: * This method is guaranteed to always return a valid WikiSession.
672: * If this context was constructed without an associated
673: * HttpServletRequest, it will return {@link WikiSession#guestSession(WikiEngine)}.
674: *
675: * @return The WikiSession associate with this context.
676: */
677: public WikiSession getWikiSession() {
678: return m_session;
679: }
680:
681: /**
682: * This method can be used to find the WikiContext programmatically
683: * from a JSP PageContext. We check the request context.
684: * The wiki context, if it exists,
685: * is looked up using the key
686: * {@link com.ecyrd.jspwiki.tags.WikiTagBase#ATTR_CONTEXT}.
687: *
688: * @since 2.4
689: * @param pageContext the JSP page context
690: * @return Current WikiContext, or null, of no context exists.
691: */
692: public static WikiContext findContext(PageContext pageContext) {
693: HttpServletRequest request = (HttpServletRequest) pageContext
694: .getRequest();
695: WikiContext context = (WikiContext) request
696: .getAttribute(WikiTagBase.ATTR_CONTEXT);
697: return context;
698: }
699:
700: /**
701: * Returns the permission required to successfully execute this context.
702: * For example, the a wiki context of VIEW for a certain page means that
703: * the PagePermission "view" is required for the page. In some cases, no
704: * particular permission is required, in which case a dummy permission will
705: * be returned ({@link java.util.PropertyPermission}<code> "os.name",
706: * "read"</code>). This method is guaranteed to always return a valid,
707: * non-null permission.
708: * @return the permission
709: * @since 2.4
710: */
711: public Permission requiredPermission() {
712: // This is a filthy rotten hack -- absolutely putrid
713: if (WikiCommand.INSTALL.equals(m_command)) {
714: // See if admin users exists
715: boolean adminExists = false;
716: try {
717: UserManager userMgr = m_engine.getUserManager();
718: UserDatabase userDb = userMgr.getUserDatabase();
719: userDb.findByLoginName(Installer.ADMIN_ID);
720: adminExists = true;
721: } catch (NoSuchPrincipalException e) {
722: return DUMMY_PERMISSION;
723: }
724: if (adminExists) {
725: return new AllPermission(m_engine.getApplicationName());
726: }
727: }
728:
729: // TODO: we should really break the contract so that this
730: // method returns null, but until then we will use this hack
731: if (m_command.requiredPermission() == null) {
732: return DUMMY_PERMISSION;
733: }
734:
735: return m_command.requiredPermission();
736: }
737:
738: /**
739: * Associates a target with the current Command and returns
740: * the new targeted Command. If the Command associated with this
741: * WikiContext is already "targeted", it is returned instead.
742: * @see com.ecyrd.jspwiki.ui.Command#targetedCommand(java.lang.Object)
743: *
744: * {@inheritDoc}
745: */
746: public Command targetedCommand(Object target) {
747: if (m_command.getTarget() == null) {
748: return m_command.targetedCommand(target);
749: }
750: return m_command;
751: }
752:
753: /**
754: * Checks whether the current user has access to this wiki context,
755: * by obtaining the required Permission ({@link #requiredPermission()})
756: * and delegating the access check to
757: * {@link com.ecyrd.jspwiki.auth.AuthorizationManager#checkPermission(WikiSession, Permission)}.
758: * If the user is allowed, this method returns <code>true</code>;
759: * <code>false</code> otherwise. If access is allowed,
760: * the wiki context will be added to the request as an attribute
761: * with the key name {@link com.ecyrd.jspwiki.tags.WikiTagBase#ATTR_CONTEXT}.
762: * Note that this method will automatically redirect the user to
763: * a login or error page, as appropriate, if access fails. This is
764: * NOT guaranteed to be default behavior in the future.
765: * @param response the http response
766: * @return the result of the access check
767: * @throws IOException In case something goes wrong
768: */
769: public boolean hasAccess(HttpServletResponse response)
770: throws IOException {
771: return hasAccess(response, true);
772: }
773:
774: /**
775: * Checks whether the current user has access to this wiki context (and
776: * optionally redirects if not), by obtaining the required Permission ({@link #requiredPermission()})
777: * and delegating the access check to
778: * {@link com.ecyrd.jspwiki.auth.AuthorizationManager#checkPermission(WikiSession, Permission)}.
779: * If the user is allowed, this method returns <code>true</code>;
780: * <code>false</code> otherwise. If access is allowed,
781: * the wiki context will be added to the request as attribute
782: * with the key name {@link com.ecyrd.jspwiki.tags.WikiTagBase#ATTR_CONTEXT}.
783: * @return the result of the access check
784: * @param response The servlet response object
785: * @param redirect If true, makes an automatic redirect to the response
786: * @throws IOException If something goes wrong
787: */
788: public boolean hasAccess(HttpServletResponse response,
789: boolean redirect) throws IOException {
790: AuthorizationManager mgr = m_engine.getAuthorizationManager();
791: boolean allowed = mgr.checkPermission(m_session,
792: requiredPermission());
793: ResourceBundle rb = getBundle(InternationalizationManager.CORE_BUNDLE);
794:
795: // Stash the wiki context
796: if (allowed) {
797: if (m_request != null
798: && m_request.getAttribute(WikiTagBase.ATTR_CONTEXT) == null) {
799: m_request.setAttribute(WikiTagBase.ATTR_CONTEXT, this );
800: }
801: }
802:
803: // If access not allowed, redirect
804: if (!allowed && redirect) {
805: Principal currentUser = m_session.getUserPrincipal();
806: Object[] arguments = { getName() };
807: if (m_session.isAuthenticated()) {
808: log.info("User " + currentUser.getName()
809: + " has no access - forbidden (permission="
810: + requiredPermission() + ")");
811: String pageurl = m_page.getName();
812: m_session.addMessage(MessageFormat.format(rb
813: .getString("security.error.noaccess.logged"),
814: arguments));
815: response.sendRedirect(m_engine.getURL(
816: WikiContext.LOGIN, pageurl, null, false));
817: } else {
818: log.info("User " + currentUser.getName()
819: + " has no access - redirecting (permission="
820: + requiredPermission() + ")");
821: String pageurl = m_page.getName();
822: m_session.addMessage(MessageFormat.format(rb
823: .getString("security.error.noaccess"),
824: arguments));
825: response.sendRedirect(m_engine.getURL(
826: WikiContext.LOGIN, pageurl, null, false));
827: }
828: }
829: return allowed;
830: }
831:
832: /**
833: * Returns true, if the current user has administrative permissions (i.e. the omnipotent
834: * AllPermission).
835: *
836: * @since 2.4.46
837: * @return true, if the user has all permissions.
838: */
839: public boolean hasAdminPermissions() {
840: boolean admin = false;
841:
842: admin = m_engine.getAuthorizationManager().checkPermission(
843: getWikiSession(),
844: new AllPermission(m_engine.getApplicationName()));
845:
846: return admin;
847: }
848:
849: /**
850: * Figures out which template a new WikiContext should be using.
851: * @param request the HTTP request
852: */
853: protected void setDefaultTemplate(HttpServletRequest request) {
854: // FIXME: Most definitely this should be checked for
855: // existence, or else it is possible to create pages that
856: // cannot be shown.
857: String defaultTemplate = m_engine.getTemplateDir();
858:
859: // Figure out which template we should be using for this page.
860: String template = null;
861: if (request != null) {
862: template = request.getParameter("skin");
863: }
864:
865: // If request doesn't supply the value, extract from wiki page
866: if (template == null) {
867: WikiPage page = getPage();
868: if (page != null) {
869: template = (String) page
870: .getAttribute(WikiEngine.PROP_TEMPLATEDIR);
871: }
872:
873: }
874:
875: // If something over-wrote the default, set the new value.
876: if (template != null) {
877: setTemplate(template);
878: } else {
879: setTemplate(defaultTemplate);
880: }
881: }
882:
883: /**
884: * Looks up and returns a PageCommand based on a supplied WikiPage and HTTP
885: * request. First, the appropriate Command is obtained by examining the HTTP
886: * request; the default is {@link PageCommand#VIEW}. If the Command is a
887: * PageCommand (and it should be, in most cases), a targeted Command is
888: * created using the (non-<code>null</code>) WikiPage as target.
889: * @param engine the wiki engine
890: * @param request the HTTP request
891: * @param page the wiki page
892: * @return the correct command
893: */
894: protected static Command findCommand(WikiEngine engine,
895: HttpServletRequest request, WikiPage page) {
896: String defaultContext = PageCommand.VIEW.getRequestContext();
897: Command command = engine.getCommandResolver().findCommand(
898: request, defaultContext);
899: if (command instanceof PageCommand && page != null) {
900: command = command.targetedCommand(page);
901: }
902: return command;
903: }
904:
905: /**
906: * Protected method that updates the internally cached Command.
907: * Will always be called when the page name, request context, or variable
908: * changes.
909: * @param requestContext the desired request context
910: * @since 2.4
911: */
912: protected void updateCommand(String requestContext) {
913: if (requestContext == null) {
914: m_command = PageCommand.NONE;
915: } else {
916: CommandResolver resolver = m_engine.getCommandResolver();
917: m_command = resolver.findCommand(m_request, requestContext);
918: }
919:
920: if (m_command instanceof PageCommand && m_page != null) {
921: m_command = m_command.targetedCommand(m_page);
922: }
923: }
924:
925: /**
926: * Locates the i18n ResourceBundle given. This method interprets
927: * the request locale, and uses that to figure out which language the
928: * user wants.
929: * @see com.ecyrd.jspwiki.i18n.InternationalizationManager
930: * @param bundle The name of the bundle you are looking for.
931: * @return A resource bundle object
932: * @throws MissingResourceException If the bundle cannot be found
933: */
934: // FIXME: This method should really cache the ResourceBundles or something...
935: public ResourceBundle getBundle(String bundle)
936: throws MissingResourceException {
937: Locale loc = null;
938:
939: if (m_request != null)
940: loc = m_request.getLocale();
941:
942: ResourceBundle b = m_engine.getInternationalizationManager()
943: .getBundle(bundle, loc);
944:
945: return b;
946: }
947:
948: /**
949: * Returns the locale of the HTTP request if available,
950: * otherwise returns the default Locale of the server.
951: *
952: * @return A valid locale object
953: * @param context The WikiContext
954: */
955: public static Locale getLocale(WikiContext context) {
956: HttpServletRequest request = context.getHttpRequest();
957: return (request != null) ? request.getLocale() : Locale
958: .getDefault();
959: }
960:
961: }
|