001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.services.controller;
066:
067: import com.jcorporate.expresso.core.controller.ControllerException;
068: import com.jcorporate.expresso.core.controller.ControllerRequest;
069: import com.jcorporate.expresso.core.controller.ControllerResponse;
070: import com.jcorporate.expresso.core.controller.DBController;
071: import com.jcorporate.expresso.core.controller.ErrorCollection;
072: import com.jcorporate.expresso.core.controller.Input;
073: import com.jcorporate.expresso.core.controller.NonHandleableException;
074: import com.jcorporate.expresso.core.controller.State;
075: import com.jcorporate.expresso.core.controller.Transition;
076: import com.jcorporate.expresso.core.db.DBException;
077: import com.jcorporate.expresso.services.validation.AuthValidationException;
078: import com.jcorporate.expresso.services.validation.ValidationEntry;
079: import com.jcorporate.expresso.services.validation.ValidationHandler;
080: import org.apache.log4j.Logger;
081:
082: import java.util.Date;
083:
084: /**
085: * This is an Expresso controller that responds to the validator
086: * clicking on an URL provided to him from the notification
087: * from the validation job. It has the responsibility of
088: * extracting the parameters from the request, resurrecting
089: * the Validation entry using the validation-db-context and the
090: * validation id. It then compares the code provided in the
091: * request with that stored in the validation entry. If the code
092: * matches, then the application-supplied validation handler is called
093: * to allow the validated-process to go through.
094: *
095: * @author Shash Chatterjee
096: */
097: public class ValidationController extends DBController {
098: private static Logger log = Logger
099: .getLogger(ValidationController.class.getName());
100:
101: /**
102: * Typical default constructor for a controller, defines
103: * all the states handled by this controller and also
104: * sets the initial state if no "state=..." parameter
105: * is provided when this controller is invoked.
106: * <p/>
107: * Creation date: (9/23/2001 9:53:01 AM)
108: * Author: Shash Chatterjee
109: */
110: public ValidationController() {
111: super ();
112: addState(new State("validate", "Validate"));
113: addState(new State("promptValidation", "ValidationCode"));
114: setInitialState("validate");
115: this
116: .setSchema(com.jcorporate.expresso.core.ExpressoSchema.class);
117: }
118:
119: /**
120: * A short title for this controller, used mainly in UI screens.
121: * <p/>
122: * Creation date: (9/23/2001 9:54:30 AM)
123: * Author: Shash Chatterjee
124: *
125: * @return The title
126: */
127: public String getTitle() {
128: return ("AuthorizationProcessing");
129: }
130:
131: /**
132: * This method simply provides an UI for the three parameters
133: * found in a validation URL. It is onlyu used when there is
134: * an error found processing the link with the runValidateState(...)
135: * method.
136: * <p/>
137: * Creation date: (9/23/2001 9:56:25 AM)
138: * Author: Shash Chatterjee
139: *
140: * @param request All the request parameters
141: * @param response The response created by this state
142: * @throws ControllerException Some of the objects used generate this
143: */
144: protected void runPromptValidationState(ControllerRequest request,
145: ControllerResponse response) throws ControllerException {
146:
147: // The name of the context used for the validation entry
148: Input ctx = new Input("ctx", "Validation Context");
149: ctx.setDefaultValue(response.getFormCache("ctx"));
150: response.add(ctx);
151:
152: // The sequence/ID number of the validation entry
153: Input id = new Input("id", "ID");
154: id.setDefaultValue(response.getFormCache("id"));
155: response.add(id);
156:
157: // The validation code
158: Input code = new Input("code", "Code");
159: code.setDefaultValue(response.getFormCache("code"));
160: response.add(code);
161:
162: // A button to go back to the rubValidateState
163: Transition val = new Transition("validate", this );
164: val.setLabel("RetryValidation");
165: response.add(val);
166: }
167:
168: /**
169: * This method simply provides an UI for the three parameters
170: * found in a validation URL. It is onlyu used when there is
171: * an error found processing the link with the runValidateState(...)
172: * method.
173: * <p/>
174: * Creation date: (9/23/2001 9:56:25 AM)
175: * Author: Shash Chatterjee
176: *
177: * @param request All the request parameters
178: * @param response The response created by this state
179: * @return ControllerResponse
180: * @throws ControllerException If there as an exception thrown by the
181: * validation classes, also some of the objects used generate this
182: * @throws DBException Some of the objects used generate this
183: * @throws NonHandleableException Some of the objects used generate this
184: */
185: protected ControllerResponse runValidateState(
186: ControllerRequest request, ControllerResponse response)
187: throws ControllerException, DBException,
188: NonHandleableException {
189: ValidationEntry ve = null;
190: try {
191: ErrorCollection errors = new ErrorCollection();
192:
193: // Context for the validation entry
194: String dbName = request.getParameter("ctx");
195:
196: if ((dbName == null) || (dbName.equals(""))) {
197: errors
198: .addError("Validation operation needs a db context");
199: } else {
200: response.setFormCache("ctx", dbName);
201: }
202:
203: // Unique id/seq. # for the validation entry
204: String id = request.getParameter("id");
205:
206: if ((id == null) || (id.equals(""))) {
207: errors.addError("Validation operation needs an ID");
208: } else {
209: response.setFormCache("id", id);
210: }
211:
212: // The validation code
213: String code = request.getParameter("code");
214:
215: if ((code == null) || (code.equals(""))) {
216: errors.addError("Validation operation needs a code.");
217: } else {
218: response.setFormCache("code", code);
219: }
220:
221: // Resurrect the validation entry, given the context/id
222: try {
223: ve = new ValidationEntry(dbName, id);
224: } catch (AuthValidationException e) {
225: errors
226: .addError("This validation link could not be found");
227: }
228:
229: // Do some error checking here...
230: if (errors.isEmpty()) {
231: String state = ve.getStatus();
232:
233: // Only process the validation entry if it is "available"
234: if (state.equals(ValidationEntry.EXPIRED)) {
235: errors.addError("This validation link has expired");
236: } else if (state.equals(ValidationEntry.VALIDATED)) {
237: errors
238: .addError("This validation link is no longer available, it was already validated");
239: } else {
240:
241: // Make sure the entry hasn't expired already
242: Date now = new Date();
243: Date expiresAt = ve.getExpiresAt();
244:
245: if (now.after(expiresAt)) {
246: ve.setStatus(ValidationEntry.EXPIRED);
247: errors
248: .addError("This validation link has expired");
249: }
250: }
251: }
252: // Check if the supplied code matches that in the validation entry
253: if (errors.isEmpty()) {
254: if (!ve.codeMatches(code)) {
255: errors
256: .addError("Specified code is invalid, validation failed");
257: log.warn("Received invalid validation code. "
258: + code);
259: }
260: }
261: // If errors were found so far, display the error and prompt mfor corrected input
262: if (!errors.isEmpty()) {
263: response.saveErrors(errors);
264: response = this .newState("promptValidation", request);
265: log.warn("error in validation for code: " + code);
266: return response;
267: }
268:
269: // Get the application-specific handler and call the "validated" method on it.
270: ValidationHandler vh = ve.instantiateHandler();
271:
272: // If we get here...everything went smoothly
273: ve.setStatus(ValidationEntry.VALIDATED);
274:
275: //
276: //Save the validation entry in the session.
277: //
278: request.getSession().setPersistentAttribute(
279: ValidationEntry.SESSION_KEY, ve);
280:
281: // Get the application-specific handler and call the "validated" method on it.
282: response = vh.validated(ve.getParams(), request, response,
283: this );
284: if (log.isInfoEnabled()) {
285: log.info("Successfully validated code" + code
286: + " for validation handler: "
287: + vh.getClass().getName());
288: }
289:
290: return response;
291: } catch (AuthValidationException vex) {
292: log.error("Error processing validation", vex);
293:
294: try {
295: //We had an error. Reset the validation entry to 'waiting'
296: //to allow a retry.
297: ve.setStatus(ValidationEntry.WAITING);
298: } catch (AuthValidationException ex) {
299: log.error("There is an error validating code: "
300: + request.getParameter("code")
301: + "it could not be reset to a waiting state."
302: + ex);
303: }
304:
305: throw new ControllerException("Validation error", vex);
306: } catch (Throwable t) {
307: try {
308: //We had an error. Reset the validation entry to 'waiting'
309: //to allow a retry.
310: ve.setStatus(ValidationEntry.WAITING);
311: } catch (AuthValidationException ex) {
312: log.error("There is an error validating code: "
313: + request.getParameter("code")
314: + "it could not be reset to a waiting state."
315: + ex);
316: }
317:
318: log.error("Error processing validation", t);
319: throw new ControllerException("Validation error", t);
320: }
321: }
322:
323: /**
324: * This method allows access to all states of this controller to everybody. The goal
325: * of preventing 'hack' attacks here is to require the tough random numbers. Currently
326: * we are doing 160 Bit random numbers. Makes for quite a long random URL
327: * <p/>
328: * Creation date: (9/23/2001 2:19:02 PM)
329: * Author: Shash Chatterjee
330: *
331: * @param newState The state to check permissions for
332: * @param params The request parameters
333: * @return true if the current is allowed to execute this state, false otherwise
334: * @throws ControllerException upon error (this implementation does not)
335: */
336: public synchronized boolean stateAllowed(String newState,
337: ControllerRequest params) throws ControllerException {
338: return true;
339: } /* stateAllowed(String) */
340:
341: }
|