From 092dbd87a2d6aacd97ccbdcf6c3494ffc0e24dde Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Tue, 31 Aug 2010 20:07:13 +0000 Subject: [PATCH] ALF-4106: WS call to clear audit entries - /api/audit/clear/{application}?fromTime={fromTime}&toTime={toTime} git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@22110 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repository/audit/clear.post.desc.xml | 27 ++++++++ .../repository/audit/clear.post.json.ftl | 3 + .../repository/audit/control.properties | 1 + .../repository/audit/query.get.desc.xml | 27 ++++++++ .../web-scripts-application-context.xml | 16 +++-- .../scripts/audit/AbstractAuditWebScript.java | 29 ++++++++ .../web/scripts/audit/AuditClearPost.java | 67 ++++++++++++++++++ .../web/scripts/audit/AuditControlGet.java | 2 +- .../web/scripts/audit/AuditWebScriptTest.java | 68 +++++++++++++++++++ 9 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.json.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/repository/audit/query.get.desc.xml create mode 100644 source/java/org/alfresco/repo/web/scripts/audit/AuditClearPost.java diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.desc.xml new file mode 100644 index 0000000000..e6e9c1de37 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.desc.xml @@ -0,0 +1,27 @@ + + Alfresco Audit Service Clear + Delete audit entries for a given application and time range + /api/audit/clear/{application}?fromTime={fromTime}&toTime={toTime} + + admin + required + internal + + + application + Name of the audit application (mandatory) + + + fromTime + Time, in milliseconds, of the oldest audit entry to delete (omit to assume oldest) + + + toTime + Time, in milleseconds, of the youngest audit entry to delete (omit to assume current time) + + + + + + + diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.json.ftl new file mode 100644 index 0000000000..7c5ee644c4 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/clear.post.json.ftl @@ -0,0 +1,3 @@ +{ + "cleared" : ${cleared} +} diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties index 2d6356d41b..d81c76d834 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties @@ -1,4 +1,5 @@ # Audit Control Web Script I18N +audit.err.app.notProvided=Application name not supplied. audit.err.app.notFound=Application not found: {0} audit.err.path.notProvided=No path was supplied after the application name. audit.err.action.invalid=Parameter 'action' must be either 'enable' or 'disable' \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/query.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/query.get.desc.xml new file mode 100644 index 0000000000..7955d406b7 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/query.get.desc.xml @@ -0,0 +1,27 @@ + + Alfresco Audit Service Query + Get audit events + /api/audit/query/{application}?{k1}={v1},{k2}={v2} + + admin + required + internal + + + application + Name of the audit application (mandatory parameter) + + + k1 + First key to query for. If no value is provided, then the present of the key is enough. + + + v1 + First value to query for. If this is no provided, then the presence of the key is enough. + + + + + + + diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 0fd4c5e568..b98321d7dd 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -28,6 +28,13 @@ + + + + + @@ -859,11 +866,10 @@ parent="abstractAuditWebScript"> - - - + + diff --git a/source/java/org/alfresco/repo/web/scripts/audit/AbstractAuditWebScript.java b/source/java/org/alfresco/repo/web/scripts/audit/AbstractAuditWebScript.java index 926e4bdb3a..af90c99def 100644 --- a/source/java/org/alfresco/repo/web/scripts/audit/AbstractAuditWebScript.java +++ b/source/java/org/alfresco/repo/web/scripts/audit/AbstractAuditWebScript.java @@ -38,11 +38,14 @@ public abstract class AbstractAuditWebScript extends DeclarativeWebScript public static final String PARAM_APPLICATION = "application"; public static final String PARAM_PATH="path"; public static final String PARAM_ENABLED = "enabled"; + public static final String PARAM_FROM_TIME = "fromTime"; + public static final String PARAM_TO_TIME = "toTime"; public static final String JSON_KEY_ENABLED = "enabled"; public static final String JSON_KEY_APPLICATIONS = "applications"; public static final String JSON_KEY_NAME = "name"; public static final String JSON_KEY_PATH = "path"; + public static final String JSON_KEY_CLEARED = "cleared"; /** * Logger that can be used by subclasses. @@ -113,4 +116,30 @@ public abstract class AbstractAuditWebScript extends DeclarativeWebScript String enableStr = req.getParameter(PARAM_ENABLED); return Boolean.parseBoolean(enableStr); } + + protected Long getFromTime(WebScriptRequest req) + { + String timeStr = req.getParameter(PARAM_FROM_TIME); + try + { + return Long.parseLong(timeStr); + } + catch (NumberFormatException e) + { + return null; + } + } + + protected Long getToTime(WebScriptRequest req) + { + String timeStr = req.getParameter(PARAM_TO_TIME); + try + { + return Long.parseLong(timeStr); + } + catch (NumberFormatException e) + { + return null; + } + } } diff --git a/source/java/org/alfresco/repo/web/scripts/audit/AuditClearPost.java b/source/java/org/alfresco/repo/web/scripts/audit/AuditClearPost.java new file mode 100644 index 0000000000..78d64fcda4 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/audit/AuditClearPost.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.web.scripts.audit; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.service.cmr.audit.AuditService.AuditApplication; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * @author Derek Hulley + * @since 3.4 + */ +public class AuditClearPost extends AbstractAuditWebScript +{ + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(7); + + String appName = getAppName(req); + if (appName == null) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, "audit.err.app.notProvided"); + } + AuditApplication app = auditService.getAuditApplications().get(appName); + if (app == null) + { + throw new WebScriptException(Status.STATUS_NOT_FOUND, "audit.err.app.notFound", appName); + } + // Get from/to times + Long fromTime = getFromTime(req); // might be null + Long toTime = getToTime(req); // might be null + + // Clear + int cleared = auditService.clearAudit(appName, fromTime, toTime); + + model.put(JSON_KEY_CLEARED, cleared); + + // Done + if (logger.isDebugEnabled()) + { + logger.debug("Result: \n\tRequest: " + req + "\n\tModel: " + model); + } + return model; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/audit/AuditControlGet.java b/source/java/org/alfresco/repo/web/scripts/audit/AuditControlGet.java index c2cf5adf6c..ca99404c94 100644 --- a/source/java/org/alfresco/repo/web/scripts/audit/AuditControlGet.java +++ b/source/java/org/alfresco/repo/web/scripts/audit/AuditControlGet.java @@ -55,7 +55,7 @@ public class AuditControlGet extends AbstractAuditWebScript AuditApplication app = appsByName.get(appName); if (app == null) { - throw new WebScriptException(Status.STATUS_NOT_FOUND, "audit.err.app.notFound", app); + throw new WebScriptException(Status.STATUS_NOT_FOUND, "audit.err.app.notFound", appName); } // Discard all the other applications appsByName = Collections.singletonMap(appName, app); diff --git a/source/java/org/alfresco/repo/web/scripts/audit/AuditWebScriptTest.java b/source/java/org/alfresco/repo/web/scripts/audit/AuditWebScriptTest.java index 40c2430960..f76212de55 100644 --- a/source/java/org/alfresco/repo/web/scripts/audit/AuditWebScriptTest.java +++ b/source/java/org/alfresco/repo/web/scripts/audit/AuditWebScriptTest.java @@ -21,10 +21,13 @@ package org.alfresco.repo.web.scripts.audit; import java.util.Map; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.web.scripts.BaseWebScriptTest; import org.alfresco.service.cmr.audit.AuditService; import org.alfresco.service.cmr.audit.AuditService.AuditApplication; +import org.alfresco.service.cmr.security.AuthenticationService; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.context.ApplicationContext; @@ -42,6 +45,7 @@ public class AuditWebScriptTest extends BaseWebScriptTest { private ApplicationContext ctx; private AuditService auditService; + private AuthenticationService authenticationService; private String admin; private boolean globallyEnabled; @@ -50,6 +54,7 @@ public class AuditWebScriptTest extends BaseWebScriptTest { super.setUp(); ctx = getServer().getApplicationContext(); + authenticationService = (AuthenticationService) ctx.getBean("AuthenticationService"); auditService = (AuditService) ctx.getBean("AuditService"); admin = AuthenticationUtil.getAdminUserName(); @@ -205,4 +210,67 @@ public class AuditWebScriptTest extends BaseWebScriptTest } } } + + public void testClearAuditRepo() throws Exception + { + long now = System.currentTimeMillis(); + long future = Long.MAX_VALUE; + + + boolean wasRepoEnabled = auditService.isAuditEnabled(APP_REPO_NAME, APP_REPO_PATH); + boolean wasEnabled = auditService.isAuditEnabled(); + // We need to set this back after the test + try + { + auditService.setAuditEnabled(true); + auditService.enableAudit(APP_REPO_NAME, APP_REPO_PATH); + + // Force a failed login + RunAsWork failureWork = new RunAsWork() + { + @Override + public Void doWork() throws Exception + { + try + { + authenticationService.authenticate("domino", "crud".toCharArray()); + fail("Failed to force authentication failure"); + } + catch (AuthenticationException e) + { + // Expected + } + return null; + } + }; + AuthenticationUtil.runAs(failureWork, AuthenticationUtil.getSystemUserName()); + + // Delete audit entries that could not have happened + String url = "/api/audit/clear/" + APP_REPO_NAME + "?fromTime=" + future; + TestWebScriptServer.PostRequest req = new TestWebScriptServer.PostRequest(url, "", MimetypeMap.MIMETYPE_JSON); + Response response = sendRequest(req, Status.STATUS_OK, admin); + JSONObject json = new JSONObject(response.getContentAsString()); + int cleared = json.getInt(AbstractAuditWebScript.JSON_KEY_CLEARED); + assertEquals("Could not have cleared more than 0", 0, cleared); + + url = "/api/audit/clear/" + APP_REPO_NAME + "?fromTime=" + now + "&toTime=" + future; + req = new TestWebScriptServer.PostRequest(url, "", MimetypeMap.MIMETYPE_JSON); + response = sendRequest(req, Status.STATUS_OK, admin); + json = new JSONObject(response.getContentAsString()); + cleared = json.getInt(AbstractAuditWebScript.JSON_KEY_CLEARED); + assertTrue("Should have cleared at least 1 entry", cleared > 0); + } + finally + { + if (wasRepoEnabled) + { + auditService.enableAudit(APP_REPO_NAME, APP_REPO_PATH); + } + else + { + auditService.disableAudit(APP_REPO_NAME, APP_REPO_PATH); + } + auditService.setAuditEnabled(wasEnabled); + } + } }