mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-02 04:51:22 +01:00
support generate UI token for notary
This commit is contained in:
parent
ac6c26d6db
commit
109db458c3
@ -271,6 +271,6 @@ func NewUsernameTokenAuthorizer(username string, scopeType, scopeName string, sc
|
||||
}
|
||||
|
||||
func (u *usernameTokenAuthorizer) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) {
|
||||
token, expiresIn, issuedAt, err = token_util.GenTokenForUI(u.username, service, scopes)
|
||||
token, expiresIn, issuedAt, err = token_util.RegistryTokenForUI(u.username, service, scopes)
|
||||
return
|
||||
}
|
||||
|
@ -74,25 +74,49 @@ func GetResourceActions(scopes []string) []*token.ResourceActions {
|
||||
return res
|
||||
}
|
||||
|
||||
// GenTokenForUI is for the UI process to call, so it won't establish a https connection from UI to proxy.
|
||||
func GenTokenForUI(username string, service string, scopes []string) (string, int, *time.Time, error) {
|
||||
//filterAccess iterate a list of resource actions and try to use the filter that matches the resource type to filter the actions.
|
||||
func filterAccess(access []*token.ResourceActions, u userInfo, filters map[string]accessFilter) error {
|
||||
var err error
|
||||
for _, a := range access {
|
||||
f, ok := filters[a.Type]
|
||||
if !ok {
|
||||
a.Actions = []string{}
|
||||
log.Warningf("No filter found for access type: %s, skip filter, the access of resource '%s' will be set empty.", a.Type, a.Name)
|
||||
continue
|
||||
}
|
||||
err = f.filter(u, a)
|
||||
log.Debugf("user: %s, access: %v", u.name, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//RegistryTokenForUI calls genTokenForUI to get raw token for registry
|
||||
func RegistryTokenForUI(username string, service string, scopes []string) (string, int, *time.Time, error) {
|
||||
return genTokenForUI(username, service, scopes, registryFilterMap)
|
||||
}
|
||||
|
||||
//NotaryTokenForUI calls genTokenForUI to get raw token for notary
|
||||
func NotaryTokenForUI(username string, service string, scopes []string) (string, int, *time.Time, error) {
|
||||
return genTokenForUI(username, service, scopes, notaryFilterMap)
|
||||
}
|
||||
|
||||
// genTokenForUI is for the UI process to call, so it won't establish a https connection from UI to proxy.
|
||||
func genTokenForUI(username string, service string, scopes []string, filters map[string]accessFilter) (string, int, *time.Time, error) {
|
||||
isAdmin, err := dao.IsAdminRole(username)
|
||||
if err != nil {
|
||||
return "", 0, nil, err
|
||||
}
|
||||
f := &repositoryFilter{
|
||||
parser: &basicParser{},
|
||||
}
|
||||
u := userInfo{
|
||||
name: username,
|
||||
allPerm: isAdmin,
|
||||
}
|
||||
access := GetResourceActions(scopes)
|
||||
for _, a := range access {
|
||||
err = f.filter(u, a)
|
||||
if err != nil {
|
||||
return "", 0, nil, err
|
||||
}
|
||||
err = filterAccess(access, u, filters)
|
||||
if err != nil {
|
||||
return "", 0, nil, err
|
||||
}
|
||||
return MakeRawToken(username, service, access)
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
)
|
||||
|
||||
var creatorMap map[string]Creator
|
||||
var registryFilterMap map[string]accessFilter
|
||||
var notaryFilterMap map[string]accessFilter
|
||||
|
||||
const (
|
||||
notary = "harbor-notary"
|
||||
@ -35,22 +37,29 @@ const (
|
||||
//InitCreators initialize the token creators for different services
|
||||
func InitCreators() {
|
||||
creatorMap = make(map[string]Creator)
|
||||
registryFilterMap = map[string]accessFilter{
|
||||
"repository": &repositoryFilter{
|
||||
parser: &basicParser{},
|
||||
},
|
||||
"registry": ®istryFilter{},
|
||||
}
|
||||
ext, err := config.ExtEndpoint()
|
||||
if err != nil {
|
||||
log.Warningf("Failed to get ext enpoint, err: %v, the token service will not be functional with notary requests", err)
|
||||
} else {
|
||||
notaryFilterMap = map[string]accessFilter{
|
||||
"repository": &repositoryFilter{
|
||||
parser: &endpointParser{
|
||||
endpoint: strings.Split(ext, "//")[1],
|
||||
},
|
||||
},
|
||||
}
|
||||
creatorMap[notary] = &generalCreator{
|
||||
validators: []ReqValidator{
|
||||
&basicAuthValidator{},
|
||||
},
|
||||
service: notary,
|
||||
filterMap: map[string]accessFilter{
|
||||
"repository": &repositoryFilter{
|
||||
parser: &endpointParser{
|
||||
endpoint: strings.Split(ext, "//")[1],
|
||||
},
|
||||
},
|
||||
},
|
||||
service: notary,
|
||||
filterMap: notaryFilterMap,
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,13 +68,8 @@ func InitCreators() {
|
||||
&secretValidator{config.JobserviceSecret()},
|
||||
&basicAuthValidator{},
|
||||
},
|
||||
service: registry,
|
||||
filterMap: map[string]accessFilter{
|
||||
"repository": &repositoryFilter{
|
||||
parser: &basicParser{},
|
||||
},
|
||||
"registry": ®istryFilter{},
|
||||
},
|
||||
service: registry,
|
||||
filterMap: registryFilterMap,
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +149,6 @@ type repositoryFilter struct {
|
||||
|
||||
func (rep repositoryFilter) filter(user userInfo, a *token.ResourceActions) error {
|
||||
//clear action list to assign to new acess element after perm check.
|
||||
a.Actions = []string{}
|
||||
img, err := rep.parser.parse(a.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -216,16 +219,9 @@ func (g generalCreator) Create(r *http.Request) (*tokenJSON, error) {
|
||||
user = &userInfo{}
|
||||
}
|
||||
access := GetResourceActions(scopes)
|
||||
for _, a := range access {
|
||||
f, ok := g.filterMap[a.Type]
|
||||
if !ok {
|
||||
log.Warningf("No filter found for access type: %s, skip.", a.Type)
|
||||
continue
|
||||
}
|
||||
err = f.filter(*user, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = filterAccess(access, *user, g.filterMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return makeToken(user.name, g.service, access)
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ func TestMain(m *testing.M) {
|
||||
if err := config.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
InitCreators()
|
||||
result := m.Run()
|
||||
if result != 0 {
|
||||
os.Exit(result)
|
||||
@ -184,3 +185,28 @@ func TestEndpointParser(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterAccess(t *testing.T) {
|
||||
//TODO put initial data in DB to verify repository filter.
|
||||
var err error
|
||||
s := []string{"registry:catalog:*"}
|
||||
a1 := GetResourceActions(s)
|
||||
a2 := GetResourceActions(s)
|
||||
u := userInfo{"jack", false}
|
||||
ra1 := token.ResourceActions{
|
||||
Type: "registry",
|
||||
Name: "catalog",
|
||||
Actions: []string{"*"},
|
||||
}
|
||||
ra2 := token.ResourceActions{
|
||||
Type: "registry",
|
||||
Name: "catalog",
|
||||
Actions: []string{},
|
||||
}
|
||||
err = filterAccess(a1, u, registryFilterMap)
|
||||
assert.Nil(t, err, "Unexpected error: %v", err)
|
||||
assert.Equal(t, ra1, *a1[0], "Mismatch after registry filter Map")
|
||||
err = filterAccess(a2, u, notaryFilterMap)
|
||||
assert.Nil(t, err, "Unexpected error: %v", err)
|
||||
assert.Equal(t, ra2, *a2[0], "Mismatch after notary filter Map")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user