mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-17 04:11:24 +01:00
update codes of auth context
This commit is contained in:
parent
2818c047bf
commit
3ebe1a824b
@ -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"
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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,
|
||||
})
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user