SAIL-240 (SAIL-294) AuditDAO: AuditService enhancements

- Added isAuditEnabled and enableAudit for global case (system-wide)
 - Some neatening up of Audit SQL (common WHERE and ORDER BY clauses)
 - AuditService enforces 'admin' role for all methods


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21471 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2010-07-28 17:40:17 +00:00
parent 67fc407496
commit 44e18c2d81
5 changed files with 111 additions and 176 deletions

View File

@@ -145,6 +145,45 @@
</isNotNull> </isNotNull>
</delete> </delete>
<sql id="select_AuditEntriesWhereSnippet">
<dynamic prepend="where">
<isNotNull prepend="and" property="auditAppNameId">
app.app_name_id = #auditAppNameId#
</isNotNull>
<isNotNull prepend="and" property="auditUserId">
entry.audit_user_id = #auditUserId#
</isNotNull>
<isNotNull prepend="and" property="auditFromId">
<![CDATA[entry.id >= #auditFromId#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToId">
<![CDATA[entry.id < #auditToId#]]>
</isNotNull>
<isNotNull prepend="and" property="auditFromTime">
<![CDATA[entry.audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToTime">
<![CDATA[entry.audit_time < #auditToTime#]]>
</isNotNull>
<isNotNull prepend="and" property="searchKeyId">
sp_kpl.key_prop_id = #searchKeyId#
</isNotNull>
<isNotNull prepend="and" property="searchValueId">
sp_mpl.value_prop_id = #searchValueId#
</isNotNull>
</dynamic>
</sql>
<sql id="select_AuditEntriesOrderBySnippet">
<isEqual property="forward" compareProperty="forwardTrue">
order by
entry.id asc
</isEqual>
<isNotEqual property="forward" compareProperty="forwardTrue">
order by
entry.id desc
</isNotEqual>
</sql>
<!-- Get audit entries --> <!-- Get audit entries -->
<select id="select_AuditEntriesWithValues" parameterClass="AuditQueryParameters" resultMap="result_AuditQueryAllValues"> <select id="select_AuditEntriesWithValues" parameterClass="AuditQueryParameters" resultMap="result_AuditQueryAllValues">
select select
@@ -181,40 +220,8 @@
left join alf_prop_double_value dv on (dv.id = pv.long_value and pv.persisted_type = 2) left join alf_prop_double_value dv on (dv.id = pv.long_value and pv.persisted_type = 2)
left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5)) left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5))
left join alf_prop_serializable_value serv on (serv.id = pv.long_value and pv.persisted_type = 4) left join alf_prop_serializable_value serv on (serv.id = pv.long_value and pv.persisted_type = 4)
<dynamic prepend="where"> <include refid="select_AuditEntriesWhereSnippet"/>
<isNotNull prepend="and" property="auditAppNameId"> <include refid="select_AuditEntriesOrderBySnippet"/>
app.app_name_id = #auditAppNameId#
</isNotNull>
<isNotNull prepend="and" property="auditUserId">
entry.audit_user_id = #auditUserId#
</isNotNull>
<isNotNull prepend="and" property="auditFromId">
<![CDATA[entry.id >= #auditFromId#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToId">
<![CDATA[entry.id < #auditToId#]]>
</isNotNull>
<isNotNull prepend="and" property="auditFromTime">
<![CDATA[entry.audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToTime">
<![CDATA[entry.audit_time < #auditToTime#]]>
</isNotNull>
<isNotNull prepend="and" property="searchKeyId">
sp_kpl.key_prop_id = #searchKeyId#
</isNotNull>
<isNotNull prepend="and" property="searchValueId">
sp_mpl.value_prop_id = #searchValueId#
</isNotNull>
</dynamic>
<isEqual property="forward" compareProperty="forwardTrue">
order by
entry.id asc
</isEqual>
<isNotEqual property="forward" compareProperty="forwardTrue">
order by
entry.id desc
</isNotEqual>
</select> </select>
<!-- Get audit entries --> <!-- Get audit entries -->
@@ -236,40 +243,8 @@
join alf_prop_link sp_mpl on (sp_mpl.root_prop_id = entry.audit_values_id) join alf_prop_link sp_mpl on (sp_mpl.root_prop_id = entry.audit_values_id)
</isNotNull> </isNotNull>
<dynamic prepend="where"> <include refid="select_AuditEntriesWhereSnippet"/>
<isNotNull prepend="and" property="auditAppNameId"> <include refid="select_AuditEntriesOrderBySnippet"/>
app.app_name_id = #auditAppNameId#
</isNotNull>
<isNotNull prepend="and" property="auditUserId">
entry.audit_user_id = #auditUserId#
</isNotNull>
<isNotNull prepend="and" property="auditFromId">
<![CDATA[entry.id >= #auditFromId#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToId">
<![CDATA[entry.id < #auditToId#]]>
</isNotNull>
<isNotNull prepend="and" property="auditFromTime">
<![CDATA[entry.audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToTime">
<![CDATA[entry.audit_time < #auditToTime#]]>
</isNotNull>
<isNotNull prepend="and" property="searchKeyId">
sp_kpl.key_prop_id = #searchKeyId#
</isNotNull>
<isNotNull prepend="and" property="searchValueId">
sp_mpl.value_prop_id = #searchValueId#
</isNotNull>
</dynamic>
<isEqual property="forward" compareProperty="forwardTrue">
order by
entry.id asc
</isEqual>
<isNotEqual property="forward" compareProperty="forwardTrue">
order by
entry.id desc
</isNotEqual>
</select> </select>
</sqlMap> </sqlMap>

View File

@@ -857,7 +857,16 @@
<!-- TODO: Add audit security --> <!-- TODO: Add audit security -->
<bean id="AuditService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" /> <bean id="AuditService_security" class="org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>
<property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
<property name="objectDefinitionSource">
<value>
org.alfresco.service.cmr.audit.AuditService.*=ACL_METHOD.ROLE_ADMINISTRATOR
</value>
</property>
</bean>
<!-- ======================== --> <!-- ======================== -->
<!-- Repository Admin Service --> <!-- Repository Admin Service -->

View File

@@ -512,10 +512,10 @@ public class AuditComponentTest extends TestCase
} }
}; };
auditService.clearAudit(APPLICATION_API_TEST); clearAuditLog(APPLICATION_API_TEST);
results.clear(); results.clear();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
auditService.auditQuery(auditQueryCallback, params, -1); queryAuditLog(auditQueryCallback, params, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
assertTrue("There should be no audit entries for the API test after a clear", results.isEmpty()); assertTrue("There should be no audit entries for the API test after a clear", results.isEmpty());
@@ -535,7 +535,7 @@ public class AuditComponentTest extends TestCase
AuthenticationUtil.runAs(createAuthenticationWork, AuthenticationUtil.getSystemUserName()); AuthenticationUtil.runAs(createAuthenticationWork, AuthenticationUtil.getSystemUserName());
// Clear everything out and do a successful authentication // Clear everything out and do a successful authentication
auditService.clearAudit(APPLICATION_API_TEST); clearAuditLog(APPLICATION_API_TEST);
try try
{ {
AuthenticationUtil.pushAuthentication(); AuthenticationUtil.pushAuthentication();
@@ -549,12 +549,12 @@ public class AuditComponentTest extends TestCase
// Check that the call was audited // Check that the call was audited
results.clear(); results.clear();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
auditService.auditQuery(auditQueryCallback, params, -1); queryAuditLog(auditQueryCallback, params, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
assertFalse("Did not get any audit results after successful login", results.isEmpty()); assertFalse("Did not get any audit results after successful login", results.isEmpty());
// Clear everything and check that unsuccessful authentication was audited // Clear everything and check that unsuccessful authentication was audited
auditService.clearAudit(APPLICATION_API_TEST); clearAuditLog(APPLICATION_API_TEST);
try try
{ {
authenticationService.authenticate("banana", "****".toCharArray()); authenticationService.authenticate("banana", "****".toCharArray());
@@ -566,7 +566,7 @@ public class AuditComponentTest extends TestCase
} }
results.clear(); results.clear();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
auditService.auditQuery(auditQueryCallback, params, -1); queryAuditLog(auditQueryCallback, params, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
assertFalse("Did not get any audit results after failed login", results.isEmpty()); assertFalse("Did not get any audit results after failed login", results.isEmpty());
} }
@@ -606,7 +606,40 @@ public class AuditComponentTest extends TestCase
params.setApplicationName(APPLICATION_API_TEST); params.setApplicationName(APPLICATION_API_TEST);
params.setForward(false); params.setForward(false);
params.setToId(Long.MAX_VALUE); params.setToId(Long.MAX_VALUE);
auditService.auditQuery(auditQueryCallback, params, 1); queryAuditLog(auditQueryCallback, params, 1);
} }
/**
* Clearn the audit log as 'admin'
*/
private void clearAuditLog(final String applicationName)
{
RunAsWork<Void> work = new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
auditService.clearAudit(applicationName);
return null;
}
};
AuthenticationUtil.runAs(work, AuthenticationUtil.getAdminRoleName());
}
/**
* Clearn the audit log as 'admin'
*/
private void queryAuditLog(final AuditQueryCallback callback, final AuditQueryParameters parameters, final int maxResults)
{
RunAsWork<Void> work = new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
auditService.auditQuery(callback, parameters, maxResults);
return null;
}
};
AuthenticationUtil.runAs(work, AuthenticationUtil.getAdminRoleName());
}
} }

View File

@@ -18,16 +18,14 @@
*/ */
package org.alfresco.repo.audit; package org.alfresco.repo.audit;
import java.io.Serializable;
import org.alfresco.service.cmr.audit.AuditQueryParameters; import org.alfresco.service.cmr.audit.AuditQueryParameters;
import org.alfresco.service.cmr.audit.AuditService; import org.alfresco.service.cmr.audit.AuditService;
import org.springframework.extensions.surf.util.ParameterCheck;
/** /**
* The implementation of the AuditService for application auditing. * The implementation of the AuditService for application auditing.
* *
* @author Andy Hind * @author Derek Hulley
* @since 3.2
*/ */
public class AuditServiceImpl implements AuditService public class AuditServiceImpl implements AuditService
{ {
@@ -43,6 +41,15 @@ public class AuditServiceImpl implements AuditService
this.auditComponent = auditComponent; this.auditComponent = auditComponent;
} }
/**
* {@inheritDoc}
* @since 3.4
*/
public boolean isAuditEnabled()
{
return auditComponent.isAuditEnabled();
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* @since 3.2 * @since 3.2
@@ -89,55 +96,4 @@ public class AuditServiceImpl implements AuditService
{ {
auditComponent.auditQuery(callback, parameters, maxResults); auditComponent.auditQuery(callback, parameters, maxResults);
} }
/**
* {@inheritDoc}
* @since 3.2
*/
public void auditQuery(
AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to,
int maxResults)
{
ParameterCheck.mandatory("callback", callback);
AuditQueryParameters params = new AuditQueryParameters();
params.setForward(true);
params.setApplicationName(applicationName);
params.setUser(user);
params.setFromTime(from);
params.setToTime(to);
auditComponent.auditQuery(callback, params, maxResults);
}
/**
* {@inheritDoc}
* @since 3.2
*/
public void auditQuery(
AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue,
int maxResults)
{
ParameterCheck.mandatory("callback", callback);
AuditQueryParameters params = new AuditQueryParameters();
params.setForward(true);
params.setApplicationName(applicationName);
params.setUser(user);
params.setFromTime(from);
params.setToTime(to);
if (searchKey != null || searchValue != null)
{
params.addSearchKey(searchKey, searchValue);
}
auditComponent.auditQuery(callback, params, maxResults);
}
} }

View File

@@ -31,6 +31,13 @@ import org.alfresco.service.PublicService;
@PublicService @PublicService
public interface AuditService public interface AuditService
{ {
/**
* @return Returns <tt>true</tt> if auditing is globally enabled
*
* @since 3.4
*/
boolean isAuditEnabled();
/** /**
* @param applicationName the name of the application to check * @param applicationName the name of the application to check
* @param path the path to check * @param path the path to check
@@ -122,49 +129,4 @@ public interface AuditService
* @since 3.3 * @since 3.3
*/ */
void auditQuery(AuditQueryCallback callback, AuditQueryParameters parameters, int maxResults); void auditQuery(AuditQueryCallback callback, AuditQueryParameters parameters, int maxResults);
/**
* Get the audit entries that match the given criteria.
*
* @param callback the callback that will handle results
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName if not <tt>null</tt>, find entries logged against this application
* @param user if not <tt>null</tt>, find entries logged against this user
* @param from the start search time (<tt>null</tt> to start at the beginning)
* @param to the end search time (<tt>null</tt> for no limit)
* @param maxResults the maximum number of results to retrieve (zero or negative to ignore)
*
* @since 3.2
* @deprecated Use {@link #auditQuery(AuditQueryCallback, AuditQueryParameters)}
*/
void auditQuery(
AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to,
int maxResults);
/**
* Get the audit entries that match the given criteria.
*
* @param callback the callback that will handle results
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName if not <tt>null</tt>, find entries logged against this application
* @param user if not <tt>null</tt>, find entries logged against this user
* @param from the start search time (<tt>null</tt> to start at the beginning)
* @param to the end search time (<tt>null</tt> for no limit)
* @param searchKey the audit key path that must exist (<tt>null</tt> to ignore)
* @param searchValue an audit value that must exist (<tt>null</tt> to ignore)
* @param maxResults the maximum number of results to retrieve (zero or negative to ignore)
*
* @since 3.2
* @deprecated Use {@link #auditQuery(AuditQueryCallback, AuditQueryParameters)}
*/
void auditQuery(
AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue,
int maxResults);
} }