mirror of
https://github.com/goharbor/harbor
synced 2025-04-12 22:50:55 +00:00
Implement audit log ext API (#21414)
Signed-off-by: stonezdj <stone.zhang@broadcom.com>
This commit is contained in:
parent
3b655213c0
commit
4d5bc19866
|
@ -6940,6 +6940,7 @@ definitions:
|
|||
description: The operation's detail description
|
||||
operation_result:
|
||||
type: boolean
|
||||
x-omitempty: false
|
||||
description: the operation's result, true for success, false for fail
|
||||
op_time:
|
||||
type: string
|
||||
|
|
|
@ -127,8 +127,6 @@ var (
|
|||
|
||||
{Resource: rbac.ResourceMetadata, Action: rbac.ActionRead},
|
||||
|
||||
{Resource: rbac.ResourceLog, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceQuota, Action: rbac.ActionRead},
|
||||
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionCreate},
|
||||
|
@ -199,8 +197,6 @@ var (
|
|||
{Resource: rbac.ResourceMember, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceMember, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceLog, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionList},
|
||||
|
||||
|
@ -254,8 +250,6 @@ var (
|
|||
{Resource: rbac.ResourceMember, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceMember, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceLog, Action: rbac.ActionList},
|
||||
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionRead},
|
||||
{Resource: rbac.ResourceLabel, Action: rbac.ActionList},
|
||||
|
||||
|
|
|
@ -28,21 +28,25 @@ import (
|
|||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/audit"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/restapi/operations/auditlog"
|
||||
)
|
||||
|
||||
func newAuditLogAPI() *auditlogAPI {
|
||||
return &auditlogAPI{
|
||||
auditMgr: audit.Mgr,
|
||||
projectCtl: project.Ctl,
|
||||
auditMgr: audit.Mgr,
|
||||
auditextMgr: auditext.Mgr,
|
||||
projectCtl: project.Ctl,
|
||||
}
|
||||
}
|
||||
|
||||
type auditlogAPI struct {
|
||||
BaseAPI
|
||||
auditMgr audit.Manager
|
||||
projectCtl project.Controller
|
||||
auditMgr audit.Manager
|
||||
auditextMgr auditext.Manager
|
||||
projectCtl project.Controller
|
||||
}
|
||||
|
||||
func (a *auditlogAPI) ListAuditLogs(ctx context.Context, params auditlog.ListAuditLogsParams) middleware.Responder {
|
||||
|
@ -111,14 +115,85 @@ func (a *auditlogAPI) ListAuditLogs(ctx context.Context, params auditlog.ListAud
|
|||
WithPayload(auditLogs)
|
||||
}
|
||||
func (a *auditlogAPI) ListAuditLogExts(ctx context.Context, params auditlog.ListAuditLogExtsParams) middleware.Responder {
|
||||
// TODO: implement this method
|
||||
secCtx, ok := security.FromContext(ctx)
|
||||
if !ok {
|
||||
return a.SendError(ctx, errors.UnauthorizedError(errors.New("security context not found")))
|
||||
}
|
||||
if !secCtx.IsAuthenticated() {
|
||||
return a.SendError(ctx, errors.UnauthorizedError(nil).WithMessage(secCtx.GetUsername()))
|
||||
}
|
||||
query, err := a.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
|
||||
if err := a.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceAuditLog); err != nil {
|
||||
ol := &q.OrList{}
|
||||
if sc, ok := secCtx.(*local.SecurityContext); ok && sc.IsAuthenticated() {
|
||||
user := sc.User()
|
||||
member := &project.MemberQuery{
|
||||
UserID: user.UserID,
|
||||
GroupIDs: user.GroupIDs,
|
||||
}
|
||||
|
||||
projects, err := a.projectCtl.List(ctx, q.New(q.KeyWords{"member": member}), project.Metadata(false))
|
||||
if err != nil {
|
||||
return a.SendError(ctx, fmt.Errorf(
|
||||
"failed to get projects of user %s: %v", secCtx.GetUsername(), err))
|
||||
}
|
||||
for _, project := range projects {
|
||||
if a.HasProjectPermission(ctx, project.ProjectID, rbac.ActionList, rbac.ResourceLog) {
|
||||
ol.Values = append(ol.Values, project.ProjectID)
|
||||
}
|
||||
}
|
||||
}
|
||||
// make sure no project will be selected with the query
|
||||
if len(ol.Values) == 0 {
|
||||
ol.Values = append(ol.Values, -1)
|
||||
}
|
||||
query.Keywords["ProjectID"] = ol
|
||||
}
|
||||
|
||||
total, err := a.auditextMgr.Count(ctx, query)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
logs, err := a.auditextMgr.List(ctx, query)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
return auditlog.NewListAuditLogExtsOK().
|
||||
WithXTotalCount(0).
|
||||
WithLink(a.Links(ctx, params.HTTPRequest.URL, 0, 0, 0).String()).
|
||||
WithPayload(nil)
|
||||
WithXTotalCount(total).
|
||||
WithLink(a.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
|
||||
WithPayload(convertToModelAuditLogExt(logs))
|
||||
}
|
||||
|
||||
func (a *auditlogAPI) ListAuditLogEventTypes(_ context.Context, _ auditlog.ListAuditLogEventTypesParams) middleware.Responder {
|
||||
// TODO: implement this method
|
||||
return auditlog.NewListAuditLogEventTypesOK().WithPayload(nil)
|
||||
func (a *auditlogAPI) ListAuditLogEventTypes(ctx context.Context, _ auditlog.ListAuditLogEventTypesParams) middleware.Responder {
|
||||
if err := a.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceAuditLog); err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
var eventTypes []*models.AuditLogEventType
|
||||
for _, v := range model.EventTypes {
|
||||
eventTypes = append(eventTypes, &models.AuditLogEventType{
|
||||
EventType: v,
|
||||
})
|
||||
}
|
||||
return auditlog.NewListAuditLogEventTypesOK().WithPayload(eventTypes)
|
||||
}
|
||||
|
||||
func convertToModelAuditLogExt(logs []*model.AuditLogExt) []*models.AuditLogExt {
|
||||
var auditLogs []*models.AuditLogExt
|
||||
for _, log := range logs {
|
||||
auditLogs = append(auditLogs, &models.AuditLogExt{
|
||||
ID: log.ID,
|
||||
Resource: log.Resource,
|
||||
ResourceType: log.ResourceType,
|
||||
Username: log.Username,
|
||||
Operation: log.Operation,
|
||||
OperationDescription: log.OperationDescription,
|
||||
OperationResult: log.OperationResult,
|
||||
OpTime: strfmt.DateTime(log.OpTime),
|
||||
})
|
||||
}
|
||||
return auditLogs
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import (
|
|||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg"
|
||||
"github.com/goharbor/harbor/src/pkg/audit"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext"
|
||||
"github.com/goharbor/harbor/src/pkg/member"
|
||||
"github.com/goharbor/harbor/src/pkg/project/metadata"
|
||||
pkgModels "github.com/goharbor/harbor/src/pkg/project/models"
|
||||
|
@ -66,6 +67,7 @@ func newProjectAPI() *projectAPI {
|
|||
return &projectAPI{
|
||||
auditMgr: audit.Mgr,
|
||||
artCtl: artifact.Ctl,
|
||||
auditextMgr: auditext.Mgr,
|
||||
metadataMgr: pkg.ProjectMetaMgr,
|
||||
userCtl: user.Ctl,
|
||||
repositoryCtl: repository.Ctl,
|
||||
|
@ -82,6 +84,7 @@ func newProjectAPI() *projectAPI {
|
|||
type projectAPI struct {
|
||||
BaseAPI
|
||||
auditMgr audit.Manager
|
||||
auditextMgr auditext.Manager
|
||||
artCtl artifact.Controller
|
||||
metadataMgr metadata.Manager
|
||||
userCtl user.Controller
|
||||
|
@ -940,9 +943,29 @@ func highestRole(roles []int) int {
|
|||
}
|
||||
|
||||
func (a *projectAPI) GetLogExts(ctx context.Context, params operation.GetLogExtsParams) middleware.Responder {
|
||||
// TODO: implement the function
|
||||
if err := a.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionList, rbac.ResourceLog); err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
pro, err := a.projectCtl.GetByName(ctx, params.ProjectName)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
query, err := a.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
query.Keywords["ProjectID"] = pro.ProjectID
|
||||
|
||||
total, err := a.auditextMgr.Count(ctx, query)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
logs, err := a.auditextMgr.List(ctx, query)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
return operation.NewGetLogExtsOK().
|
||||
WithXTotalCount(0).
|
||||
WithLink(a.Links(ctx, params.HTTPRequest.URL, 0, 0, 15).String()).
|
||||
WithPayload(nil)
|
||||
WithXTotalCount(total).
|
||||
WithLink(a.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
|
||||
WithPayload(convertToModelAuditLogExt(logs))
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class TestAssignRoleToLdapGroup(unittest.TestCase):
|
|||
self.project.add_project_members(project_id, member_role_id = 3, _ldap_group_dn = "cn=harbor_guest,ou=groups,dc=example,dc=com", **ADMIN_CLIENT)
|
||||
|
||||
projects = self.project.get_projects(dict(name=project_name), **USER_ADMIN)
|
||||
self.assertTrue(len(projects) == 1)
|
||||
self.assertTrue(len(projects) == 1)
|
||||
self.assertEqual(1, projects[0].current_user_role_id)
|
||||
|
||||
#Mike has logged in harbor in previous test.
|
||||
|
@ -80,8 +80,8 @@ class TestAssignRoleToLdapGroup(unittest.TestCase):
|
|||
self.assertTrue(len(artifacts) == 0)
|
||||
|
||||
self.assertTrue(self.project.query_user_logs(project_name, **USER_ADMIN)>0, "admin user can see logs")
|
||||
self.assertTrue(self.project.query_user_logs(project_name, **USER_DEV)>0, "dev user can see logs")
|
||||
self.assertTrue(self.project.query_user_logs(project_name, **USER_GUEST)>0, "guest user can see logs")
|
||||
self.assertTrue(self.project.query_user_logs(project_name, status_code=403, **USER_DEV)==0, "dev user can not see any logs")
|
||||
self.assertTrue(self.project.query_user_logs(project_name, status_code=403, **USER_GUEST)==0, "guest user can not see any logs")
|
||||
self.assertTrue(self.project.query_user_logs(project_name, status_code=403, **USER_TEST)==0, "test user can not see any logs")
|
||||
|
||||
self.repo.delete_repository(project_name, repo_name_admin.split('/')[1], **USER_ADMIN)
|
||||
|
|
Loading…
Reference in New Issue
Block a user