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