From 7321e3547db50cc2ad5f909cc3fceb3d663c1cd1 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Tue, 15 Dec 2020 17:08:01 +0800 Subject: [PATCH] Add handler to handle redirect via authproxy This commit add a handler to handle the request to "/c/authproxy/redirect". Harbor is configured to authenticate against an authproxy, if a request with query string `?token=xxxx` is sent to this URI, the handler will do tokenreview according to the setting of authproxy and simulate a `login` workflow based on the result of token review. Signed-off-by: Daniel Jiang --- src/common/const.go | 2 + src/core/api/base.go | 1 - src/core/auth/authproxy/auth.go | 8 +++ src/core/controllers/authproxy_redirect.go | 65 ++++++++++++++++++++++ src/server/route.go | 1 + 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/core/controllers/authproxy_redirect.go diff --git a/src/common/const.go b/src/common/const.go index aec7424b8..deb6afeb4 100755 --- a/src/common/const.go +++ b/src/common/const.go @@ -145,6 +145,8 @@ const ( OIDCCallbackPath = "/c/oidc/callback" OIDCLoginPath = "/c/oidc/login" + AuthProxyRediretPath = "/c/authproxy/redirect" + ChartUploadCtxKey = contextKey("chart_upload_event") ChartDownloadCtxKey = contextKey("chart_download_event") diff --git a/src/core/api/base.go b/src/core/api/base.go index 7356afb98..02e7fb286 100644 --- a/src/core/api/base.go +++ b/src/core/api/base.go @@ -147,7 +147,6 @@ func (b *BaseController) SendPermissionError() { } else { b.SendForbiddenError(errors.New(b.SecurityCtx.GetUsername())) } - } // WriteJSONData writes the JSON data to the client. diff --git a/src/core/auth/authproxy/auth.go b/src/core/auth/authproxy/auth.go index 0a88e5bf9..0ea97bf3b 100644 --- a/src/core/auth/authproxy/auth.go +++ b/src/core/auth/authproxy/auth.go @@ -123,6 +123,14 @@ func (a *Auth) tokenReview(sessionID string) (*models.User, error) { return u, nil } +// VerifyToken reviews the token to generate the user model +func (a *Auth) VerifyToken(token string) (*models.User, error) { + if err := a.ensure(); err != nil { + return nil, err + } + return a.tokenReview(token) +} + // OnBoardUser delegates to dao pkg to insert/update data in DB. func (a *Auth) OnBoardUser(u *models.User) error { return dao.OnBoardUser(u) diff --git a/src/core/controllers/authproxy_redirect.go b/src/core/controllers/authproxy_redirect.go new file mode 100644 index 000000000..e88295c95 --- /dev/null +++ b/src/core/controllers/authproxy_redirect.go @@ -0,0 +1,65 @@ +package controllers + +import ( + "fmt" + "net/http" + + "github.com/goharbor/harbor/src/common" + "github.com/goharbor/harbor/src/core/api" + "github.com/goharbor/harbor/src/core/auth/authproxy" + "github.com/goharbor/harbor/src/core/config" + "github.com/goharbor/harbor/src/lib/log" +) + +const ( + authproxyTokenKey = "token" + postURIKey = "postURI" +) + +var helper = &authproxy.Auth{} + +// AuthProxyController handles requests with token that can be reviewed by authproxy. +type AuthProxyController struct { + api.BaseController +} + +// Prepare checks the auth mode and fail early +func (apc *AuthProxyController) Prepare() { + am, err := config.AuthMode() + if err != nil { + apc.SendInternalServerError(err) + return + } + if am != common.HTTPAuth { + apc.SendPreconditionFailedError(fmt.Errorf("the auth mode %s does not support this flow", am)) + return + } +} + +// HandleRedirect reviews the token and login the user based on the review status. +func (apc *AuthProxyController) HandleRedirect() { + token := apc.Ctx.Request.URL.Query().Get(authproxyTokenKey) + if token == "" { + log.Errorf("No token found in request.") + apc.Ctx.Redirect(http.StatusMovedPermanently, "/") + return + } + u, err := helper.VerifyToken(token) + if err != nil { + log.Errorf("Failed to verify token, error: %v", err) + apc.Ctx.Redirect(http.StatusMovedPermanently, "/") + return + } + if err := helper.PostAuthenticate(u); err != nil { + log.Errorf("Failed to onboard user, error: %v", err) + apc.Ctx.Redirect(http.StatusMovedPermanently, "/") + return + } + apc.PopulateUserSession(*u) + uri := apc.Ctx.Request.URL.Query().Get(postURIKey) + if uri == "" { + uri = "/" + } + apc.Ctx.Redirect(http.StatusMovedPermanently, uri) + return +} diff --git a/src/server/route.go b/src/server/route.go index 25713a2b9..81969e5ae 100644 --- a/src/server/route.go +++ b/src/server/route.go @@ -40,6 +40,7 @@ func registerRoutes() { beego.Router(common.OIDCLoginPath, &controllers.OIDCController{}, "get:RedirectLogin") beego.Router("/c/oidc/onboard", &controllers.OIDCController{}, "post:Onboard") beego.Router(common.OIDCCallbackPath, &controllers.OIDCController{}, "get:Callback") + beego.Router(common.AuthProxyRediretPath, &controllers.AuthProxyController{}, "get:HandleRedirect") beego.Router("/api/internal/configurations", &api.ConfigAPI{}, "get:GetInternalConfig;put:Put") beego.Router("/api/internal/renameadmin", &api.InternalAPI{}, "post:RenameAdmin")