From e244f2c93cf39097fa889ad9e99c85330ada7a08 Mon Sep 17 00:00:00 2001 From: Andrew Hind Date: Mon, 4 Sep 2006 19:12:55 +0000 Subject: [PATCH] Expose audit service as public service and in freemarker. Tests git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3683 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco/repo/audit/AuditComponent.java | 11 + .../repo/audit/AuditComponentImpl.java | 73 +++-- .../org/alfresco/repo/audit/AuditDAO.java | 13 + .../alfresco/repo/audit/AuditServiceImpl.java | 29 +- .../alfresco/repo/audit/AuditServiceTest.java | 291 ++++++++++++++++++ .../repo/audit/hibernate/Audit.hbm.xml | 14 + .../repo/audit/hibernate/AuditConfigImpl.java | 4 +- .../repo/audit/hibernate/AuditDateImpl.java | 4 +- .../repo/audit/hibernate/AuditFactImpl.java | 17 + .../repo/audit/hibernate/AuditInfoImpl.java | 224 ++++++++++++++ .../repo/audit/hibernate/AuditSource.java | 6 + .../repo/audit/hibernate/AuditSourceImpl.java | 8 +- .../audit/hibernate/HibernateAuditDAO.java | 78 ++++- .../repo/audit/model/AbstractAuditEntry.java | 2 +- .../service/ServiceDescriptorRegistry.java | 9 + .../org/alfresco/service/ServiceRegistry.java | 8 + .../alfresco/service/cmr/audit/AuditInfo.java | 4 +- .../service/cmr/repository/NodeService.java | 2 +- .../service/cmr/repository/TemplateNode.java | 9 + 19 files changed, 753 insertions(+), 53 deletions(-) create mode 100644 source/java/org/alfresco/repo/audit/AuditServiceTest.java create mode 100644 source/java/org/alfresco/repo/audit/hibernate/AuditInfoImpl.java diff --git a/source/java/org/alfresco/repo/audit/AuditComponent.java b/source/java/org/alfresco/repo/audit/AuditComponent.java index 3b13c7e5f5..4fde6c0461 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponent.java +++ b/source/java/org/alfresco/repo/audit/AuditComponent.java @@ -16,6 +16,9 @@ */ package org.alfresco.repo.audit; +import java.util.List; + +import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.repository.NodeRef; import org.aopalliance.intercept.MethodInvocation; @@ -47,6 +50,14 @@ public interface AuditComponent * an arbitrary list of parameters */ public void audit(String source, String description, NodeRef key, Object... args); + + /** + * Get the audit trail for a node. + * + * @param nodeRef + * @return + */ + public List getAuditTrail(NodeRef nodeRef); } diff --git a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java index ae06c52778..6ee47e0c6d 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java +++ b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java @@ -21,12 +21,15 @@ import java.lang.reflect.Method; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Date; +import java.util.List; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.Auditable; import org.alfresco.service.NotAuditable; +import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -241,8 +244,7 @@ public class AuditComponentImpl implements AuditComponent * @param returnObject * @return */ - private AuditMode postInvocation(AuditMode auditMode, AuditState auditInfo, MethodInvocation mi, - Object returnObject) + private AuditMode postInvocation(AuditMode auditMode, AuditState auditInfo, MethodInvocation mi, Object returnObject) { if (returnObject == null) { @@ -260,14 +262,29 @@ public class AuditComponentImpl implements AuditComponent Auditable auditable = mi.getMethod().getAnnotation(Auditable.class); if (auditable.key() == Auditable.Key.RETURN) { - if ((returnObject != null) && (returnObject instanceof NodeRef)) + if (returnObject != null) { - NodeRef key = (NodeRef) returnObject; - auditInfo.setKeyStore(key.getStoreRef()); - auditInfo.setKeyGUID(key.getId()); + if (returnObject instanceof NodeRef) + { + NodeRef key = (NodeRef) returnObject; + auditInfo.setKeyStore(key.getStoreRef()); + auditInfo.setKeyGUID(key.getId()); + } + else if (returnObject instanceof StoreRef) + { + auditInfo.setKeyStore((StoreRef)returnObject); + } } } + // If the user name is not set, try and set it after the method call. + // This covers authentication when the user is only known after the call. + + if (auditInfo.getUserIdentifier() == null) + { + auditInfo.setUserIdentifier(AuthenticationUtil.getCurrentUserName()); + } + return auditMode; } @@ -334,10 +351,17 @@ public class AuditComponentImpl implements AuditComponent default: break; } - if ((key != null) && (key instanceof NodeRef)) + if (key != null) { - auditInfo.setKeyStore(((NodeRef) key).getStoreRef()); - auditInfo.setKeyGUID(((NodeRef) key).getId()); + if (key instanceof NodeRef) + { + auditInfo.setKeyStore(((NodeRef) key).getStoreRef()); + auditInfo.setKeyGUID(((NodeRef) key).getId()); + } + else if (key instanceof StoreRef) + { + auditInfo.setKeyStore((StoreRef) key); + } } auditInfo.setKeyPropertiesAfter(null); auditInfo.setKeyPropertiesBefore(null); @@ -347,17 +371,25 @@ public class AuditComponentImpl implements AuditComponent Serializable[] serArgs = new Serializable[mi.getArguments().length]; for (int i = 0; i < mi.getArguments().length; i++) { - if (mi.getArguments()[i] == null) + if ((auditable.recordable() == null) + || (auditable.recordable().length <= i) || auditable.recordable()[i]) { - serArgs[i] = null; - } - else if (mi.getArguments()[i] instanceof Serializable) - { - serArgs[i] = (Serializable) mi.getArguments()[i]; + if (mi.getArguments()[i] == null) + { + serArgs[i] = null; + } + else if (mi.getArguments()[i] instanceof Serializable) + { + serArgs[i] = (Serializable) mi.getArguments()[i]; + } + else + { + serArgs[i] = mi.getArguments()[i].toString(); + } } else { - serArgs[i] = mi.getArguments()[i].toString(); + serArgs[i] = "********"; } } auditInfo.setMethodArguments(serArgs); @@ -407,8 +439,13 @@ public class AuditComponentImpl implements AuditComponent } } - private AuditMode onApplicationAudit(AuditMode auditMode, AuditState auditInfo, String source, - String description, NodeRef key, Object... args) + public List getAuditTrail(NodeRef nodeRef) + { + return auditDAO.getAuditTrail(nodeRef); + } + + private AuditMode onApplicationAudit(AuditMode auditMode, AuditState auditInfo, String source, String description, + NodeRef key, Object... args) { AuditMode effectiveAuditMode = auditModel.beforeExecution(auditMode, source, description, key, args); diff --git a/source/java/org/alfresco/repo/audit/AuditDAO.java b/source/java/org/alfresco/repo/audit/AuditDAO.java index 2092be97df..e429784550 100644 --- a/source/java/org/alfresco/repo/audit/AuditDAO.java +++ b/source/java/org/alfresco/repo/audit/AuditDAO.java @@ -16,6 +16,11 @@ */ package org.alfresco.repo.audit; +import java.util.List; + +import org.alfresco.service.cmr.audit.AuditInfo; +import org.alfresco.service.cmr.repository.NodeRef; + /** * The interface to persist audit information. * @@ -29,4 +34,12 @@ public interface AuditDAO * @param auditInfo */ public void audit(AuditState auditInfo); + + /** + * Get the audit trail for a node. + * + * @param nodeRef + * @return + */ + public List getAuditTrail(NodeRef nodeRef); } diff --git a/source/java/org/alfresco/repo/audit/AuditServiceImpl.java b/source/java/org/alfresco/repo/audit/AuditServiceImpl.java index dbdd8b3d22..34c108e0c2 100644 --- a/source/java/org/alfresco/repo/audit/AuditServiceImpl.java +++ b/source/java/org/alfresco/repo/audit/AuditServiceImpl.java @@ -68,6 +68,11 @@ public class AuditServiceImpl implements AuditService auditComponent.audit(source, description, key, args); } + public List getAuditTrail(NodeRef nodeRef) + { + return auditComponent.getAuditTrail(nodeRef); + } + public static void main(String[] args) throws Exception { @@ -82,17 +87,25 @@ public class AuditServiceImpl implements AuditService try { + NodeRef nodeRef = new NodeRef(new StoreRef("test", "audit"), "id"); as.audit("AuditedApp", "First"); - as.audit("AuditedApp", "Second", new NodeRef(new StoreRef("test", "audit"), "id")); + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); + as.audit("AuditedApp", "Second", nodeRef); + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); as.audit("AuditedApp", "Third", new Object[] { "one", "two", "three" }); - as.audit("AuditedApp", "Fourth", new NodeRef(new StoreRef("test", "audit"), "id"), new Object[] { "one", + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); + as.audit("AuditedApp", "Fourth",nodeRef, new Object[] { "one", "two", "three" }); - + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); as.audit("UnAuditedApp", "First"); - as.audit("UnAuditedApp", "Second", new NodeRef(new StoreRef("test", "audit"), "id")); + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); + as.audit("UnAuditedApp", "Second", nodeRef); + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); as.audit("UnAuditedApp", "Third", new Object[] { "one", "two", "three" }); - as.audit("UnAuditedApp", "Fourth", new NodeRef(new StoreRef("test", "audit"), "id"), new Object[] { "one", + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); + as.audit("UnAuditedApp", "Fourth", nodeRef, new Object[] { "one", "two", "three" }); + System.out.println("Audit entries for node "+as.getAuditTrail(nodeRef).size()); } finally { @@ -101,10 +114,4 @@ public class AuditServiceImpl implements AuditService tx.commit(); } - - public List getAuditTrail(NodeRef nodeRef) - { - // TODO Auto-generated method stub - return null; - } } diff --git a/source/java/org/alfresco/repo/audit/AuditServiceTest.java b/source/java/org/alfresco/repo/audit/AuditServiceTest.java new file mode 100644 index 0000000000..aa6a4bf10c --- /dev/null +++ b/source/java/org/alfresco/repo/audit/AuditServiceTest.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.audit; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.audit.model.AuditEntry; +import org.alfresco.repo.audit.model.TrueFalseUnset; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.MutableAuthenticationDao; +import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.repo.security.permissions.impl.ModelDAO; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.audit.AuditInfo; +import org.alfresco.service.cmr.audit.AuditService; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespacePrefixResolver; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.BaseSpringTest; + +public class AuditServiceTest extends BaseSpringTest +{ + + private NodeService nodeService; + + private DictionaryService dictionaryService; + + private PermissionServiceSPI permissionService; + + private NamespacePrefixResolver namespacePrefixResolver; + + private AuthenticationService authenticationService; + + private AuthenticationComponent authenticationComponent; + + private ServiceRegistry serviceRegistry; + + private ModelDAO permissionModelDAO; + + private PersonService personService; + + private AuthorityService authorityService; + + private MutableAuthenticationDao authenticationDAO; + + private NodeRef rootNodeRef; + + private NodeRef systemNodeRef; + + private AuditService auditService; + + private AuditEntry auditEntry; + + private NodeRef typesNodeRef; + + private QName children; + + private QName system; + + private QName container; + + private QName types; + + public AuditServiceTest() + { + super(); + } + + protected void onSetUpInTransaction() throws Exception + { + nodeService = (NodeService) applicationContext.getBean("nodeService"); + dictionaryService = (DictionaryService) applicationContext.getBean(ServiceRegistry.DICTIONARY_SERVICE + .getLocalName()); + permissionService = (PermissionServiceSPI) applicationContext.getBean("permissionService"); + namespacePrefixResolver = (NamespacePrefixResolver) applicationContext + .getBean(ServiceRegistry.NAMESPACE_SERVICE.getLocalName()); + authenticationService = (AuthenticationService) applicationContext.getBean("authenticationService"); + authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent"); + serviceRegistry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); + permissionModelDAO = (ModelDAO) applicationContext.getBean("permissionsModelDAO"); + personService = (PersonService) applicationContext.getBean("personService"); + authorityService = (AuthorityService) applicationContext.getBean("authorityService"); + + authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); + authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("alfDaoImpl"); + + auditService = (AuditService) applicationContext.getBean("AuditService"); + auditEntry = (AuditEntry) applicationContext.getBean("auditModel"); + + StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime()); + rootNodeRef = nodeService.getRootNode(storeRef); + + children = ContentModel.ASSOC_CHILDREN; + system = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system"); + container = ContentModel.TYPE_CONTAINER; + types = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "people"); + + systemNodeRef = nodeService.createNode(rootNodeRef, children, system, container).getChildRef(); + typesNodeRef = nodeService.createNode(systemNodeRef, children, types, container).getChildRef(); + Map props = createPersonProperties("andy"); + nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); + props = createPersonProperties("lemur"); + nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); + + // create an authentication object e.g. the user + if (authenticationDAO.userExists("andy")) + { + authenticationService.deleteAuthentication("andy"); + } + authenticationService.createAuthentication("andy", "andy".toCharArray()); + + if (authenticationDAO.userExists("lemur")) + { + authenticationService.deleteAuthentication("lemur"); + } + authenticationService.createAuthentication("lemur", "lemur".toCharArray()); + + if (authenticationDAO.userExists("admin")) + { + authenticationService.deleteAuthentication("admin"); + } + authenticationService.createAuthentication("admin", "admin".toCharArray()); + + authenticationComponent.clearCurrentSecurityContext(); + } + + public void testApplicationAudit() + { + AuthenticationUtil.setSystemUserAsCurrentUser(); + try + { + + NodeRef nodeRef = new NodeRef(new StoreRef("test", "audit"), "id"); + int start = auditService.getAuditTrail(nodeRef).size(); + int increment = auditEntry.getEnabled() == TrueFalseUnset.TRUE ? 1 : 0; + auditService.audit("AuditedApp", "First"); + assertEquals(start, auditService.getAuditTrail(nodeRef).size()); + auditService.audit("AuditedApp", "Second", nodeRef); + assertEquals(start + (1 * increment), auditService.getAuditTrail(nodeRef).size()); + auditService.audit("AuditedApp", "Third", new Object[] { "one", "two", "three" }); + assertEquals(start + (1 * increment), auditService.getAuditTrail(nodeRef).size()); + auditService.audit("AuditedApp", "Fourth", nodeRef, new Object[] { "one", "two", "three" }); + assertEquals(start + (2 * increment), auditService.getAuditTrail(nodeRef).size()); + auditService.audit("UnAuditedApp", "First"); + assertEquals(start + (2 * increment), auditService.getAuditTrail(nodeRef).size()); + auditService.audit("UnAuditedApp", "Second", nodeRef); + assertEquals(start + (3 * increment), auditService.getAuditTrail(nodeRef).size()); + auditService.audit("UnAuditedApp", "Third", new Object[] { "one", "two", "three" }); + assertEquals(start + (3 * increment), auditService.getAuditTrail(nodeRef).size()); + auditService.audit("UnAuditedApp", "Fourth", nodeRef, new Object[] { "one", "two", "three" }); + assertEquals(start + (4 * increment), auditService.getAuditTrail(nodeRef).size()); + } + finally + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + } + + public void testNodeServiceAudit() + { + AuthenticationUtil.setSystemUserAsCurrentUser(); + try + { + int start = auditService.getAuditTrail(typesNodeRef).size(); + int increment = auditEntry.getEnabled() == TrueFalseUnset.TRUE ? 1 : 0; + + // Create + + Map props = createPersonProperties("woof"); + NodeRef created = serviceRegistry.getNodeService().createNode(typesNodeRef, children, + ContentModel.TYPE_PERSON, container, props).getChildRef(); + assertEquals(start + (1 * increment), auditService.getAuditTrail(typesNodeRef).size()); + List list = auditService.getAuditTrail(typesNodeRef); + assertEquals(0, auditService.getAuditTrail(created).size()); + + // Update + + serviceRegistry.getNodeService().setProperty(created, ContentModel.PROP_FIRSTNAME, "New First Name"); + assertEquals((1 * increment), auditService.getAuditTrail(created).size()); + + // Update + + serviceRegistry.getNodeService().setProperty(created, ContentModel.PROP_FIRSTNAME, "Next First Name"); + assertEquals((2 * increment), auditService.getAuditTrail(created).size()); + + // Delete + + serviceRegistry.getNodeService().deleteNode(created); + assertEquals((3 * increment), auditService.getAuditTrail(created).size()); + + list = auditService.getAuditTrail(created); + assertNotNull(list); + } + finally + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + } + + public void xtestCreateStore() + { + + AuthenticationUtil.setSystemUserAsCurrentUser(); + try + { + serviceRegistry.getNodeService() + .createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_Audit_" + System.nanoTime()); + // Should have a query to support this - check direct in the DB + } + finally + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + setComplete(); + } + + public void xtestAuthenticartionDoesNotReportPasswords() + { + // Should have a query to support this - check direct in the DB + AuthenticationUtil.setSystemUserAsCurrentUser(); + try + { + serviceRegistry.getAuthenticationService().createAuthentication("cabbage", "cabbage".toCharArray()); + serviceRegistry.getAuthenticationService().updateAuthentication("cabbage", "cabbage".toCharArray(), + "red".toCharArray()); + } + finally + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + + try + { + serviceRegistry.getAuthenticationService().authenticate("cabbage", "red".toCharArray()); + } + finally + { + serviceRegistry.getAuthenticationService().clearCurrentSecurityContext(); + } + setComplete(); + } + + public void xtestAuthenticartionFailure() + { + // Should have a query to support this - check direct in the DB + AuthenticationUtil.setSystemUserAsCurrentUser(); + + serviceRegistry.getAuthenticationService().createAuthentication("woof", "cabbage".toCharArray()); + serviceRegistry.getAuthenticationService().authenticate("woof", "red".toCharArray()); + + } + + public void testThereIsAnAuditService() + { + assertNotNull(serviceRegistry.getAuditService()); + } + + private Map createPersonProperties(String userName) + { + HashMap properties = new HashMap(); + properties.put(ContentModel.PROP_USERNAME, userName); + return properties; + } + +} diff --git a/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml b/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml index 4bb874a29d..2471679cc5 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml +++ b/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml @@ -155,4 +155,18 @@ audit_store.method = :method + + select + audit_fact + from + org.alfresco.repo.audit.hibernate.AuditFactImpl as audit_fact + where + audit_fact.storeProtocol = :protocol and + audit_fact.storeId = :store_id and + audit_fact.nodeUUID = :node_id + order by + audit_fact.date asc + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/audit/hibernate/AuditConfigImpl.java b/source/java/org/alfresco/repo/audit/hibernate/AuditConfigImpl.java index 6e86b0b8ee..adbb284e22 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/AuditConfigImpl.java +++ b/source/java/org/alfresco/repo/audit/hibernate/AuditConfigImpl.java @@ -87,10 +87,10 @@ public class AuditConfigImpl implements AuditConfig, InitializingBean /** * Helper method to get the latest audit config */ - public static AuditConfigImpl getLatestConfig(Session session) + public static AuditConfig getLatestConfig(Session session) { Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_LAST_AUDIT_CONFIG); - return (AuditConfigImpl) query.uniqueResult(); + return (AuditConfig) query.uniqueResult(); } @Override diff --git a/source/java/org/alfresco/repo/audit/hibernate/AuditDateImpl.java b/source/java/org/alfresco/repo/audit/hibernate/AuditDateImpl.java index a15e9c85da..0b79abc8bc 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/AuditDateImpl.java +++ b/source/java/org/alfresco/repo/audit/hibernate/AuditDateImpl.java @@ -280,10 +280,10 @@ public class AuditDateImpl implements AuditDate /** * Helper method to get the latest audit date */ - public static AuditDateImpl getLatestDate(Session session) + public static AuditDate getLatestDate(Session session) { Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_LAST_AUDIT_DATE); - return (AuditDateImpl) query.uniqueResult(); + return (AuditDate) query.uniqueResult(); } } diff --git a/source/java/org/alfresco/repo/audit/hibernate/AuditFactImpl.java b/source/java/org/alfresco/repo/audit/hibernate/AuditFactImpl.java index 3ec7f4a4ad..1b4b433519 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/AuditFactImpl.java +++ b/source/java/org/alfresco/repo/audit/hibernate/AuditFactImpl.java @@ -17,6 +17,11 @@ package org.alfresco.repo.audit.hibernate; import java.util.Date; +import java.util.List; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.hibernate.Query; +import org.hibernate.Session; /** * An Audit fact Rely on standard equals and hash code as they should all be unique. @@ -575,4 +580,16 @@ public class AuditFactImpl implements AuditFact this.userId = userId; } + /** + * Helper method to get all the audit entries for a node. + */ + @SuppressWarnings("unchecked") + public static List getAuditTrail(Session session, NodeRef nodeRef) + { + Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_AUDIT_TRAIL); + query.setParameter(HibernateAuditDAO.QUERY_AUDIT_PROTOCOL, nodeRef.getStoreRef().getProtocol()); + query.setParameter(HibernateAuditDAO.QUERY_AUDIT_STORE_ID, nodeRef.getStoreRef().getIdentifier()); + query.setParameter(HibernateAuditDAO.QUERY_AUDIT_NODE_ID, nodeRef.getId()); + return (List) query.list(); + } } diff --git a/source/java/org/alfresco/repo/audit/hibernate/AuditInfoImpl.java b/source/java/org/alfresco/repo/audit/hibernate/AuditInfoImpl.java new file mode 100644 index 0000000000..92a14a5ece --- /dev/null +++ b/source/java/org/alfresco/repo/audit/hibernate/AuditInfoImpl.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.audit.hibernate; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +import org.alfresco.service.cmr.audit.AuditInfo; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; + +public class AuditInfoImpl implements AuditInfo +{ + private String auditApplication; + + private String auditMethod; + + private String auditService; + + private String clientAddress; + + private Date date; + + private boolean fail; + + private boolean filtered; + + private String hostAddress; + + private String keyGUID; + + private Map keyPropertiesAfter; + + private Map keyPropertiesBefore; + + private StoreRef keyStore; + + private String message; + + private Serializable[] methodArguments; + + private String[] methodArgumentsAsStrings; + + private String path; + + private Serializable returnObject; + + private String returnObjectAsString; + + private String sessionId; + + private Throwable throwable; + + private String throwableAsString; + + private String txId; + + private String userIdentifier; + + public AuditInfoImpl(AuditFact auditFact) + { + super(); + this.auditApplication = auditFact.getAuditSource().getApplication(); + this.auditMethod = auditFact.getAuditSource().getMethod(); + this.auditService = auditFact.getAuditSource().getService(); + this.clientAddress = auditFact.getClientInetAddress(); + this.date = auditFact.getDate(); + this.fail = auditFact.isFail(); + this.filtered = auditFact.isFiltered(); + this.hostAddress= auditFact.getHostInetAddress(); + this.keyGUID = auditFact.getNodeUUID(); + this.keyPropertiesAfter = null; + this.keyPropertiesBefore = null; + this.keyStore = new StoreRef(auditFact.getStoreProtocol(), auditFact.getStoreId()); + this.message = auditFact.getMessage(); + this.methodArguments = null; + this.methodArgumentsAsStrings = new String[5]; + this.methodArgumentsAsStrings[0] = auditFact.getArg1(); + this.methodArgumentsAsStrings[1] = auditFact.getArg2(); + this.methodArgumentsAsStrings[2] = auditFact.getArg3(); + this.methodArgumentsAsStrings[3] = auditFact.getArg4(); + this.methodArgumentsAsStrings[4] = auditFact.getArg5(); + this.path = auditFact.getPath(); + this.returnObject = null; + this.returnObjectAsString = auditFact.getReturnValue(); + this.sessionId = auditFact.getSessionId(); + this.throwable = null; + this.throwableAsString = auditFact.getException(); + this.txId = auditFact.getTransactionId(); + this.userIdentifier = auditFact.getUserId(); + } + + public String getAuditApplication() + { + return auditApplication; + } + + public String getAuditMethod() + { + return auditMethod; + } + + public String getAuditService() + { + return auditService; + } + + public String getClientAddress() + { + return clientAddress; + } + + public Date getDate() + { + return date; + } + + public boolean isFail() + { + return fail; + } + + public boolean isFiltered() + { + return filtered; + } + + public String getHostAddress() + { + return hostAddress; + } + + public String getKeyGUID() + { + return keyGUID; + } + + public Map getKeyPropertiesAfter() + { + return keyPropertiesAfter; + } + + public Map getKeyPropertiesBefore() + { + return keyPropertiesBefore; + } + + public StoreRef getKeyStore() + { + return keyStore; + } + + public String getMessage() + { + return message; + } + + public Serializable[] getMethodArguments() + { + return methodArguments; + } + + public String[] getMethodArgumentsAsStrings() + { + return methodArgumentsAsStrings; + } + + public String getPath() + { + return path; + } + + public Serializable getReturnObject() + { + return returnObject; + } + + public String getReturnObjectAsString() + { + return returnObjectAsString; + } + + public String getSessionId() + { + return sessionId; + } + + public Throwable getThrowable() + { + return throwable; + } + + public String getThrowableAsString() + { + return throwableAsString; + } + + public String getTxId() + { + return txId; + } + + public String getUserIdentifier() + { + return userIdentifier; + } + + +} diff --git a/source/java/org/alfresco/repo/audit/hibernate/AuditSource.java b/source/java/org/alfresco/repo/audit/hibernate/AuditSource.java index 17ac1c2ef0..0bab03f211 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/AuditSource.java +++ b/source/java/org/alfresco/repo/audit/hibernate/AuditSource.java @@ -26,4 +26,10 @@ public interface AuditSource public String getService(); + void setApplication(String auditApplication); + + void setService(String auditService); + + void setMethod(String auditMethod); + } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/audit/hibernate/AuditSourceImpl.java b/source/java/org/alfresco/repo/audit/hibernate/AuditSourceImpl.java index 927d042317..5cf50a6cd3 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/AuditSourceImpl.java +++ b/source/java/org/alfresco/repo/audit/hibernate/AuditSourceImpl.java @@ -87,21 +87,21 @@ public class AuditSourceImpl implements AuditSource this.service = service; } - public static AuditSourceImpl getApplicationSource(Session session, String application) + public static AuditSource getApplicationSource(Session session, String application) { Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE); query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_APP, application); - return (AuditSourceImpl) query.uniqueResult(); + return (AuditSource) query.uniqueResult(); } - public static AuditSourceImpl getApplicationSource(Session session, String application, String service, + public static AuditSource getApplicationSource(Session session, String application, String service, String method) { Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_AUDIT_METHOD_SOURCE); query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_APP, application); query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_SER, service); query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_MET, method); - return (AuditSourceImpl) query.uniqueResult(); + return (AuditSource) query.uniqueResult(); } @Override diff --git a/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java b/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java index 627ea4a062..63c9b3e3d8 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java +++ b/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java @@ -20,21 +20,28 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.audit.AuditConfiguration; import org.alfresco.repo.audit.AuditDAO; +import org.alfresco.repo.audit.AuditException; import org.alfresco.repo.audit.AuditState; import org.alfresco.repo.content.AbstractContentStore; import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.TransactionalDao; +import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.datatype.Duration; import org.alfresco.util.EqualsHelper; import org.alfresco.util.GUID; @@ -63,6 +70,14 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, public static final String QUERY_AUDIT_APP_SOURCE_MET = "method"; + public static final String QUERY_AUDIT_TRAIL = "audit.GetAuditTrailForNode"; + + public static final String QUERY_AUDIT_PROTOCOL = "protocol"; + + public static final String QUERY_AUDIT_STORE_ID = "store_id"; + + public static final String QUERY_AUDIT_NODE_ID = "node_id"; + /** a uuid identifying this unique instance */ private String uuid; @@ -93,15 +108,35 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, } public void audit(AuditState auditInfo) + { + if(AuthenticationUtil.getCurrentUserName() == null) + { + AuthenticationUtil.setSystemUserAsCurrentUser(); + try + { + audit0(auditInfo); + } + finally + { + AuthenticationUtil.clearCurrentSecurityContext(); + } + } + else + { + audit0(auditInfo); + } + } + + private void audit0(AuditState auditInfo) { // Find/Build the configuraton entry - AuditConfigImpl auditConfig = getAuditConfig(auditInfo); + AuditConfig auditConfig = getAuditConfig(auditInfo); // Find/Build any dates - AuditDateImpl auditDate = getAuditDate(auditInfo); + AuditDate auditDate = getAuditDate(auditInfo); // Find/Build the source - AuditSourceImpl auditSource = getAuditSource(auditInfo); + AuditSource auditSource = getAuditSource(auditInfo); // Build the new audit fact information AuditFactImpl auditFact = new AuditFactImpl(); @@ -170,9 +205,9 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, } } - private AuditSourceImpl getAuditSource(AuditState auditInfo) + private AuditSource getAuditSource(AuditState auditInfo) { - AuditSourceImpl auditSourceImpl; + AuditSource auditSourceImpl; SourceKey sourceKey = new SourceKey(auditInfo.getAuditApplication(), auditInfo.getAuditService(), auditInfo.getAuditMethod()); if(sourceIds.get() == null) @@ -182,7 +217,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, Long id = sourceIds.get().get(sourceKey); if(id != null) { - auditSourceImpl = (AuditSourceImpl) getSession().get(AuditSourceImpl.class, id.longValue()); + auditSourceImpl = (AuditSource) getSession().get(AuditSourceImpl.class, id.longValue()); if(auditSourceImpl != null) { return auditSourceImpl; @@ -218,7 +253,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, return auditSourceImpl; } - private AuditDateImpl getAuditDate(AuditState auditInfo) + private AuditDate getAuditDate(AuditState auditInfo) { Calendar cal = GregorianCalendar.getInstance(); cal.setTime(auditInfo.getDate()); @@ -228,7 +263,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, cal.set(Calendar.HOUR_OF_DAY, 0); Date required = cal.getTime(); - AuditDateImpl auditDate; + AuditDate auditDate; if (auditDateImplId.get() == null) { auditDate = AuditDateImpl.getLatestDate(getSession()); @@ -242,7 +277,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, } else { - auditDate = (AuditDateImpl) getSession().get(AuditDateImpl.class, auditDateImplId.get().longValue()); + auditDate = (AuditDate) getSession().get(AuditDateImpl.class, auditDateImplId.get().longValue()); if ((auditDate == null) || (!required.equals(auditDate.getDate()))) { auditDate = AuditDateImpl.getLatestDate(getSession()); @@ -265,9 +300,9 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, return auditDate; } - private AuditConfigImpl getAuditConfig(AuditState auditInfo) + private AuditConfig getAuditConfig(AuditState auditInfo) { - AuditConfigImpl auditConfig; + AuditConfig auditConfig; if ((auditConfiguration.get() == null) || (auditConfiguration.get() != auditInfo.getAuditConfiguration())) { auditConfig = AuditConfigImpl.getLatestConfig(getSession()); @@ -313,7 +348,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, } else { - auditConfig = (AuditConfigImpl) getSession() + auditConfig = (AuditConfig) getSession() .get(AuditConfigImpl.class, auditConfigImplId.get().longValue()); if (auditConfig == null) { @@ -436,4 +471,23 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, return hash; } } + + public List getAuditTrail(NodeRef nodeRef) + { + if(nodeRef == null) + { + return Collections.emptyList(); + } + List internalTrail = AuditFactImpl.getAuditTrail(getSession(), nodeRef); + + ArrayList answer = new ArrayList(internalTrail.size()); + for(AuditFact auditFact : internalTrail) + { + AuditInfo info = new AuditInfoImpl(auditFact); + answer.add(info); + } + return answer; + } + + } diff --git a/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java b/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java index 7349e44be0..c99fd0bb7c 100644 --- a/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java +++ b/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java @@ -117,7 +117,7 @@ public abstract class AbstractAuditEntry return auditMode; } - /* package */TrueFalseUnset getEnabled() + public TrueFalseUnset getEnabled() { return enabled; } diff --git a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java index eb018bc77a..c705ca22d2 100644 --- a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java +++ b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java @@ -25,6 +25,7 @@ import java.util.Map; import org.alfresco.service.ServiceDescriptor; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.action.ActionService; +import org.alfresco.service.cmr.audit.AuditService; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.lock.LockService; @@ -322,4 +323,12 @@ public class ServiceDescriptorRegistry { return (WorkflowService)getService(WORKFLOW_SERVICE); } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getWorkflowService() + */ + public AuditService getAuditService() + { + return (AuditService)getService(AUDIT_SERVICE); + } } diff --git a/source/java/org/alfresco/service/ServiceRegistry.java b/source/java/org/alfresco/service/ServiceRegistry.java index 7e893e3789..d98cf4fda1 100644 --- a/source/java/org/alfresco/service/ServiceRegistry.java +++ b/source/java/org/alfresco/service/ServiceRegistry.java @@ -19,6 +19,7 @@ package org.alfresco.service; import java.util.Collection; import org.alfresco.service.cmr.action.ActionService; +import org.alfresco.service.cmr.audit.AuditService; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.lock.LockService; @@ -84,6 +85,7 @@ public interface ServiceRegistry static final QName FILE_FOLDER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "FileFolderService"); static final QName SCRIPT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ScriptService"); static final QName WORKFLOW_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "WorkflowService"); + static final QName AUDIT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuditService"); /** * Get the list of services provided by the Repository @@ -263,4 +265,10 @@ public interface ServiceRegistry */ @NotAuditable WorkflowService getWorkflowService(); + + /** + * @return the audit service (or null if one is not provided) + */ + @NotAuditable + AuditService getAuditService(); } diff --git a/source/java/org/alfresco/service/cmr/audit/AuditInfo.java b/source/java/org/alfresco/service/cmr/audit/AuditInfo.java index 31b1475e3b..f601a61bc9 100644 --- a/source/java/org/alfresco/service/cmr/audit/AuditInfo.java +++ b/source/java/org/alfresco/service/cmr/audit/AuditInfo.java @@ -57,7 +57,7 @@ public interface AuditInfo * * @return - the client address - may be null. */ - public InetAddress getClientAddress(); + public String getClientAddress(); /** * The timestamp for the audit entry. @@ -85,7 +85,7 @@ public interface AuditInfo * * @return */ - public InetAddress getHostAddress(); + public String getHostAddress(); /** * Get the ID of the key node. diff --git a/source/java/org/alfresco/service/cmr/repository/NodeService.java b/source/java/org/alfresco/service/cmr/repository/NodeService.java index 130e67f4ab..2b8c0aba46 100644 --- a/source/java/org/alfresco/service/cmr/repository/NodeService.java +++ b/source/java/org/alfresco/service/cmr/repository/NodeService.java @@ -54,7 +54,7 @@ public interface NodeService * @return Returns a reference to the store * @throws StoreExistsException */ - @Auditable(parameters = {"protocol", "identifier"}) + @Auditable(key = Auditable.Key.RETURN, parameters = {"protocol", "identifier"}) public StoreRef createStore(String protocol, String identifier) throws StoreExistsException; /** diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java index a78f6c6590..6d2a05b55c 100644 --- a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java +++ b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java @@ -34,6 +34,7 @@ import org.alfresco.repo.template.NodeSearchResultsMap; import org.alfresco.repo.template.SavedSearchResultsMap; import org.alfresco.repo.template.XPathResultsMap; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.security.AccessPermission; @@ -660,6 +661,14 @@ public final class TemplateNode implements Serializable } + // Audit API + + + public List getAuditTrail() + { + return this.services.getAuditService().getAuditTrail(this.nodeRef); + } + // ------------------------------------------------------------------------------ // Misc helpers