From 94822746f14507f7bf6fba2cfe1fdbff8eff43f1 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Wed, 21 Jun 2017 17:50:36 +0800 Subject: [PATCH] implement admiral login --- .../security/authcontext/authcontext.go | 76 +++++++++++++++---- src/ui/filter/security.go | 54 +++++++------ 2 files changed, 93 insertions(+), 37 deletions(-) diff --git a/src/common/security/authcontext/authcontext.go b/src/common/security/authcontext/authcontext.go index a9b924449..b0b0b5bef 100644 --- a/src/common/security/authcontext/authcontext.go +++ b/src/common/security/authcontext/authcontext.go @@ -15,6 +15,7 @@ package authcontext import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -93,29 +94,18 @@ func (a *AuthContext) HasAllPerm(project string) bool { // GetByToken ... func GetByToken(token string) (*AuthContext, error) { - endpoint := config.AdmiralEndpoint() - path := strings.TrimRight(endpoint, "/") + "/sso/auth-context" - req, err := http.NewRequest(http.MethodGet, path, nil) + req, err := http.NewRequest(http.MethodGet, buildCtxURL(), nil) if err != nil { return nil, err } req.Header.Add(AuthTokenHeader, token) - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() + code, _, data, err := send(req) - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusOK { + if code != http.StatusOK { return nil, fmt.Errorf("failed to get auth context by token: %d %s", - resp.StatusCode, string(data)) + code, string(data)) } ctx := &AuthContext{ @@ -127,3 +117,59 @@ func GetByToken(token string) (*AuthContext, error) { return ctx, nil } + +// Login ... +func Login(username, password string) (string, *AuthContext, error) { + data, err := json.Marshal(&struct { + Username string `json:"username"` + Password string `json:"password"` + }{ + Username: username, + Password: password, + }) + if err != nil { + return "", nil, err + } + + req, err := http.NewRequest(http.MethodPost, buildLoginURL(), bytes.NewBuffer(data)) + if err != nil { + return "", nil, err + } + + code, header, data, err := send(req) + if code != http.StatusOK { + return "", nil, fmt.Errorf("failed to login with user %s: %d %s", username, + code, string(data)) + } + + ctx := &AuthContext{ + Projects: make(map[string][]string), + } + if err = json.Unmarshal(data, ctx); err != nil { + return "", nil, err + } + + return header.Get(AuthTokenHeader), ctx, nil +} + +func send(req *http.Request) (int, http.Header, []byte, error) { + resp, err := client.Do(req) + if err != nil { + return 0, nil, nil, err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return 0, nil, nil, err + } + return resp.StatusCode, resp.Header, data, nil +} + +func buildCtxURL() string { + return strings.TrimRight(config.AdmiralEndpoint(), "/") + "/sso/auth-context" +} + +func buildLoginURL() string { + return strings.TrimRight(config.AdmiralEndpoint(), "/") + "/sso/login" +} diff --git a/src/ui/filter/security.go b/src/ui/filter/security.go index 10e0f720d..d447cc3cc 100644 --- a/src/ui/filter/security.go +++ b/src/ui/filter/security.go @@ -51,6 +51,7 @@ func Init() { if config.WithAdmiral() { reqCtxModifiers = []ReqCtxModifier{ &secretReqCtxModifier{}, + &basicAuthReqCtxModifier{}, &tokenReqCtxModifier{}, &unauthorizedReqCtxModifier{}} return @@ -123,34 +124,43 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool { if !ok { return false } - - user, err := auth.Login(models.AuthModel{ - Principal: username, - Password: password, - }) - if err != nil { - log.Errorf("failed to authenticate %s: %v", username, err) - return false - } - if user == nil { - return false - } + log.Debug("got user information via basic auth") var securCtx security.Context var pm projectmanager.ProjectManager - log.Debug("got user information via basic auth") + if config.WithAdmiral() { // integration with admiral - // we can add logic here to support basic auth in integration mode - log.Debug("basic auth isn't supported in integration mode") - return false - } + token, authCtx, err := authcontext.Login(username, password) + if err != nil { + log.Errorf("failed to authenticate %s: %v", username, err) + return false + } - // standalone - log.Debug("using local database project manager") - pm = config.GlobalProjectMgr - log.Debug("creating local database security context...") - securCtx = local.NewSecurityContext(user, pm) + log.Debug("creating PMS project manager...") + pm = pms.NewProjectManager(config.AdmiralEndpoint(), token) + + log.Debug("creating admiral security context...") + securCtx = admiral.NewSecurityContext(authCtx, pm) + } else { + // standalone + user, err := auth.Login(models.AuthModel{ + Principal: username, + Password: password, + }) + if err != nil { + log.Errorf("failed to authenticate %s: %v", username, err) + return false + } + if user == nil { + log.Debug("basic auth user is nil") + return false + } + log.Debug("using local database project manager") + pm = config.GlobalProjectMgr + log.Debug("creating local database security context...") + securCtx = local.NewSecurityContext(user, pm) + } setSecurCtxAndPM(ctx.Request, securCtx, pm)