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