diff --git a/config/alfresco/auditConfig.xml b/config/alfresco/auditConfig.xml index 775e060362..3eeac13515 100644 --- a/config/alfresco/auditConfig.xml +++ b/config/alfresco/auditConfig.xml @@ -135,13 +135,16 @@ - + + + + diff --git a/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml b/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml index be86435f4c..d7daf21b62 100644 --- a/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml +++ b/config/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication-context.xml @@ -117,6 +117,9 @@ + + + diff --git a/config/alfresco/subsystems/Authentication/common-ldap-context.xml b/config/alfresco/subsystems/Authentication/common-ldap-context.xml index 1654d1bfff..3775a43ecb 100644 --- a/config/alfresco/subsystems/Authentication/common-ldap-context.xml +++ b/config/alfresco/subsystems/Authentication/common-ldap-context.xml @@ -80,6 +80,9 @@ + + + diff --git a/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml b/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml index 4835346417..cdfe3700dc 100644 --- a/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml +++ b/config/alfresco/subsystems/Authentication/passthru/passthru-authentication-context.xml @@ -95,6 +95,9 @@ + + + diff --git a/source/java/org/alfresco/repo/audit/AuditBootstrap.java b/source/java/org/alfresco/repo/audit/AuditBootstrap.java index 6740a482cc..0e94b27b55 100644 --- a/source/java/org/alfresco/repo/audit/AuditBootstrap.java +++ b/source/java/org/alfresco/repo/audit/AuditBootstrap.java @@ -57,6 +57,12 @@ public class AuditBootstrap extends AbstractLifecycleBean @Override protected void onBootstrap(ApplicationEvent event) { + // Don't bootstrap if the system is read-only + if (transactionService.isReadOnly()) + { + return; + } + RetryingTransactionCallback callback = new RetryingTransactionCallback() { public Void execute() throws Throwable diff --git a/source/java/org/alfresco/repo/audit/AuditComponent.java b/source/java/org/alfresco/repo/audit/AuditComponent.java index b60fed19bc..daf838d8da 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponent.java +++ b/source/java/org/alfresco/repo/audit/AuditComponent.java @@ -70,6 +70,14 @@ public interface AuditComponent * @since 2.1 */ public void audit(String source, String description, NodeRef key, Object... args); + + /** + * Add an audit entry - without invoking the method invocation. + * Only the method arguments can be audited. + * + * @since 3.2 + */ + void beforeMethodCallManualAudit(Class clazz, Object target, String method, Object ... args); /** * Get the audit trail for a node. diff --git a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java index b10e6aab39..9ef15d13fc 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java +++ b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java @@ -64,11 +64,12 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.transaction.TransactionService; -import org.springframework.extensions.surf.util.ParameterCheck; import org.alfresco.util.PathMapper; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aop.framework.ReflectiveMethodInvocation; +import org.springframework.extensions.surf.util.ParameterCheck; /** * The default audit component implementation. TODO: Implement before, after and exception filtering. At the moment @@ -234,7 +235,7 @@ public class AuditComponentImpl implements AuditComponent { logger.debug("Auditing - " + serviceName + "." + methodName); } - return auditImpl(mi); + return auditImpl(mi, true); } else { @@ -242,7 +243,7 @@ public class AuditComponentImpl implements AuditComponent { logger.debug("UnknownService." + methodName); } - return auditImpl(mi); + return auditImpl(mi, true); } } @@ -298,16 +299,20 @@ public class AuditComponentImpl implements AuditComponent * @throws Throwable - * any Throwable that can be thrown by th audtied method. */ - public Object auditImpl(MethodInvocation mi) throws Throwable + public Object auditImpl(MethodInvocation mi, boolean execute) throws Throwable { final AuditState auditInfo = new AuditState(auditConfiguration); // RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi); AuditMode auditMode = AuditMode.UNSET; try { + Object o = null; auditMode = beforeInvocation(auditMode, auditInfo, mi); - Object o = mi.proceed(); - auditMode = postInvocation(auditMode, auditInfo, mi, o); + if (execute) + { + o = mi.proceed(); + auditMode = postInvocation(auditMode, auditInfo, mi, o); + } if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.SUCCESS)) { RetryingTransactionCallback cb = new RetryingTransactionCallback() @@ -611,6 +616,120 @@ public class AuditComponentImpl implements AuditComponent } } + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.audit.AuditComponent#beforeMethodCallManualAudit(org.aopalliance.intercept.MethodInvocation) + */ + @SuppressWarnings("unchecked") + public void beforeMethodCallManualAudit(Class clazz, Object target, String methodName, Object ... args) + { + Class[] argTypes = new Class[args.length]; + for(int i = 0; i < args.length; i++) + { + argTypes[i] = args[i].getClass(); + } + Method method; + try + { + method = clazz.getMethod(methodName, argTypes); + } + catch (SecurityException e1) + { + return; + } + catch (NoSuchMethodException e1) + { + return; + } + MethodInvocation methodInvocation = new ReflectiveMethodInvocation(null, target, method, args, null, null) {}; + if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue())) + { + if (auditModel instanceof AuditEntry && ((AuditEntry) auditModel).getEnabled() == TrueFalseUnset.TRUE) + { + boolean auditInternal = (auditModel.getAuditInternalServiceMethods(methodInvocation) == TrueFalseUnset.TRUE); + try + { + String serviceName = publicServiceIdentifier.getPublicServiceName(methodInvocation); + + if (!auditInternal) + { + auditFlag.set(Boolean.TRUE); + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("Auditing internal service use for - " + serviceName + "." + methodName); + } + } + + if (method.isAnnotationPresent(Auditable.class)) + { + + if (serviceName != null) + { + if (logger.isDebugEnabled()) + { + logger.debug("Auditing - " + serviceName + "." + methodName); + } + try + { + auditImpl(methodInvocation, false); + } + catch (Throwable e) + { + + } + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("UnknownService." + methodName); + } + try + { + auditImpl(methodInvocation, false); + } + catch (Throwable e) + { + + } + } + + } + else if (method.isAnnotationPresent(NotAuditable.class)) + { + if (logger.isDebugEnabled()) + { + logger.debug("Not Audited. " + serviceName + "." + methodName); + } + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("Unannotated service method " + serviceName + "." + methodName); + } + if (method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAnnotationPresent(PublicService.class)) + { + throw new RuntimeException("Unannotated service method " + serviceName + "." + methodName); + } + } + } + finally + { + if (!auditInternal) + { + auditFlag.set(Boolean.FALSE); + } + } + } + + } + } + /** * A simple audit entry Currently we ignore filtering here. */ diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java index d6dc94586e..586a881bad 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java @@ -24,11 +24,16 @@ */ package org.alfresco.repo.security.authentication; +import java.lang.reflect.Method; import java.util.Collections; import java.util.Set; +import org.alfresco.repo.audit.AuditComponent; import org.alfresco.repo.management.subsystems.ActivateableBean; import org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.framework.ReflectiveMethodInvocation; public class AuthenticationServiceImpl extends AbstractAuthenticationService implements ActivateableBean { @@ -36,6 +41,8 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp TicketComponent ticketComponent; + AuditComponent auditComponent; + private String domain; private boolean allowsUserCreation = true; @@ -58,7 +65,16 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp { this.authenticationComponent = authenticationComponent; } + + /** + * @param auditComponent the auditComponent to set + */ + public void setAuditComponent(AuditComponent auditComponent) + { + this.auditComponent = auditComponent; + } + /* * (non-Javadoc) * @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive() @@ -85,8 +101,7 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp throw ae; } ticketComponent.clearCurrentTicket(); - - ticketComponent.getCurrentTicket(userName, null, true); // to ensure new ticket is created (even if client does not explicitly call getCurrentTicket) + getCurrentTicket(null); } public String getCurrentUserName() throws AuthenticationException @@ -146,24 +161,16 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService imp String ticket = ticketComponent.getCurrentTicket(userName, sessionId, false); if (ticket == null) { - try - { - preAuthenticationCheck(userName); - } - catch (AuthenticationException e) - { - clearCurrentSecurityContext(); - throw e; - } // If we get through the authentication check then it's safe to issue a new ticket (e.g. for // SSO/external-based login) - return ticketComponent.getCurrentTicket(userName, sessionId, true); + return getNewTicket(sessionId); } return ticket; } public String getNewTicket(String sessionId) { + auditComponent.beforeMethodCallManualAudit(AuthenticationService.class, this, "getNewTicket", ""); String userName = getCurrentUserName(); try {