Audit hooks on JSON/RPC and SSH commands using Gerrit plugins.

New @Audit annotation to enable invocation of
AuditService injected on GerritGlobalModule.

Annotation applies to JSON/RPC interfaces whilst
on the SSH side audit is "hooked" directly into
SshLog class.

Enables the integration of Audit plugins through
the implementation of audit-listeners.
Dynamic loading and unloading of audit plugins is supported
through the @Extension/@Listener association and
automatically loaded and unloaded using Plugin
module self-registration.

In order to implement a new AuditListener implementation
you only to:

1) Define an implementation of AuditListener and annotate
as:

@Listener
public class MyAuditTrail extends AuditListener

2) Define a Plugin Module to bind your Audit implementation
in the configure() method as:

DynamicSet.bind(binder(), AuditListener.class)
  .to(MyAuditTrail.class);

Change-Id: Iaa26c4687a4ef4cbe27fe8396a5e0b8f6627536f
Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
This commit is contained in:
Luca Milanesio
2012-04-13 11:12:18 +01:00
committed by Edwin Kempin
parent d5e87c3aad
commit 27ba2ac5e6
20 changed files with 592 additions and 10 deletions

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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 com.google.gerrit.common.audit;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Audit annotation for JSON/RPC interfaces.
*
* Flag with @Audit all the JSON/RPC methods to
* be traced in audit-trail and submitted to the
* AuditService.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Audit {
String action() default "";
/** List of positions of parameters to be obfuscated in audit-trail (i.e. passwords) */
int[] obfuscate() default {};
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.auth.userpass;
import com.google.gerrit.common.audit.Audit;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtjsonrpc.common.AllowCrossSiteRequest;
import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -22,6 +23,7 @@ import com.google.gwtjsonrpc.common.RpcImpl.Version;
@RpcImpl(version = Version.V2_0)
public interface UserPassAuthService extends RemoteJsonService {
@Audit(action = "sign in", obfuscate={1})
@AllowCrossSiteRequest
void authenticate(String username, String password,
AsyncCallback<LoginResult> callback);

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId;
@@ -33,20 +34,25 @@ public interface AccountSecurity extends RemoteJsonService {
@SignInRequired
void mySshKeys(AsyncCallback<List<AccountSshKey>> callback);
@Audit
@SignInRequired
void addSshKey(String keyText, AsyncCallback<AccountSshKey> callback);
@Audit
@SignInRequired
void deleteSshKeys(Set<AccountSshKey.Id> ids,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void changeUserName(String newName, AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void generatePassword(AccountExternalId.Key key,
AsyncCallback<AccountExternalId> callback);
@Audit
@SignInRequired
void clearPassword(AccountExternalId.Key key,
AsyncCallback<AccountExternalId> gerritCallback);
@@ -57,21 +63,26 @@ public interface AccountSecurity extends RemoteJsonService {
@SignInRequired
void myGroups(AsyncCallback<List<GroupDetail>> callback);
@Audit
@SignInRequired
void deleteExternalIds(Set<AccountExternalId.Key> keys,
AsyncCallback<Set<AccountExternalId.Key>> callback);
@Audit
@SignInRequired
void updateContact(String fullName, String emailAddr,
ContactInformation info, AsyncCallback<Account> callback);
@Audit
@SignInRequired
void enterAgreement(String agreementName,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void registerEmail(String address, AsyncCallback<Account> callback);
@Audit
@SignInRequired
void validateEmail(String token, AsyncCallback<VoidResult> callback);
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
@@ -36,10 +37,12 @@ public interface AccountService extends RemoteJsonService {
@SignInRequired
void myDiffPreferences(AsyncCallback<AccountDiffPreference> callback);
@Audit
@SignInRequired
void changePreferences(AccountGeneralPreferences pref,
AsyncCallback<VoidResult> gerritCallback);
@Audit
@SignInRequired
void changeDiffPreferences(AccountDiffPreference diffPref,
AsyncCallback<VoidResult> callback);
@@ -47,14 +50,17 @@ public interface AccountService extends RemoteJsonService {
@SignInRequired
void myProjectWatch(AsyncCallback<List<AccountProjectWatchInfo>> callback);
@Audit
@SignInRequired
void addProjectWatch(String projectName, String filter,
AsyncCallback<AccountProjectWatchInfo> callback);
@Audit
@SignInRequired
void updateProjectWatch(AccountProjectWatch watch,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void deleteProjectWatches(Set<AccountProjectWatch.Key> keys,
AsyncCallback<VoidResult> callback);

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.Change;
@@ -25,12 +26,16 @@ import com.google.gwtjsonrpc.common.RpcImpl.Version;
@RpcImpl(version = Version.V2_0)
public interface ChangeDetailService extends RemoteJsonService {
@Audit
void changeDetail(Change.Id id, AsyncCallback<ChangeDetail> callback);
@Audit
void includedInDetail(Change.Id id, AsyncCallback<IncludedInDetail> callback);
@Audit
void patchSetDetail(PatchSet.Id key, AsyncCallback<PatchSetDetail> callback);
@Audit
void patchSetDetail2(PatchSet.Id baseId, PatchSet.Id key,
AccountDiffPreference diffPrefs, AsyncCallback<PatchSetDetail> callback);

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -28,6 +29,7 @@ public interface ChangeListService extends RemoteJsonService {
*
* @param req the add and remove cluster.
*/
@Audit
@SignInRequired
void toggleStars(ToggleStarRequest req, AsyncCallback<VoidResult> callback);
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwtjsonrpc.common.AsyncCallback;
@@ -24,27 +25,34 @@ import com.google.gwtjsonrpc.common.RpcImpl.Version;
@RpcImpl(version = Version.V2_0)
public interface ChangeManageService extends RemoteJsonService {
@Audit
@SignInRequired
void submit(PatchSet.Id patchSetId, AsyncCallback<ChangeDetail> callback);
@Audit
@SignInRequired
void abandonChange(PatchSet.Id patchSetId, String message,
AsyncCallback<ChangeDetail> callback);
@Audit
@SignInRequired
void revertChange(PatchSet.Id patchSetId, String message,
AsyncCallback<ChangeDetail> callback);
@Audit
@SignInRequired
void restoreChange(PatchSet.Id patchSetId, String message,
AsyncCallback<ChangeDetail> callback);
@Audit
@SignInRequired
void publish(PatchSet.Id patchSetId, AsyncCallback<ChangeDetail> callback);
@Audit
@SignInRequired
void deleteDraftChange(PatchSet.Id patchSetId, AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void rebaseChange(PatchSet.Id patchSetId, AsyncCallback<ChangeDetail> callback);
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
@@ -28,48 +29,60 @@ import java.util.Set;
@RpcImpl(version = Version.V2_0)
public interface GroupAdminService extends RemoteJsonService {
@Audit
@SignInRequired
void visibleGroups(AsyncCallback<GroupList> callback);
@Audit
@SignInRequired
void createGroup(String newName, AsyncCallback<AccountGroup.Id> callback);
@Audit
@SignInRequired
void groupDetail(AccountGroup.Id groupId, AccountGroup.UUID uuid,
AsyncCallback<GroupDetail> callback);
@Audit
@SignInRequired
void changeGroupDescription(AccountGroup.Id groupId, String description,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void changeGroupOptions(AccountGroup.Id groupId, GroupOptions groupOptions,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void changeGroupOwner(AccountGroup.Id groupId, String newOwnerName,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void renameGroup(AccountGroup.Id groupId, String newName,
AsyncCallback<GroupDetail> callback);
@Audit
@SignInRequired
void changeGroupType(AccountGroup.Id groupId, AccountGroup.Type newType,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void addGroupMember(AccountGroup.Id groupId, String nameOrEmail,
AsyncCallback<GroupDetail> callback);
@Audit
@SignInRequired
void addGroupInclude(AccountGroup.Id groupId, String groupName,
AsyncCallback<GroupDetail> callback);
@Audit
@SignInRequired
void deleteGroupMembers(AccountGroup.Id groupId,
Set<AccountGroupMember.Key> keys, AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void deleteGroupIncludes(AccountGroup.Id groupId,
Set<AccountGroupInclude.Key> keys, AsyncCallback<VoidResult> callback);

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
@@ -34,13 +35,16 @@ import java.util.Set;
@RpcImpl(version = Version.V2_0)
public interface PatchDetailService extends RemoteJsonService {
@Audit
void patchScript(Patch.Key key, PatchSet.Id a, PatchSet.Id b,
AccountDiffPreference diffPrefs, AsyncCallback<PatchScript> callback);
@Audit
@SignInRequired
void saveDraft(PatchLineComment comment,
AsyncCallback<PatchLineComment> callback);
@Audit
@SignInRequired
void deleteDraft(PatchLineComment.Key key, AsyncCallback<VoidResult> callback);
@@ -57,18 +61,22 @@ public interface PatchDetailService extends RemoteJsonService {
* change, then <code>null</code> is passed as result to
* {@link AsyncCallback#onSuccess(Object)}
*/
@Audit
@SignInRequired
void deleteDraftPatchSet(PatchSet.Id psid, AsyncCallback<ChangeDetail> callback);
@Audit
@SignInRequired
void publishComments(PatchSet.Id psid, String message,
Set<ApprovalCategoryValue.Id> approvals,
AsyncCallback<VoidResult> callback);
@Audit
@SignInRequired
void addReviewers(Change.Id id, List<String> reviewers, boolean confirmed,
AsyncCallback<ReviewerResult> callback);
@Audit
@SignInRequired
void removeReviewer(Change.Id id, Account.Id reviewerId,
AsyncCallback<ReviewerResult> callback);
@@ -82,6 +90,7 @@ public interface PatchDetailService extends RemoteJsonService {
/**
* Update the reviewed status for the patch.
*/
@Audit
@SignInRequired
void setReviewedByCurrentUser(Key patchKey, boolean reviewed, AsyncCallback<VoidResult> callback);
}

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
@@ -34,6 +35,7 @@ public interface ProjectAdminService extends RemoteJsonService {
void projectDetail(Project.NameKey projectName,
AsyncCallback<ProjectDetail> callback);
@Audit
@SignInRequired
void createNewProject(String projectName, String parentName,
boolean emptyCommit, boolean permissionsOnly,
@@ -42,10 +44,12 @@ public interface ProjectAdminService extends RemoteJsonService {
void projectAccess(Project.NameKey projectName,
AsyncCallback<ProjectAccess> callback);
@Audit
@SignInRequired
void changeProjectSettings(Project update,
AsyncCallback<ProjectDetail> callback);
@Audit
@SignInRequired
void changeProjectAccess(Project.NameKey projectName, String baseRevision,
String message, List<AccessSection> sections,
@@ -59,10 +63,12 @@ public interface ProjectAdminService extends RemoteJsonService {
void listBranches(Project.NameKey projectName,
AsyncCallback<ListBranchesResult> callback);
@Audit
@SignInRequired
void addBranch(Project.NameKey projectName, String branchName,
String startingRevision, AsyncCallback<ListBranchesResult> callback);
@Audit
@SignInRequired
void deleteBranch(Project.NameKey projectName, Set<Branch.NameKey> ids,
AsyncCallback<Set<Branch.NameKey>> callback);