mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-04 17:49:48 +01:00
Provide secret manager for proxy cache project
This commit provides the secret manager for proxy cache. The secret is used for pushing blobs to local when it's proxied from remote registry. Each secret can be used only once and has a relatively short expiration time. Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
parent
4d4a04fad4
commit
840aa86dfa
70
src/pkg/proxy/secret/manager.go
Normal file
70
src/pkg/proxy/secret/manager.go
Normal file
@ -0,0 +1,70 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
)
|
||||
|
||||
const defaultExpiration = 15 * time.Second
|
||||
|
||||
type targetRepository struct {
|
||||
name string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
// Manager generates and verifies the secret for repositories under proxy project
|
||||
// The secret normally is used for authorizing a request trying to push artifact to a project
|
||||
// A secret can be used only once and expires in a short period of time.
|
||||
// As the request will be sent to 127.0.0.1 so the secret will live in one process.
|
||||
type Manager interface {
|
||||
// Generate generates a secret for the given repository, sample value for repository: "library/ubuntu"
|
||||
Generate(repository string) string
|
||||
// Verify verifies the secret against repo name, after the verification the secret should be invalid
|
||||
Verify(secret, repository string) bool
|
||||
}
|
||||
|
||||
type mgr struct {
|
||||
m *sync.Map
|
||||
exp time.Duration
|
||||
}
|
||||
|
||||
func (man *mgr) Generate(rn string) string {
|
||||
s := utils.GenerateRandomStringWithLen(8)
|
||||
man.m.Store(s, targetRepository{name: rn, expiresAt: time.Now().Add(man.exp)})
|
||||
return s
|
||||
}
|
||||
|
||||
func (man *mgr) Verify(sec, rn string) bool {
|
||||
v, ok := man.m.Load(sec)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
p, ok := v.(targetRepository)
|
||||
if ok && p.name == rn {
|
||||
defer man.m.Delete(sec)
|
||||
return p.expiresAt.After(time.Now())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
defaultManager Manager
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// GetManager returns the default manager which is a singleton in the package
|
||||
func GetManager() Manager {
|
||||
once.Do(func() {
|
||||
defaultManager = createManager(defaultExpiration)
|
||||
})
|
||||
return defaultManager
|
||||
}
|
||||
|
||||
func createManager(d time.Duration) Manager {
|
||||
return &mgr{
|
||||
m: &sync.Map{},
|
||||
exp: d,
|
||||
}
|
||||
}
|
33
src/pkg/proxy/secret/manager_test.go
Normal file
33
src/pkg/proxy/secret/manager_test.go
Normal file
@ -0,0 +1,33 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestManger(t *testing.T) {
|
||||
manager := GetManager()
|
||||
rn1 := "project1/golang"
|
||||
assert.False(t, manager.Verify("whatever", rn1))
|
||||
s1 := manager.Generate(rn1)
|
||||
s2 := manager.Generate(rn1)
|
||||
assert.False(t, s1 == s2)
|
||||
|
||||
assert.False(t, manager.Verify(s1, "project1/donotexist"))
|
||||
assert.True(t, manager.Verify(s1, rn1))
|
||||
// A secret can be used only once.
|
||||
assert.False(t, manager.Verify(s1, rn1))
|
||||
manager2 := GetManager()
|
||||
assert.Equal(t, manager2, manager)
|
||||
}
|
||||
|
||||
func TestExpiration(t *testing.T) {
|
||||
manager := createManager(1 * time.Second)
|
||||
rn1 := "project1/golang"
|
||||
s := manager.Generate(rn1)
|
||||
// Sleep till the secret expires
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.False(t, manager.Verify(s, rn1))
|
||||
}
|
Loading…
Reference in New Issue
Block a user