001/*
002 * (C) Copyright 2011-2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     tdelprat, jcarsique
018 *
019 */
020
021package org.nuxeo.wizard;
022
023import static org.nuxeo.common.Environment.NUXEO_DATA_DIR;
024import static org.nuxeo.launcher.config.ConfigurationGenerator.DB_EXCLUDE_CHECK_LIST;
025import static org.nuxeo.launcher.config.ConfigurationGenerator.DB_NOSQL_LIST;
026import static org.nuxeo.launcher.config.ConfigurationGenerator.INSTALL_AFTER_RESTART;
027import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_BIND_ADDRESS;
028import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_HOST;
029import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_NAME;
030import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_PORT;
031import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_PWD;
032import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_USER;
033import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_MONGODB_NAME;
034import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_MONGODB_SERVER;
035import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_TEMPLATE_DBNAME;
036import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_TEMPLATE_DBNOSQL_NAME;
037import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_WIZARD_DONE;
038
039import java.io.File;
040import java.io.IOException;
041import java.lang.reflect.Method;
042import java.net.InetAddress;
043import java.net.URLEncoder;
044import java.net.UnknownHostException;
045import java.sql.SQLException;
046import java.util.ArrayList;
047import java.util.Enumeration;
048import java.util.HashMap;
049import java.util.Hashtable;
050import java.util.List;
051import java.util.Map;
052
053import javax.naming.AuthenticationException;
054import javax.naming.NameNotFoundException;
055import javax.naming.NamingEnumeration;
056import javax.naming.NamingException;
057import javax.naming.directory.Attributes;
058import javax.naming.directory.DirContext;
059import javax.naming.directory.InitialDirContext;
060import javax.naming.directory.SearchControls;
061import javax.naming.directory.SearchResult;
062import javax.servlet.ServletException;
063import javax.servlet.http.HttpServlet;
064import javax.servlet.http.HttpServletRequest;
065import javax.servlet.http.HttpServletResponse;
066
067import org.apache.commons.codec.binary.Base64;
068import org.apache.commons.logging.Log;
069import org.apache.commons.logging.LogFactory;
070import org.nuxeo.launcher.commons.DatabaseDriverException;
071import org.nuxeo.launcher.config.ConfigurationException;
072import org.nuxeo.launcher.config.ConfigurationGenerator;
073import org.nuxeo.wizard.context.Context;
074import org.nuxeo.wizard.context.ParamCollector;
075import org.nuxeo.wizard.download.DownloadablePackageOptions;
076import org.nuxeo.wizard.download.PackageDownloader;
077import org.nuxeo.wizard.helpers.ConnectRegistrationHelper;
078import org.nuxeo.wizard.helpers.IPValidator;
079import org.nuxeo.wizard.helpers.NumberValidator;
080import org.nuxeo.wizard.helpers.PackageDownloaderHelper;
081import org.nuxeo.wizard.nav.Page;
082import org.nuxeo.wizard.nav.SimpleNavigationHandler;
083
084/**
085 * Main entry point : find the right handler and start jsp rendering
086 *
087 * @author Tiry (tdelprat@nuxeo.com)
088 * @since 5.4.2
089 */
090public class RouterServlet extends HttpServlet {
091
092    private static final long serialVersionUID = 1L;
093
094    protected static Log log = LogFactory.getLog(RouterServlet.class);
095
096    protected SimpleNavigationHandler navHandler = SimpleNavigationHandler.instance();
097
098    public static final String CONNECT_TOKEN_KEY = "ConnectRegistrationToken";
099
100    protected String getAction(HttpServletRequest req) {
101        String uri = req.getRequestURI();
102
103        int idx = uri.indexOf("?");
104        if (idx > 0) {
105            uri = uri.substring(0, idx - 1);
106        }
107        String action = uri.replace(req.getContextPath() + "/router/", "");
108        if (action.startsWith("/")) {
109            action = action.substring(1);
110        }
111        return action;
112    }
113
114    @Override
115    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
116        // process action
117        handleAction(getAction(req), req, resp);
118    }
119
120    @Override
121    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
122        // store posted data
123        req.setCharacterEncoding("UTF-8");
124        Context.instance(req).getCollector().collectConfigurationParams(req);
125        doGet(req, resp);
126    }
127
128    protected Method findhandler(Page currentPage, String verb) {
129        String methodName = "handle" + currentPage.getAction() + verb;
130        Method method = null;
131        try {
132            method = this.getClass().getMethod(methodName, Page.class, HttpServletRequest.class,
133                    HttpServletResponse.class);
134        } catch (Exception e) {
135            // fall back to default Handler lookup
136            methodName = "handleDefault" + verb;
137            try {
138                method = this.getClass().getMethod(methodName, Page.class, HttpServletRequest.class,
139                        HttpServletResponse.class);
140            } catch (Exception e2) {
141                log.error("Unable to resolve default handler for " + verb, e);
142            }
143        }
144        return method;
145    }
146
147    protected void handleAction(String action, HttpServletRequest req, HttpServletResponse resp)
148            throws ServletException, IOException {
149        // locate page
150        Page currentPage = navHandler.getCurrentPage(action);
151        if (currentPage == null) {
152            resp.sendError(404, "Action " + action + " is not supported");
153            return;
154        }
155
156        // find action handler
157        Method handler = findhandler(currentPage, req.getMethod());
158        if (handler == null) {
159            resp.sendError(500, "No handler found for " + action);
160            return;
161        }
162
163        // execute handler => triggers rendering
164        try {
165            handler.invoke(this, currentPage, req, resp);
166        } catch (Exception e) {
167            log.error("Error during handler execution", e);
168            req.setAttribute("error", e);
169            req.getRequestDispatcher("/error.jsp").forward(req, resp);
170        }
171    }
172
173    // default handlers
174
175    public void handleDefaultGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
176            throws ServletException, IOException {
177        currentPage.dispatchToJSP(req, resp);
178    }
179
180    public void handleDefaultPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
181            throws ServletException, IOException {
182        // XXX validate data
183        currentPage.next().dispatchToJSP(req, resp, true);
184    }
185
186    // custom handlers
187
188    public void handleConnectGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
189            throws ServletException, IOException {
190        req.setAttribute("popupUrl", req.getContextPath() + "/ConnectCallback?action=display");
191        handleDefaultGET(currentPage, req, resp);
192    }
193
194    public void handleConnectCallbackGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
195            throws ServletException, IOException {
196        Context ctx = Context.instance(req);
197        String token = req.getParameter(CONNECT_TOKEN_KEY);
198        String action = req.getParameter("action");
199        String targetNav = null;
200
201        if (action == null || action.isEmpty()) {
202            action = "skip";
203        }
204        if (action.equals("register") && (token == null || token.isEmpty())) {
205            action = "skip";
206        }
207
208        if ("register".equals(action)) {
209            // store the registration info
210            Map<String, String> connectMap = new HashMap<>();
211            Context context = Context.instance(req);
212            if (token != null) {
213                String tokenData = new String(Base64.decodeBase64(token));
214                String[] tokenDataLines = tokenData.split("\n");
215                for (String line : tokenDataLines) {
216                    String[] parts = line.split(":");
217                    if (parts.length > 1) {
218                        connectMap.put(parts[0], parts[1]);
219                    }
220                }
221                context.storeConnectMap(connectMap);
222            }
223
224            // Save CLID
225            if (context.isConnectRegistrationDone()) {
226                // save Connect registration
227                ConnectRegistrationHelper.saveConnectRegistrationFile(context);
228            }
229
230            // deactivate the confirm form
231            SimpleNavigationHandler.instance().deactivatePage("ConnectFinish");
232            // go to the next page
233            targetNav = currentPage.next().getAction();
234        } else if ("skip".equals(action)) {
235            // activate the confirm form
236            SimpleNavigationHandler.instance().activatePage("ConnectFinish");
237            // go to it
238            targetNav = currentPage.next().getAction();
239        } else if ("prev".equals(action)) {
240            targetNav = currentPage.prev().prev().getAction();
241        } else if ("display".equals(action)) {
242            // compute CB url
243            String cbUrl = req.getRequestURL().toString();
244            cbUrl = cbUrl.replace("/router/" + currentPage.getAction(), "/ConnectCallback?cb=yes");
245            // In order to avoid any issue with badly configured reverse proxies
246            // => get url from the client side
247            if (ctx.getBaseUrl() != null) {
248                cbUrl = ctx.getBaseUrl() + "ConnectCallback?cb=yes";
249            }
250            cbUrl = URLEncoder.encode(cbUrl, "UTF-8");
251
252            String redirect = ctx.getCollector().getConfigurationParam("org.nuxeo.connect.url",
253                    "https://connect.nuxeo.com/nuxeo/site/") + "../../register/#/embedded?wizardCallbackUrl=" + cbUrl
254                    + "&pkg=" + ctx.getDistributionKey();
255
256            resp.sendRedirect(redirect);
257            return;
258        }
259
260        String targetUrl = req.getContextPath() + "/" + targetNav;
261        req.setAttribute("targetUrl", targetUrl);
262        handleDefaultGET(currentPage, req, resp);
263    }
264
265    public void handleConnectFinishGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
266            throws ServletException, IOException {
267        // get the connect Token and decode associated infos
268        String token = req.getParameter(CONNECT_TOKEN_KEY);
269        Map<String, String> connectMap = new HashMap<>();
270        if (token != null) {
271            String tokenData = new String(Base64.decodeBase64(token));
272            String[] tokenDataLines = tokenData.split("\n");
273            for (String line : tokenDataLines) {
274                String[] parts = line.split(":");
275                if (parts.length > 1) {
276                    connectMap.put(parts[0], parts[1]);
277                }
278            }
279            Context.instance(req).storeConnectMap(connectMap);
280        }
281        handleDefaultGET(currentPage, req, resp);
282    }
283
284    public void handleDBPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
285            throws ServletException, IOException {
286        Context ctx = Context.instance(req);
287        ParamCollector collector = ctx.getCollector();
288
289        String templateDbName = collector.getConfigurationParam(PARAM_TEMPLATE_DBNAME);
290        String templateDbNoSQLName = collector.getConfigurationParam(PARAM_TEMPLATE_DBNOSQL_NAME);
291        if ("true".equals(req.getParameter("refresh"))) {
292            collector.changeDBTemplate(templateDbName);
293            collector.changeDBTemplate(templateDbNoSQLName);
294            collector.removeDbKeys();
295            currentPage.dispatchToJSP(req, resp);
296            return;
297        }
298
299        // Check relational database
300        if (!DB_EXCLUDE_CHECK_LIST.contains(templateDbName)) {
301            if (collector.getConfigurationParam(PARAM_DB_NAME).isEmpty()) {
302                ctx.trackError(PARAM_DB_NAME, "error.dbname.required");
303            }
304            if (collector.getConfigurationParam(PARAM_DB_USER).isEmpty()) {
305                ctx.trackError(PARAM_DB_USER, "error.dbuser.required");
306            }
307            if (collector.getConfigurationParam(PARAM_DB_PWD).isEmpty()) {
308                ctx.trackError(PARAM_DB_PWD, "error.dbpassword.required");
309            }
310            if (collector.getConfigurationParam(PARAM_DB_HOST).isEmpty()) {
311                ctx.trackError(PARAM_DB_HOST, "error.dbhost.required");
312            }
313            if (collector.getConfigurationParam(PARAM_DB_PORT).isEmpty()) {
314                ctx.trackError(PARAM_DB_PORT, "error.dbport.required");
315            } else {
316                if (!NumberValidator.validate(collector.getConfigurationParam(PARAM_DB_PORT))) {
317                    ctx.trackError(PARAM_DB_PORT, "error.invalid.port");
318                } else {
319                    int dbPort = Integer.parseInt(collector.getConfigurationParam(PARAM_DB_PORT));
320                    if (dbPort < 1024 || dbPort > 65536) {
321                        ctx.trackError(PARAM_DB_PORT, "error.invalid.port");
322                    }
323                }
324            }
325            ConfigurationGenerator cg = collector.getConfigurationGenerator();
326            try {
327                cg.checkDatabaseConnection(templateDbName, collector.getConfigurationParam(PARAM_DB_NAME),
328                        collector.getConfigurationParam(PARAM_DB_USER), collector.getConfigurationParam(PARAM_DB_PWD),
329                        collector.getConfigurationParam(PARAM_DB_HOST), collector.getConfigurationParam(PARAM_DB_PORT));
330            } catch (DatabaseDriverException e) {
331                ctx.trackError(PARAM_DB_NAME, "error.db.driver.notfound");
332                log.warn(e);
333            } catch (SQLException e) {
334                ctx.trackError(PARAM_DB_NAME, "error.db.connection");
335                log.warn(e);
336            }
337        }
338
339        // Check NoSQL database
340        if (!DB_EXCLUDE_CHECK_LIST.contains(templateDbNoSQLName) && DB_NOSQL_LIST.contains(templateDbNoSQLName)) {
341            if (collector.getConfigurationParam(PARAM_MONGODB_NAME).isEmpty()) {
342                ctx.trackError(PARAM_MONGODB_NAME, "error.dbname.required");
343            }
344            if (collector.getConfigurationParam(PARAM_MONGODB_SERVER).isEmpty()) {
345                ctx.trackError(PARAM_MONGODB_SERVER, "error.dburi.required");
346            }
347        }
348
349        if (ctx.hasErrors()) {
350            currentPage.dispatchToJSP(req, resp);
351        } else {
352            currentPage.next().dispatchToJSP(req, resp, true);
353        }
354    }
355
356    public void handleUserPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
357            throws ServletException, IOException {
358        Context ctx = Context.instance(req);
359        ParamCollector collector = ctx.getCollector();
360
361        String refreshParam = req.getParameter("refresh");
362        String directoryType = collector.getConfigurationParam("nuxeo.directory.type");
363
364        if ("true".equals(refreshParam)) {
365            currentPage.dispatchToJSP(req, resp);
366            return;
367        }
368
369        if ("checkNetwork".equals(refreshParam) || "checkAuth".equals(refreshParam)
370                || "checkUserLdapParam".equals(refreshParam) || "checkGroupLdapParam".equals(refreshParam)) {
371            try {
372                if ("checkNetwork".equals(refreshParam)) {
373                    bindLdapConnection(collector, false);
374                    ctx.trackInfo("nuxeo.ldap.url", "info.host.found");
375                } else if ("checkAuth".equals(refreshParam)) {
376                    bindLdapConnection(collector, true);
377                    ctx.trackInfo("nuxeo.ldap.auth", "info.auth.success");
378                } else {
379                    DirContext dirContext = new InitialDirContext(getContextEnv(collector, true));
380                    String searchScope;
381                    String searchBaseDn;
382                    String searchClass;
383                    String searchFilter;
384                    if ("checkUserLdapParam".equals(refreshParam)) {
385                        searchBaseDn = collector.getConfigurationParam("nuxeo.ldap.user.searchBaseDn");
386                        searchScope = collector.getConfigurationParam("nuxeo.ldap.user.searchScope");
387                        searchClass = collector.getConfigurationParam("nuxeo.ldap.user.searchClass");
388                        searchFilter = collector.getConfigurationParam("nuxeo.ldap.user.searchFilter");
389                    } else {
390                        searchBaseDn = collector.getConfigurationParam("nuxeo.ldap.group.searchBaseDn");
391                        searchScope = collector.getConfigurationParam("nuxeo.ldap.group.searchScope");
392                        searchFilter = collector.getConfigurationParam("nuxeo.ldap.group.searchFilter");
393                        searchClass = "";
394                    }
395
396                    SearchControls scts = new SearchControls();
397                    if ("onelevel".equals(searchScope)) {
398                        scts.setSearchScope(SearchControls.ONELEVEL_SCOPE);
399                    } else {
400                        scts.setSearchScope(SearchControls.SUBTREE_SCOPE);
401                    }
402                    String filter = String.format("(&(%s)(objectClass=%s))",
403                            searchFilter.isEmpty() ? "objectClass=*" : searchFilter,
404                            searchClass.isEmpty() ? "*" : searchClass);
405                    NamingEnumeration<SearchResult> results;
406                    try {
407                        results = dirContext.search(searchBaseDn, filter, scts);
408                        if (!results.hasMore()) {
409                            ctx.trackError("nuxeo.ldap.search", "error.ldap.noresult");
410                        } else {
411                            SearchResult result = results.next();
412                            if (searchBaseDn.equalsIgnoreCase(result.getNameInNamespace()) && results.hasMore()) {
413                                // try not to display the root of the search
414                                // base DN
415                                result = results.next();
416                            }
417                            ctx.trackInfo("dn", result.getNameInNamespace());
418                            Attributes attributes = result.getAttributes();
419                            NamingEnumeration<String> ids = attributes.getIDs();
420                            String id;
421                            StringBuilder sb;
422                            while (ids.hasMore()) {
423                                id = ids.next();
424                                NamingEnumeration<?> values = attributes.get(id).getAll();
425                                sb = new StringBuilder();
426                                while (values.hasMore()) {
427                                    sb.append(values.next()).append(" , ");
428                                }
429                                ctx.trackInfo(id, sb.substring(0, sb.length() - 3));
430                            }
431                        }
432                    } catch (NameNotFoundException e) {
433                        ctx.trackError("nuxeo.ldap.search", "error.ldap.searchBaseDn");
434                        log.warn(e);
435                    }
436                    dirContext.close();
437                }
438            } catch (AuthenticationException e) {
439                ctx.trackError("nuxeo.ldap.auth", "error.auth.failed");
440                log.warn(e);
441            } catch (NamingException e) {
442                ctx.trackError("nuxeo.ldap.url", "error.host.not.found");
443                log.warn(e);
444            }
445        }
446
447        // Form submit
448        if (!"default".equals(directoryType) && refreshParam.isEmpty()) {
449            // first check bind to LDAP server
450            try {
451                bindLdapConnection(collector, true);
452            } catch (NamingException e) {
453                ctx.trackError("nuxeo.ldap.auth", "error.ldap.bind.failed");
454                log.warn(e);
455            }
456
457            // then check mandatory fields
458            if (collector.getConfigurationParam("nuxeo.ldap.user.searchBaseDn").isEmpty()) {
459                ctx.trackError("nuxeo.ldap.user.searchBaseDn", "error.user.searchBaseDn.required");
460            }
461            if (collector.getConfigurationParam("nuxeo.ldap.user.mapping.rdn").isEmpty()) {
462                ctx.trackError("nuxeo.ldap.user.mapping.rdn", "error.user.rdn.required");
463            }
464            if (collector.getConfigurationParam("nuxeo.ldap.user.mapping.username").isEmpty()) {
465                ctx.trackError("nuxeo.ldap.user.mapping.username", "error.user.username.required");
466            }
467            if (collector.getConfigurationParam("nuxeo.ldap.user.mapping.password").isEmpty()) {
468                ctx.trackError("nuxeo.ldap.user.mapping.password", "error.user.password.required");
469            }
470            if (collector.getConfigurationParam("nuxeo.ldap.user.mapping.firstname").isEmpty()) {
471                ctx.trackError("nuxeo.ldap.user.mapping.firstname", "error.user.firstname.required");
472            }
473            if (collector.getConfigurationParam("nuxeo.ldap.user.mapping.lastname").isEmpty()) {
474                ctx.trackError("nuxeo.ldap.user.mapping.lastname", "error.user.lastname.required");
475            }
476            String userGroupStorage = collector.getConfigurationParam("nuxeo.user.group.storage");
477            if (!"userLdapOnly".equals(userGroupStorage) && !"multiUserSqlGroup".equals(userGroupStorage)) {
478                if (collector.getConfigurationParam("nuxeo.ldap.group.searchBaseDn").isEmpty()) {
479                    ctx.trackError("nuxeo.ldap.group.searchBaseDn", "error.group.searchBaseDn.required");
480                }
481                if (collector.getConfigurationParam("nuxeo.ldap.group.mapping.rdn").isEmpty()) {
482                    ctx.trackError("nuxeo.ldap.group.mapping.rdn", "error.group.rdn.required");
483                }
484                if (collector.getConfigurationParam("nuxeo.ldap.group.mapping.name").isEmpty()) {
485                    ctx.trackError("nuxeo.ldap.group.mapping.name", "error.group.name.required");
486                }
487            }
488            if ("true".equals(collector.getConfigurationParam("nuxeo.user.emergency.enable"))) {
489                if (collector.getConfigurationParam("nuxeo.user.emergency.username").isEmpty()) {
490                    ctx.trackError("nuxeo.user.emergency.username", "error.emergency.username.required");
491                }
492                if (collector.getConfigurationParam("nuxeo.user.emergency.password").isEmpty()) {
493                    ctx.trackError("nuxeo.user.emergency.password", "error.emergency.password.required");
494                }
495            }
496        }
497
498        if (ctx.hasErrors() || ctx.hasInfos()) {
499            currentPage.dispatchToJSP(req, resp);
500        } else {
501            currentPage.next().dispatchToJSP(req, resp, true);
502        }
503    }
504
505    private Hashtable<Object, Object> getContextEnv(ParamCollector collector, boolean checkAuth) {
506        String ldapUrl = collector.getConfigurationParam("nuxeo.ldap.url");
507        String ldapBindDn = collector.getConfigurationParam("nuxeo.ldap.binddn");
508        String ldapBindPassword = collector.getConfigurationParam("nuxeo.ldap.bindpassword");
509        ConfigurationGenerator cg = collector.getConfigurationGenerator();
510        return cg.getContextEnv(ldapUrl, ldapBindDn, ldapBindPassword, checkAuth);
511    }
512
513    private void bindLdapConnection(ParamCollector collector, boolean authenticate) throws NamingException {
514        ConfigurationGenerator cg = collector.getConfigurationGenerator();
515        cg.checkLdapConnection(getContextEnv(collector, authenticate));
516    }
517
518    public void handleSmtpPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
519            throws ServletException, IOException {
520
521        Context ctx = Context.instance(req);
522        ParamCollector collector = ctx.getCollector();
523
524        if (collector.getConfigurationParam("mail.transport.auth").equals("true")) {
525            if (collector.getConfigurationParam("mail.transport.user").isEmpty()) {
526                ctx.trackError("mail.transport.user", "error.mail.transport.user.required");
527            }
528            if (collector.getConfigurationParam("mail.transport.password").isEmpty()) {
529                ctx.trackError("mail.transport.password", "error.mail.transport.password.required");
530            }
531        }
532
533        if (!collector.getConfigurationParam("mail.transport.port").isEmpty()) {
534            if (!NumberValidator.validate(collector.getConfigurationParam("mail.transport.port"))) {
535                ctx.trackError("mail.transport.port", "error.mail.transport.port.mustbeanumber");
536            }
537        }
538
539        if (ctx.hasErrors()) {
540            currentPage.dispatchToJSP(req, resp);
541        } else {
542            currentPage.next().dispatchToJSP(req, resp, true);
543        }
544    }
545
546    public void handleRecapPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
547            throws ServletException, IOException {
548        Context ctx = Context.instance(req);
549        ParamCollector collector = ctx.getCollector();
550        ConfigurationGenerator cg = collector.getConfigurationGenerator();
551
552        // Mark package selection done
553        PackageDownloaderHelper.markPackageSelectionDone(ctx);
554
555        Map<String, String> changedParameters = collector.getConfigurationParams();
556        changedParameters.put(PARAM_WIZARD_DONE, "true");
557        try {
558            // save config
559            cg.saveFilteredConfiguration(changedParameters);
560
561            // // => page will trigger the restart
562            // new Page("", "reStarting.jsp").dispatchToJSP(req, resp);
563            currentPage.next().dispatchToJSP(req, resp, true);
564        } catch (ConfigurationException e) {
565            log.error("Could not save wizard parameters.", e);
566            currentPage.dispatchToJSP(req, resp);
567        }
568    }
569
570    public void handleGeneralPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
571            throws ServletException, IOException {
572        Context ctx = Context.instance(req);
573        ParamCollector collector = ctx.getCollector();
574        String bindAddress = collector.getConfigurationParamValue(PARAM_BIND_ADDRESS);
575        if (bindAddress != null && !bindAddress.isEmpty()) {
576            if (!IPValidator.validate(bindAddress)) {
577                ctx.trackError(PARAM_BIND_ADDRESS, "error.invalid.ip");
578            }
579            try {
580                InetAddress inetAddress = ConfigurationGenerator.getBindAddress(bindAddress);
581                ConfigurationGenerator.checkAddressReachable(inetAddress);
582            } catch (ConfigurationException e) {
583                ctx.trackError(PARAM_BIND_ADDRESS, "error.already.used.ip");
584            }
585        }
586
587        if (ctx.hasErrors()) {
588            currentPage.dispatchToJSP(req, resp);
589        } else {
590            currentPage.next().dispatchToJSP(req, resp, true);
591        }
592    }
593
594    public void handleHomeGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
595            throws ServletException, IOException {
596        Context ctx = Context.instance(req);
597        if (PackageDownloaderHelper.isPackageSelectionDone(ctx)) {
598            navHandler.deactivatePage("PackagesSelection");
599            navHandler.deactivatePage("PackagesDownload");
600            navHandler.activatePage("PackagesSelectionDone");
601        }
602        handleDefaultGET(currentPage, req, resp);
603    }
604
605    public void handleHomePOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
606            throws ServletException, IOException {
607        String baseUrl = req.getParameter("baseUrl");
608        if (baseUrl != null && !baseUrl.isEmpty()) {
609            if (baseUrl.endsWith("Home")) {
610                baseUrl = baseUrl.substring(0, baseUrl.length() - 4);
611                Context.instance(req).setBaseUrl(baseUrl);
612            }
613        }
614
615        String browserInternetAccess = req.getParameter("browserInternetAccess");
616        if ("true".equals(browserInternetAccess)) {
617            Context.instance(req).setBrowserInternetAccess(true);
618            SimpleNavigationHandler.instance().deactivatePage("NetworkBlocked");
619            SimpleNavigationHandler.instance().activatePage("Connect");
620        } else {
621            Context.instance(req).setBrowserInternetAccess(false);
622            SimpleNavigationHandler.instance().activatePage("NetworkBlocked");
623            SimpleNavigationHandler.instance().deactivatePage("Connect");
624        }
625
626        currentPage.next().dispatchToJSP(req, resp, true);
627    }
628
629    public void handleProxyPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
630            throws ServletException, IOException {
631        Context ctx = Context.instance(req);
632        ParamCollector collector = ctx.getCollector();
633        String proxyType = collector.getConfigurationParamValue("nuxeo.http.proxy.type");
634        if ("none".equals(proxyType)) {
635            collector.addConfigurationParam("nuxeo.http.proxy.type", null);
636            collector.addConfigurationParam("nuxeo.http.proxy.login", null);
637            collector.addConfigurationParam("nuxeo.http.proxy.password", null);
638            collector.addConfigurationParam("nuxeo.http.proxy.host", null);
639            collector.addConfigurationParam("nuxeo.http.proxy.port", null);
640            collector.addConfigurationParam("nuxeo.http.proxy.ntml.host", null);
641            collector.addConfigurationParam("nuxeo.http.proxy.ntml.domain", null);
642            if (!PackageDownloaderHelper.isPackageSelectionDone(ctx)) {
643                PackageDownloader.instance().setProxy(null, 0, null, null, null, null);
644            }
645        } else {
646            if (!NumberValidator.validate(collector.getConfigurationParam("nuxeo.http.proxy.port"))) {
647                ctx.trackError("nuxeo.http.proxy.port", "error.nuxeo.http.proxy.port");
648            }
649            if (collector.getConfigurationParam("nuxeo.http.proxy.host").isEmpty()) {
650                ctx.trackError("nuxeo.http.proxy.host", "error.nuxeo.http.proxy.emptyHost");
651            }
652            if ("anonymous".equals(proxyType)) {
653                collector.addConfigurationParam("nuxeo.http.proxy.login", null);
654                collector.addConfigurationParam("nuxeo.http.proxy.password", null);
655                collector.addConfigurationParam("nuxeo.http.proxy.ntml.host", null);
656                collector.addConfigurationParam("nuxeo.http.proxy.ntml.domain", null);
657
658                if (!ctx.hasErrors()) {
659                    if (!PackageDownloaderHelper.isPackageSelectionDone(ctx)) {
660                        PackageDownloader.instance().setProxy(
661                                collector.getConfigurationParamValue("nuxeo.http.proxy.host"),
662                                Integer.parseInt(collector.getConfigurationParamValue("nuxeo.http.proxy.port")), null,
663                                null, null, null);
664                    }
665                }
666            } else {
667                if (collector.getConfigurationParam("nuxeo.http.proxy.login").isEmpty()) {
668                    ctx.trackError("nuxeo.http.proxy.login", "error.nuxeo.http.proxy.emptyLogin");
669                } else {
670                    if (!ctx.hasErrors()) {
671                        if (!PackageDownloaderHelper.isPackageSelectionDone(ctx)) {
672                            PackageDownloader.instance().setProxy(
673                                    collector.getConfigurationParamValue("nuxeo.http.proxy.host"),
674                                    Integer.parseInt(collector.getConfigurationParamValue("nuxeo.http.proxy.port")),
675                                    collector.getConfigurationParamValue("nuxeo.http.proxy.login"),
676                                    collector.getConfigurationParamValue("nuxeo.http.proxy.password"),
677                                    collector.getConfigurationParamValue("nuxeo.http.proxy.ntlm.host"),
678                                    collector.getConfigurationParamValue("nuxeo.http.proxy.ntml.domain"));
679                        }
680                    }
681                }
682            }
683        }
684
685        if (ctx.hasErrors()) {
686            currentPage.dispatchToJSP(req, resp);
687        } else {
688            currentPage.next().dispatchToJSP(req, resp, true);
689        }
690    }
691
692    public void handleResetGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp) throws IOException {
693        // reset
694        Context.reset();
695        SimpleNavigationHandler.reset();
696        PackageDownloader.reset();
697
698        // return to first page
699        String target = "/" + req.getContextPath() + "/"
700                + SimpleNavigationHandler.instance().getDefaultPage().getAction();
701        if (target.startsWith("//")) {
702            target = target.substring(1);
703        }
704        resp.sendRedirect(target);
705    }
706
707    public void handlePackageOptionsResourceGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
708            throws IOException {
709        DownloadablePackageOptions options = PackageDownloader.instance().getPackageOptions();
710        resp.setContentType("text/json");
711        resp.getWriter().write(options.asJson());
712    }
713
714    public void handlePackagesSelectionGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
715            throws ServletException, IOException {
716        handleDefaultGET(currentPage, req, resp);
717    }
718
719    public void handlePackagesSelectionPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
720            throws ServletException, IOException {
721        List<String> options = new ArrayList<>();
722        Enumeration<String> params = req.getParameterNames();
723        while (params.hasMoreElements()) {
724            String p = params.nextElement();
725            if ("on".equals(req.getParameter(p))) {
726                options.add(p);
727            }
728        }
729
730        PackageDownloader.instance().selectOptions(options);
731        currentPage.next().dispatchToJSP(req, resp, true);
732    }
733
734    public void handlePackagesDownloadGET(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
735            throws ServletException, IOException {
736        if ("true".equals(req.getParameter("startDownload"))) {
737            PackageDownloader.instance().startDownload();
738        } else if (req.getParameter("reStartDownload") != null) {
739            PackageDownloader.instance().reStartDownload(req.getParameter("reStartDownload"));
740        }
741        currentPage.dispatchToJSP(req, resp);
742    }
743
744    public void handlePackagesDownloadPOST(Page currentPage, HttpServletRequest req, HttpServletResponse resp)
745            throws ServletException, IOException {
746        ParamCollector collector = Context.instance(req).getCollector();
747
748        String installationFilePath = new File(collector.getConfigurationParam(NUXEO_DATA_DIR),
749                INSTALL_AFTER_RESTART).getAbsolutePath();
750
751        PackageDownloader.instance().scheduleDownloadedPackagesForInstallation(installationFilePath);
752        PackageDownloader.reset();
753        currentPage.next().dispatchToJSP(req, resp, true);
754    }
755
756}