001    package org.apache.turbine.modules.actions.sessionvalidator;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.commons.configuration.Configuration;
023    
024    import org.apache.commons.lang.StringUtils;
025    
026    import org.apache.commons.logging.Log;
027    import org.apache.commons.logging.LogFactory;
028    
029    import org.apache.turbine.Turbine;
030    import org.apache.turbine.TurbineConstants;
031    
032    import org.apache.turbine.pipeline.PipelineData;
033    import org.apache.turbine.services.security.TurbineSecurity;
034    
035    import org.apache.turbine.util.RunData;
036    import org.apache.turbine.util.TurbineException;
037    
038    /**
039     * SessionValidator that requires login for use with Template Services
040     * like Velocity or WebMacro.
041     *
042     * <br>
043     *
044     * Templating services requires a different Session Validator
045     * because of the way it handles screens.  If you use the WebMacro or
046     * Velocity Service with the DefaultSessionValidator, users will be able to
047     * bypass login by directly addressing the template using
048     * template/index.wm.  This is because the Page class looks for the
049     * keyword "template" in the Path information and if it finds it will
050     * reset the screen using it's lookup mechanism and thereby bypass
051     * Login.
052     *
053     * Note that you will need to set the template.login property to the
054     * login template.
055     *
056     * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
057     * @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
058     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
059     * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
060     * @version $Id: TemplateSecureSessionValidator.java 1066518 2011-02-02 16:30:53Z ludwig $
061     */
062    public class TemplateSecureSessionValidator
063        extends SessionValidator
064    {
065        /** Logging */
066        private static Log log = LogFactory.getLog(
067                TemplateSecureSessionValidator.class);
068    
069        /**
070         * doPerform is virtually identical to DefaultSessionValidator
071         * except that it calls template methods instead of bare screen
072         * methods. For example, it uses <code>setScreenTemplate</code> to
073         * load the tr.props TEMPLATE_LOGIN instead of the default's
074         * setScreen to TurbineConstants.SCREEN_LOGIN.
075         * @deprecated Use PipelineData version instead.
076         * @see DefaultSessionValidator
077         * @param data Turbine information.
078         * @throws TurbineException The anonymous user could not be obtained
079         *         from the security service
080         */
081        @Deprecated
082        @Override
083        public void doPerform(RunData data)
084                throws TurbineException
085        {
086            Configuration conf = Turbine.getConfiguration();
087    
088            // Pull user from session.
089            data.populate();
090    
091            // The user may have not logged in, so create a "guest/anonymous" user.
092            if (data.getUser() == null)
093            {
094                log.debug("Fixing up empty User Object!");
095                data.setUser(TurbineSecurity.getAnonymousUser());
096                data.save();
097            }
098    
099            // This is the secure sessionvalidator, so user must be logged in.
100            if (!data.getUser().hasLoggedIn())
101            {
102                log.debug("User is not logged in!");
103    
104                // only set the message if nothing else has already set it
105                // (e.g. the LogoutUser action).
106                if (StringUtils.isEmpty(data.getMessage()))
107                {
108                    data.setMessage(conf.getString(TurbineConstants.LOGIN_MESSAGE));
109                }
110    
111                // Set the screen template to the login page.
112                String loginTemplate =
113                    conf.getString(TurbineConstants.TEMPLATE_LOGIN);
114    
115                log.debug("Sending User to the Login Screen ("
116                        + loginTemplate + ")");
117                data.getTemplateInfo().setScreenTemplate(loginTemplate);
118    
119                // We're not doing any actions buddy! (except action.login which
120                // will have been performed already)
121                data.setAction(null);
122            }
123    
124            log.debug("Login Check finished!");
125    
126            // Make sure we have some way to return a response.
127            if (!data.hasScreen() && StringUtils.isEmpty(
128                    data.getTemplateInfo().getScreenTemplate()))
129            {
130                String template = conf.getString(
131                        TurbineConstants.TEMPLATE_HOMEPAGE);
132    
133                if (StringUtils.isNotEmpty(template))
134                {
135                    data.getTemplateInfo().setScreenTemplate(template);
136                }
137                else
138                {
139                    data.setScreen(conf.getString(
140                            TurbineConstants.SCREEN_HOMEPAGE));
141                }
142            }
143    
144            // The session_access_counter can be placed as a hidden field in
145            // forms.  This can be used to prevent a user from using the
146            // browsers back button and submitting stale data.
147            // FIXME!! a template needs to be written to use this with templates.
148    
149            if (data.getParameters().containsKey("_session_access_counter")
150                    && !TurbineSecurity.isAnonymousUser(data.getUser()))
151            {
152                // See comments in screens.error.InvalidState.
153                if (data.getParameters().getInt("_session_access_counter")
154                        < (((Integer) data.getUser().getTemp(
155                        "_session_access_counter")).intValue() - 1))
156                {
157                    if (data.getTemplateInfo().getScreenTemplate() != null)
158                    {
159                        data.getUser().setTemp("prev_template",
160                                data.getTemplateInfo().getScreenTemplate()
161                                .replace('/', ','));
162                        data.getTemplateInfo().setScreenTemplate(conf.getString(
163                                TurbineConstants.TEMPLATE_INVALID_STATE));
164                    }
165                    else
166                    {
167                        data.getUser().setTemp("prev_screen",
168                                               data.getScreen().replace('/', ','));
169                        data.setScreen(conf.getString(
170                                TurbineConstants.SCREEN_INVALID_STATE));
171                    }
172                    data.getUser().setTemp("prev_parameters", data.getParameters());
173                    data.setAction("");
174                }
175            }
176    
177            // We do not want to allow both a screen and template parameter.
178            // The template parameter is dominant.
179            if (data.getTemplateInfo().getScreenTemplate() != null)
180            {
181                data.setScreen(null);
182            }
183        }
184    
185        /**
186         * doPerform is virtually identical to DefaultSessionValidator
187         * except that it calls template methods instead of bare screen
188         * methods. For example, it uses <code>setScreenTemplate</code> to
189         * load the tr.props TEMPLATE_LOGIN instead of the default's
190         * setScreen to TurbineConstants.SCREEN_LOGIN.
191         *
192         * @see DefaultSessionValidator
193         * @param pipelineData Turbine information.
194         * @throws TurbineException The anonymous user could not be obtained
195         *         from the security service
196         */
197        @Override
198        public void doPerform(PipelineData pipelineData)
199        throws TurbineException
200        {
201            RunData data = getRunData(pipelineData);
202            doPerform(data);
203        }
204    
205    
206    }