/*
* Password Management Servlets (PWM)
* http://www.pwm-project.org
*
* Copyright (c) 2006-2009 Novell, Inc.
* Copyright (c) 2009-2017 The PWM Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package password.pwm.http.servlet.admin;
import com.novell.ldapchai.exception.ChaiUnavailableException;
import password.pwm.AppProperty;
import password.pwm.Permission;
import password.pwm.PwmApplication;
import password.pwm.PwmConstants;
import password.pwm.bean.UserIdentity;
import password.pwm.error.ErrorInformation;
import password.pwm.error.PwmError;
import password.pwm.error.PwmOperationalException;
import password.pwm.error.PwmUnrecoverableException;
import password.pwm.http.HttpMethod;
import password.pwm.http.JspUrl;
import password.pwm.http.ProcessStatus;
import password.pwm.http.PwmRequest;
import password.pwm.http.PwmRequestAttribute;
import password.pwm.http.PwmURL;
import password.pwm.http.bean.AdminBean;
import password.pwm.http.servlet.AbstractPwmServlet;
import password.pwm.http.servlet.ControlledPwmServlet;
import password.pwm.http.servlet.PwmServletDefinition;
import password.pwm.ldap.search.UserSearchEngine;
import password.pwm.svc.report.ReportColumnFilter;
import password.pwm.svc.report.ReportCsvUtility;
import password.pwm.svc.report.ReportService;
import password.pwm.svc.stats.StatisticsManager;
import password.pwm.util.java.JavaHelper;
import password.pwm.util.java.JsonUtil;
import password.pwm.util.java.StringUtil;
import password.pwm.util.localdb.LocalDBException;
import password.pwm.util.logging.PwmLogger;
import password.pwm.util.reports.ReportUtils;
import password.pwm.ws.server.RestResultBean;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
@WebServlet(
name = "AdminServlet",
urlPatterns = {
PwmConstants.URL_PREFIX_PRIVATE + "/admin",
PwmConstants.URL_PREFIX_PRIVATE + "/admin/*",
PwmConstants.URL_PREFIX_PRIVATE + "/admin/Administration",
}
)
public class AdminServlet extends ControlledPwmServlet {
private static final PwmLogger LOGGER = PwmLogger.forClass(AdminServlet.class);
public enum AdminAction implements AbstractPwmServlet.ProcessAction {
viewLogWindow(HttpMethod.GET),
downloadAuditLogCsv(HttpMethod.POST),
downloadUserReportCsv(HttpMethod.POST),
downloadUserSummaryCsv(HttpMethod.POST),
downloadStatisticsLogCsv(HttpMethod.POST),
clearIntruderTable(HttpMethod.POST),
reportCommand(HttpMethod.POST),
reportStatus(HttpMethod.GET),
reportSummary(HttpMethod.GET),
downloadUserDebug(HttpMethod.GET),
;
private final Collection<HttpMethod> method;
AdminAction(final HttpMethod... method)
{
this.method = Collections.unmodifiableList(Arrays.asList(method));
}
public Collection<HttpMethod> permittedMethods()
{
return method;
}
}
@Override
public Class<? extends ProcessAction> getProcessActionsClass()
{
return AdminAction.class;
}
@Override
protected void nextStep(final PwmRequest pwmRequest) throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException
{
forwardToJsp(pwmRequest);
}
@Override
public ProcessStatus preProcessCheck(final PwmRequest pwmRequest) throws PwmUnrecoverableException, IOException, ServletException
{
if (!pwmRequest.isAuthenticated()) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_AUTHENTICATION_REQUIRED);
pwmRequest.respondWithError(errorInformation);
return ProcessStatus.Halt;
}
if (!pwmRequest.getPwmSession().getSessionManager().checkPermission(pwmRequest.getPwmApplication(), Permission.PWMADMIN)) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNAUTHORIZED);
pwmRequest.respondWithError(errorInformation);
return ProcessStatus.Halt;
}
return ProcessStatus.Continue;
}
@ActionHandler(action = "viewLogWindow")
private ProcessStatus processViewLogWindow(
final PwmRequest pwmRequest
)
throws PwmUnrecoverableException, IOException, ServletException
{
pwmRequest.forwardToJsp(JspUrl.ADMIN_LOGVIEW_WINDOW);
return ProcessStatus.Halt;
}
@ActionHandler(action = "downloadAuditLogCsv")
private ProcessStatus downloadAuditLogCsv(
final PwmRequest pwmRequest
)
throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
pwmRequest.getPwmResponse().markAsDownload(
PwmConstants.ContentTypeValue.csv,
pwmApplication.getConfig().readAppProperty(AppProperty.DOWNLOAD_FILENAME_AUDIT_RECORDS_CSV)
);
final OutputStream outputStream = pwmRequest.getPwmResponse().getOutputStream();
try {
pwmApplication.getAuditManager().outputVaultToCsv(outputStream, pwmRequest.getLocale(), true);
} catch (Exception e) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN,e.getMessage());
pwmRequest.respondWithError(errorInformation);
} finally {
outputStream.close();
}
return ProcessStatus.Halt;
}
@ActionHandler(action = "downloadUserReportCsv")
private ProcessStatus downloadUserReportCsv(
final PwmRequest pwmRequest
)
throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
pwmRequest.getPwmResponse().markAsDownload(
PwmConstants.ContentTypeValue.csv,
pwmApplication.getConfig().readAppProperty(AppProperty.DOWNLOAD_FILENAME_USER_REPORT_RECORDS_CSV)
);
final OutputStream outputStream = pwmRequest.getPwmResponse().getOutputStream();
try {
final String selectedColumns = pwmRequest.readParameterAsString("selectedColumns", "");
final ReportColumnFilter columnFilter = ReportUtils.toReportColumnFilter(selectedColumns);
final ReportCsvUtility reportCsvUtility = new ReportCsvUtility(pwmApplication);
reportCsvUtility.outputToCsv(outputStream, true, pwmRequest.getLocale(), columnFilter);
} catch (Exception e) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN,e.getMessage());
pwmRequest.respondWithError(errorInformation);
} finally {
outputStream.close();
}
return ProcessStatus.Halt;
}
@ActionHandler(action = "downloadUserSummaryCsv")
private ProcessStatus downloadUserSummaryCsv(
final PwmRequest pwmRequest
)
throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
pwmRequest.getPwmResponse().markAsDownload(
PwmConstants.ContentTypeValue.csv,
pwmApplication.getConfig().readAppProperty(AppProperty.DOWNLOAD_FILENAME_USER_REPORT_SUMMARY_CSV)
);
final OutputStream outputStream = pwmRequest.getPwmResponse().getOutputStream();
try {
final ReportCsvUtility reportCsvUtility = new ReportCsvUtility(pwmApplication);
reportCsvUtility.outputSummaryToCsv(outputStream, pwmRequest.getLocale());
} catch (Exception e) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN,e.getMessage());
pwmRequest.respondWithError(errorInformation);
} finally {
outputStream.close();
}
return ProcessStatus.Halt;
}
@ActionHandler(action = "downloadStatisticsLogCsv")
private ProcessStatus downloadStatisticsLogCsv(final PwmRequest pwmRequest)
throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
pwmRequest.getPwmResponse().markAsDownload(
PwmConstants.ContentTypeValue.csv,
pwmRequest.getPwmApplication().getConfig().readAppProperty(AppProperty.DOWNLOAD_FILENAME_STATISTICS_CSV)
);
final OutputStream outputStream = pwmRequest.getPwmResponse().getOutputStream();
try {
final StatisticsManager statsManager = pwmApplication.getStatisticsManager();
statsManager.outputStatsToCsv(outputStream, pwmRequest.getLocale(), true);
} catch (Exception e) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNKNOWN,e.getMessage());
pwmRequest.respondWithError(errorInformation);
} finally {
outputStream.close();
}
return ProcessStatus.Halt;
}
@ActionHandler(action = "clearIntruderTable")
private ProcessStatus processClearIntruderTable(
final PwmRequest pwmRequest
)
throws ChaiUnavailableException, PwmUnrecoverableException, IOException, ServletException
{
if (!pwmRequest.getPwmSession().getSessionManager().checkPermission(pwmRequest.getPwmApplication(), Permission.PWMADMIN)) {
LOGGER.info(pwmRequest, "unable to execute clear intruder records");
return ProcessStatus.Halt;
}
//pwmApplication.getIntruderManager().clear();
final RestResultBean restResultBean = new RestResultBean();
pwmRequest.outputJsonResult(restResultBean);
return ProcessStatus.Halt;
}
@ActionHandler(action = "reportCommand")
private ProcessStatus processReportCommand(final PwmRequest pwmRequest) throws PwmUnrecoverableException, IOException {
final ReportService.ReportCommand reportCommand = JavaHelper.readEnumFromString(
ReportService.ReportCommand.class,
null,
pwmRequest.readParameterAsString("command")
);
LOGGER.trace(pwmRequest, "issuing command '" + reportCommand + "' to report engine");
pwmRequest.getPwmApplication().getReportService().executeCommand(reportCommand);
final RestResultBean restResultBean = new RestResultBean();
pwmRequest.outputJsonResult(restResultBean);
return ProcessStatus.Halt;
}
@ActionHandler(action = "reportStatus")
private ProcessStatus processReportStatus(final PwmRequest pwmRequest)
throws ChaiUnavailableException, PwmUnrecoverableException, IOException {
try {
final ReportStatusBean returnMap = ReportStatusBean.makeReportStatusData(
pwmRequest.getPwmApplication().getReportService(),
pwmRequest.getPwmSession().getSessionStateBean().getLocale()
);
final RestResultBean restResultBean = new RestResultBean();
restResultBean.setData(returnMap);
pwmRequest.outputJsonResult(restResultBean);
} catch (LocalDBException e) {
throw new PwmUnrecoverableException(e.getErrorInformation());
}
return ProcessStatus.Halt;
}
@ActionHandler(action = "reportSummary")
private ProcessStatus processReportSummary(final PwmRequest pwmRequest)
throws ChaiUnavailableException, PwmUnrecoverableException, IOException {
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final LinkedHashMap<String,Object> returnMap = new LinkedHashMap<>();
returnMap.put("raw",pwmApplication.getReportService().getSummaryData());
returnMap.put("presentable", pwmApplication.getReportService().getSummaryData().asPresentableCollection(
pwmApplication.getConfig(),
pwmRequest.getPwmSession().getSessionStateBean().getLocale()
));
final RestResultBean restResultBean = new RestResultBean();
restResultBean.setData(returnMap);
pwmRequest.outputJsonResult(restResultBean);
return ProcessStatus.Halt;
}
@ActionHandler(action = "downloadUserDebug")
private ProcessStatus processDownloadUserDebug(final PwmRequest pwmRequest)
throws ChaiUnavailableException, PwmUnrecoverableException, IOException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final AdminBean adminBean = pwmRequest.getPwmApplication().getSessionStateService().getBean(pwmRequest, AdminBean.class);
final UserIdentity userIdentity = adminBean.getLastUserDebug();
if (userIdentity != null) {
pwmRequest.getPwmResponse().markAsDownload(
PwmConstants.ContentTypeValue.json,
pwmApplication.getConfig().readAppProperty(AppProperty.DOWNLOAD_FILENAME_USER_DEBUG_JSON)
);
final UserDebugDataBean userDebugData = UserDebugDataReader.readUserDebugData(pwmRequest.getPwmApplication(), pwmRequest.getLocale(), pwmRequest.getSessionLabel(), userIdentity);
final String output = JsonUtil.serialize(userDebugData, JsonUtil.Flag.PrettyPrint);
pwmRequest.getPwmResponse().getOutputStream().write(output.getBytes(PwmConstants.DEFAULT_CHARSET));
} else {
pwmRequest.respondWithError(new ErrorInformation(PwmError.ERROR_UNKNOWN, "no previously searched user available for download"));
}
return ProcessStatus.Halt;
}
private void processDebugUserSearch(final PwmRequest pwmRequest)
throws PwmUnrecoverableException
{
final String username = pwmRequest.readParameterAsString("username");
if (StringUtil.isEmpty(username)) {
return;
}
final UserSearchEngine userSearchEngine = pwmRequest.getPwmApplication().getUserSearchEngine();
final UserIdentity userIdentity;
try {
userIdentity = userSearchEngine.resolveUsername(username,null,null, pwmRequest.getSessionLabel());
final AdminBean adminBean = pwmRequest.getPwmApplication().getSessionStateService().getBean(pwmRequest, AdminBean.class);
adminBean.setLastUserDebug(userIdentity);
} catch (ChaiUnavailableException e) {
setLastError(pwmRequest, PwmUnrecoverableException.fromChaiException(e).getErrorInformation());
return;
} catch (PwmOperationalException e) {
setLastError(pwmRequest, e.getErrorInformation());
return;
}
final UserDebugDataBean userDebugData = UserDebugDataReader.readUserDebugData(pwmRequest.getPwmApplication(), pwmRequest.getLocale(), pwmRequest.getSessionLabel(), userIdentity);
pwmRequest.setAttribute(PwmRequestAttribute.UserDebugData, userDebugData);
}
private void forwardToJsp(final PwmRequest pwmRequest) throws ServletException, PwmUnrecoverableException, IOException {
final Page currentPage = Page.forUrl(pwmRequest.getURL());
if (currentPage == Page.debugUser) {
processDebugUserSearch(pwmRequest);
}
if (currentPage != null) {
pwmRequest.forwardToJsp(currentPage.getJspURL());
return;
}
pwmRequest.sendRedirect(pwmRequest.getContextPath() + PwmServletDefinition.Admin.servletUrl() + Page.dashboard.getUrlSuffix());
}
public enum Page {
dashboard(JspUrl.ADMIN_DASHBOARD,"/dashboard"),
analysis(JspUrl.ADMIN_ANALYSIS,"/analysis"),
activity(JspUrl.ADMIN_ACTIVITY,"/activity"),
tokenLookup(JspUrl.ADMIN_TOKEN_LOOKUP,"/tokens"),
viewLog(JspUrl.ADMIN_LOGVIEW,"/logs"),
urlReference(JspUrl.ADMIN_URLREFERENCE,"/urls"),
debugUser(JspUrl.ADMIN_DEBUG,"/userdebug"),
;
private final JspUrl jspURL;
private final String urlSuffix;
Page(final JspUrl jspURL, final String urlSuffix) {
this.jspURL = jspURL;
this.urlSuffix = urlSuffix;
}
public JspUrl getJspURL() {
return jspURL;
}
public String getUrlSuffix() {
return urlSuffix;
}
public static Page forUrl(final PwmURL pwmURL) {
final String url = pwmURL.toString();
for (final Page page : Page.values()) {
if (url.endsWith(page.urlSuffix)) {
return page;
}
}
return null;
}
}
}