diff --git a/src/core/controllers/oidc.go b/src/core/controllers/oidc.go index 295acb2cf..606c75265 100644 --- a/src/core/controllers/oidc.go +++ b/src/core/controllers/oidc.go @@ -24,11 +24,13 @@ import ( "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/utils" + "github.com/goharbor/harbor/src/controller/event/metadata/commonevent" ctluser "github.com/goharbor/harbor/src/controller/user" "github.com/goharbor/harbor/src/core/api" "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/log" + "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/oidc" ) @@ -38,6 +40,8 @@ const userInfoKey = "oidc_user_info" const redirectURLKey = "oidc_redirect_url" const oidcUserComment = "Onboarded via OIDC provider" +const loginUserOperation = "login_user" + // OIDCController handles requests for OIDC login, callback and user onboard type OIDCController struct { api.BaseController @@ -208,6 +212,19 @@ func (oc *OIDCController) Callback() { redirectURLStr = "/" } oc.Controller.Redirect(redirectURLStr, http.StatusFound) + // The log middleware can capture the OIDC user login event with the URL, but it cannot get the current username from security context because the security context is not ready yet. + // need to create login event in the OIDC login call back logic + // to avoid generate duplicate event in audit log ext, the PreCheck function of the login event intentionally bypass the OIDC user login event in log middleware + // and OIDC's login callback function will create the login event and send it to notification. + if config.AuditLogEventEnabled(ctx, loginUserOperation) { + e := &commonevent.Metadata{ + Ctx: ctx, + Username: u.Username, + RequestMethod: oc.Ctx.Request.Method, + RequestURL: oc.Ctx.Request.URL.String(), + } + notification.AddEvent(e.Ctx, e, true) + } } func userOnboard(ctx context.Context, oc *OIDCController, info *oidc.UserInfo, username string, tokenBytes []byte) (*models.User, bool) { diff --git a/src/pkg/auditext/event/login/login.go b/src/pkg/auditext/event/login/login.go index 00e8dfa4c..4c340a026 100644 --- a/src/pkg/auditext/event/login/login.go +++ b/src/pkg/auditext/event/login/login.go @@ -33,6 +33,7 @@ func init() { var login = &loginResolver{} var logout = &logoutResolver{} commonevent.RegisterResolver(`/c/login$`, login) + commonevent.RegisterResolver(`/c/oidc/callback.*`, login) commonevent.RegisterResolver(`/c/log_out$`, logout) } @@ -54,7 +55,7 @@ func (l *loginResolver) Resolve(ce *commonevent.Metadata, event *event.Event) er OcurrAt: time.Now(), Operation: opLogin, OperationDescription: opLogin, - IsSuccessful: true, + IsSuccessful: ce.ResponseCode <= http.StatusTemporaryRedirect, } // Extract the username from payload @@ -65,9 +66,10 @@ func (l *loginResolver) Resolve(ce *commonevent.Metadata, event *event.Event) er e.ResourceName = match[1] e.Operator = match[1] } - } - if ce.ResponseCode != http.StatusOK { - e.IsSuccessful = false + } else if ce.RequestMethod == http.MethodGet { + e.IsSuccessful = true // for OIDC login event, always success + e.Operator = ce.Username + e.ResourceName = ce.Username } event.Topic = ctlevent.TopicCommonEvent event.Data = e