diff --git a/src/common/security/authcontext/authcontext.go b/src/common/security/authcontext/authcontext.go index 266d0f7ee..7cc4ba005 100644 --- a/src/common/security/authcontext/authcontext.go +++ b/src/common/security/authcontext/authcontext.go @@ -23,6 +23,7 @@ import ( "strings" ) +// TODO update the value of role when admiral API is ready const ( // AuthTokenHeader is the key of auth token header AuthTokenHeader = "x-xenon-auth-token" @@ -32,16 +33,19 @@ const ( guestRole = "GUEST" ) -var client = &http.Client{ - Transport: &http.Transport{}, +type project struct { + DocumentSelfLink string `json:"documentSelfLink"` + Name string `json:"name"` + Roles []string `json:"roles"` } // AuthContext ... type AuthContext struct { - PrincipalID string `json:"principalId"` - Name string `json:"name"` - Roles []string `json:"projects"` - Projects map[string][]string `json:"roles"` + PrincipalID string `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Roles []string `json:"roles"` + Projects []*project `json:"projects"` } // GetUsername ... @@ -53,7 +57,6 @@ func (a *AuthContext) GetUsername() string { func (a *AuthContext) IsSysAdmin() bool { isSysAdmin := false for _, role := range a.Roles { - // TODO update the value of role when admiral API is ready if role == sysAdminRole { isSysAdmin = true break @@ -63,14 +66,14 @@ func (a *AuthContext) IsSysAdmin() bool { } // HasReadPerm ... -func (a *AuthContext) HasReadPerm(project string) bool { - _, exist := a.Projects[project] - return exist +func (a *AuthContext) HasReadPerm(projectName string) bool { + roles := a.getRoles(projectName) + return len(roles) > 0 } // HasWritePerm ... -func (a *AuthContext) HasWritePerm(project string) bool { - roles, _ := a.Projects[project] +func (a *AuthContext) HasWritePerm(projectName string) bool { + roles := a.getRoles(projectName) for _, role := range roles { if role == projectAdminRole || role == developerRole { return true @@ -80,8 +83,8 @@ func (a *AuthContext) HasWritePerm(project string) bool { } // HasAllPerm ... -func (a *AuthContext) HasAllPerm(project string) bool { - roles, _ := a.Projects[project] +func (a *AuthContext) HasAllPerm(projectName string) bool { + roles := a.getRoles(projectName) for _, role := range roles { if role == projectAdminRole { return true @@ -90,66 +93,57 @@ func (a *AuthContext) HasAllPerm(project string) bool { return false } -// GetMyProjects returns all projects which the user is a member of -func (a *AuthContext) GetMyProjects() ([]string, error) { - existence := map[string]bool{} - projects := []string{} - for _, list := range a.Projects { - for _, p := range list { - if existence[p] { - continue - } - existence[p] = true - projects = append(projects, p) +func (a *AuthContext) getRoles(projectName string) []string { + for _, project := range a.Projects { + if project.Name == projectName { + return project.Roles } - } - return projects, nil + + return []string{} } -// GetByToken ... -func GetByToken(url, token string) (*AuthContext, error) { - return get(url, token) +// GetMyProjects returns all projects which the user is a member of +func (a *AuthContext) GetMyProjects() []string { + projects := []string{} + for _, project := range a.Projects { + projects = append(projects, project.Name) + } + return projects } -// GetAuthCtxOfUser gets the user's auth context -func GetAuthCtxOfUser(url, token string, username string) (*AuthContext, error) { - return get(url, token, username) +// GetAuthCtxOfCurrentUser returns the auth context of the current user +func GetAuthCtxOfCurrentUser(client *http.Client, url, token string) (*AuthContext, error) { + return get(client, url, token) +} + +// GetAuthCtxOfSpecificUser returns the auth context of the specific user +func GetAuthCtxOfSpecificUser(client *http.Client, url, token string, username string) (*AuthContext, error) { + return get(client, url, token, username) } // get the user's auth context, if the username is not provided // get the default auth context of the token -func get(url, token string, username ...string) (*AuthContext, error) { - principalID := "" - if len(username) > 0 { - principalID = username[0] +func get(client *http.Client, url, token string, username ...string) (*AuthContext, error) { + endpoint := "" + if len(username) > 0 && len(username[0]) > 0 { + endpoint = buildSpecificUserAuthCtxURL(url, username[0]) + } else { + endpoint = buildCurrentUserAuthCtxURL(url) } - req, err := http.NewRequest(http.MethodGet, buildCtxURL(url, principalID), nil) + + req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { return nil, err } req.Header.Add(AuthTokenHeader, token) - code, _, data, err := send(req) - - if code != http.StatusOK { - return nil, fmt.Errorf("failed to get auth context by token: %d %s", - code, string(data)) - } - - ctx := &AuthContext{ - Projects: make(map[string][]string), - } - if err = json.Unmarshal(data, ctx); err != nil { - return nil, err - } - - return ctx, nil + return send(client, req) } -// Login with credential and returns token, auth context and error -func Login(url, username, password string) (string, *AuthContext, error) { +// Login with credential and returns auth context and error +func Login(client *http.Client, url, username, password string) (*AuthContext, error) { data, err := json.Marshal(&struct { Username string `json:"username"` Password string `json:"password"` @@ -158,52 +152,51 @@ func Login(url, username, password string) (string, *AuthContext, error) { Password: password, }) if err != nil { - return "", nil, err + return nil, err } req, err := http.NewRequest(http.MethodPost, buildLoginURL(url), bytes.NewBuffer(data)) if err != nil { - return "", nil, err + 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 + return send(client, req) } -func send(req *http.Request) (int, http.Header, []byte, error) { +func send(client *http.Client, req *http.Request) (*AuthContext, error) { resp, err := client.Do(req) if err != nil { - return 0, nil, nil, err + return nil, err } defer resp.Body.Close() data, err := ioutil.ReadAll(resp.Body) if err != nil { - return 0, nil, nil, err + return nil, err } - return resp.StatusCode, resp.Header, data, nil + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code: %d %s", resp.StatusCode, string(data)) + } + + ctx := &AuthContext{} + if err = json.Unmarshal(data, ctx); err != nil { + return nil, err + } + + return ctx, nil } -func buildCtxURL(url, principalID string) string { - url = strings.TrimRight(url, "/") + "/sso/auth-context" - if len(principalID) > 0 { - url += "/" + principalID - } - return url +func buildCurrentUserAuthCtxURL(url string) string { + return strings.TrimRight(url, "/") + "/auth/session" } +func buildSpecificUserAuthCtxURL(url, principalID string) string { + return fmt.Sprintf("%s/auth/idm/principals/%s/security-context", + strings.TrimRight(url, "/"), principalID) +} + +// TODO update the url func buildLoginURL(url string) string { return strings.TrimRight(url, "/") + "/sso/login" } diff --git a/src/ui/api/project.go b/src/ui/api/project.go index 8561140e2..1743b1097 100644 --- a/src/ui/api/project.go +++ b/src/ui/api/project.go @@ -79,12 +79,18 @@ func (p *ProjectAPI) Post() { p.HandleUnauthorized() return } - - onlyAdmin, err := config.OnlyAdminCreateProject() - if err != nil { - log.Errorf("failed to determine whether only admin can create projects: %v", err) - p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) + var onlyAdmin bool + var err error + if config.WithAdmiral() { + onlyAdmin = true + } else { + onlyAdmin, err = config.OnlyAdminCreateProject() + if err != nil { + log.Errorf("failed to determine whether only admin can create projects: %v", err) + p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) + } } + if onlyAdmin && !p.SecurityCtx.IsSysAdmin() { log.Errorf("Only sys admin can create project") p.RenderError(http.StatusForbidden, "Only system admin can create project") diff --git a/src/ui/config/config.go b/src/ui/config/config.go index f4e7a394e..449ab7b72 100644 --- a/src/ui/config/config.go +++ b/src/ui/config/config.go @@ -113,14 +113,14 @@ func initProjectManager() { // integration with admiral log.Info("initializing the project manager based on PMS...") // TODO read ca/cert file and pass it to the TLS config - AdminserverClient := &http.Client{ + AdmiralClient = &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, } - GlobalProjectMgr = pms.NewProjectManager(AdminserverClient, + GlobalProjectMgr = pms.NewProjectManager(AdmiralClient, AdmiralEndpoint(), &pms.FileTokenReader{ Path: defaultTokenFilePath, }) diff --git a/src/ui/filter/security.go b/src/ui/filter/security.go index 6b56ec3bc..aca52d7d7 100644 --- a/src/ui/filter/security.go +++ b/src/ui/filter/security.go @@ -131,7 +131,8 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool { if config.WithAdmiral() { // integration with admiral - _, authCtx, err := authcontext.Login(config.AdmiralEndpoint(), username, password) + authCtx, err := authcontext.Login(config.AdmiralClient, + config.AdmiralEndpoint(), username, password) if err != nil { log.Errorf("failed to authenticate %s: %v", username, err) return false @@ -203,7 +204,8 @@ func (t *tokenReqCtxModifier) Modify(ctx *beegoctx.Context) bool { log.Debug("got token from request") - authContext, err := authcontext.GetByToken(config.AdmiralEndpoint(), token) + authContext, err := authcontext.GetAuthCtxOfCurrentUser(config.AdmiralClient, + config.AdmiralEndpoint(), token) if err != nil { log.Errorf("failed to get auth context: %v", err) return false diff --git a/src/ui/projectmanager/pms/pm.go b/src/ui/projectmanager/pms/pm.go index 4f8479797..df3e23eed 100644 --- a/src/ui/projectmanager/pms/pm.go +++ b/src/ui/projectmanager/pms/pm.go @@ -304,16 +304,12 @@ func (p *ProjectManager) GetPublic() ([]*models.Project, error) { // GetByMember ... func (p *ProjectManager) GetByMember(username string) ([]*models.Project, error) { projects := []*models.Project{} - ctx, err := authcontext.GetAuthCtxOfUser(p.endpoint, p.getToken(), username) - if err != nil { - return projects, err - } - - names, err := ctx.GetMyProjects() + ctx, err := authcontext.GetAuthCtxOfSpecificUser(p.client, p.endpoint, p.getToken(), username) if err != nil { return projects, err } + names := ctx.GetMyProjects() for _, name := range names { project, err := p.Get(name) if err != nil {