Redirect regular user to OIDC login page (#7717)

When the auth mode is OIDC, when a user login via Harbor's login form.
If the user does not exist or the user is onboarded via OIDC, he will be
redirected to the OIDC login page.

Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
Daniel Jiang 2019-05-09 10:53:40 +08:00 committed by Wang Yan
parent 1828537672
commit cbbf2ea973
4 changed files with 49 additions and 1 deletions

View File

@ -139,6 +139,7 @@ const (
RobotTokenDuration = "robot_token_duration"
OIDCCallbackPath = "/c/oidc/callback"
OIDCLoginPath = "/c/oidc/login"
ChartUploadCtxKey = contextKey("chart_upload_event")
)

View File

@ -16,12 +16,15 @@ package controllers
import (
"bytes"
"context"
"github.com/goharbor/harbor/src/core/filter"
"html/template"
"net"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"github.com/astaxie/beego"
"github.com/beego/i18n"
@ -54,10 +57,43 @@ type messageDetail struct {
UUID string
}
func redirectForOIDC(ctx context.Context, username string) bool {
am, _ := ctx.Value(filter.AuthModeKey).(string)
if am != common.OIDCAuth {
return false
}
u, err := dao.GetUser(models.User{Username: username})
if err != nil {
log.Warningf("Failed to get user by name: %s, error: %v", username, err)
}
if u == nil {
return true
}
ou, err := dao.GetOIDCUserByUserID(u.UserID)
if err != nil {
log.Warningf("Failed to get OIDC user info for user, id: %d, error: %v", u.UserID, err)
}
if ou != nil {
return true
}
return false
}
// Login handles login request from UI.
func (cc *CommonController) Login() {
principal := cc.GetString("principal")
password := cc.GetString("password")
if redirectForOIDC(cc.Ctx.Request.Context(), principal) {
ep, err := config.ExtEndpoint()
if err != nil {
log.Errorf("Failed to get the external endpoint, error: %v", err)
cc.CustomAbort(http.StatusUnauthorized, "")
}
url := strings.TrimSuffix(ep, "/") + common.OIDCLoginPath
log.Debugf("Redirect user %s to login page of OIDC provider", principal)
cc.Redirect(url, http.StatusFound)
return
}
user, err := auth.Login(models.AuthModel{
Principal: principal,

View File

@ -14,6 +14,8 @@
package controllers
import (
"context"
"github.com/goharbor/harbor/src/core/filter"
"net/http"
"net/http/httptest"
// "net/url"
@ -90,6 +92,15 @@ func TestUserResettable(t *testing.T) {
assert.True(isUserResetable(u1))
}
func TestRedirectForOIDC(t *testing.T) {
ctx := context.WithValue(context.Background(), filter.AuthModeKey, common.DBAuth)
assert.False(t, redirectForOIDC(ctx, "nonexist"))
ctx = context.WithValue(context.Background(), filter.AuthModeKey, common.OIDCAuth)
assert.True(t, redirectForOIDC(ctx, "nonexist"))
assert.False(t, redirectForOIDC(ctx, "admin"))
}
// TestMain is a sample to run an endpoint test
func TestAll(t *testing.T) {
config.InitWithSettings(utilstest.GetUnitTestConfig())

View File

@ -38,7 +38,7 @@ func initRouters() {
beego.Router("/c/reset", &controllers.CommonController{}, "post:ResetPassword")
beego.Router("/c/userExists", &controllers.CommonController{}, "post:UserExists")
beego.Router("/c/sendEmail", &controllers.CommonController{}, "get:SendResetEmail")
beego.Router("/c/oidc/login", &controllers.OIDCController{}, "get:RedirectLogin")
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")