好久没用 Harbor,把密码给忘记了,通过修改数据库重置一下密码吧。
分析源码
看了一下 harbor 的源码,找到生成密码的源码 src/common/utils/encrypt.go
:
package utils
import (
"crypto/sha1"
"crypto/sha256"
"fmt"
"hash"
"golang.org/x/crypto/pbkdf2"
)
const (
// SHA1 is the name of sha1 hash alg
SHA1 = "sha1"
// SHA256 is the name of sha256 hash alg
SHA256 = "sha256"
)
// HashAlg used to get correct alg for hash
var HashAlg = map[string]func() hash.Hash{
SHA1: sha1.New,
SHA256: sha256.New,
}
// Encrypt encrypts the content with salt
func Encrypt(content string, salt string, encrptAlg string) string {
return fmt.Sprintf("%x", pbkdf2.Key([]byte(content), []byte(salt), 4096, 16, HashAlg[encrptAlg]))
}
查看用户表
进入数据库容器
docker exec -it harbor-db bash
连接数据库
postgres [ / ]$ psql
psql (9.6.20)
Type "help" for help.
切换数据库
postgres=# \c registry
You are now connected to database "registry" as user "postgres".
查看表结构
registry=# \d harbor_user
Table "public.harbor_user"
Column | Type | Modifiers
------------------+-----------------------------+---------------------------------------------------------------
user_id | integer | not null default nextval('harbor_user_user_id_seq'::regclass)
username | character varying(255) |
email | character varying(255) |
password | character varying(40) | not null
realname | character varying(255) | not null
comment | character varying(30) |
deleted | boolean | not null default false
reset_uuid | character varying(40) | default NULL::character varying
salt | character varying(40) | default NULL::character varying
sysadmin_flag | boolean | not null default false
creation_time | timestamp without time zone | default now()
update_time | timestamp without time zone | default now()
password_version | character varying(16) | default 'sha256'::character varying
Indexes:
"harbor_user_pkey" PRIMARY KEY, btree (user_id)
"harbor_user_email_key" UNIQUE CONSTRAINT, btree (email)
"harbor_user_username_key" UNIQUE CONSTRAINT, btree (username)
Referenced by:
TABLE "oidc_user" CONSTRAINT "oidc_user_user_id_fkey" FOREIGN KEY (user_id) REFERENCES harbor_user(user_id)
TABLE "project" CONSTRAINT "project_owner_id_fkey" FOREIGN KEY (owner_id) REFERENCES harbor_user(user_id)
Triggers:
harbor_user_update_time_at_modtime BEFORE UPDATE ON harbor_user FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column()
生成密码
通过分析源代码和数据表结构,现在来写一个生成密码的程序。
源码
package main
import (
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"flag"
"fmt"
"hash"
"github.com/goharbor/harbor/src/lib/log"
"golang.org/x/crypto/pbkdf2"
)
const (
// SHA1 is the name of sha1 hash alg
SHA1 = "sha1"
// SHA256 is the name of sha256 hash alg
SHA256 = "sha256"
)
var (
HashAlg = map[string]func() hash.Hash{
SHA1: sha1.New,
SHA256: sha256.New,
}
password string
salt string
alg string
)
func main() {
flag.StringVar(&password, "p", "", "password")
flag.StringVar(&salt, "salt", "", "salt")
flag.StringVar(&alg, "alg", SHA256, "encrypt algorithm, support sha1 and sha256")
flag.Parse()
if salt == "" {
salt = GenerateRandomString()
}
fmt.Printf("%x", pbkdf2.Key([]byte(password), []byte(salt), 4096, 16, HashAlg[alg]))
}
// GenerateRandomStringWithLen generates a random string with length
func GenerateRandomStringWithLen(length int) string {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
l := len(chars)
result := make([]byte, length)
_, err := rand.Read(result)
if err != nil {
log.Warningf("Error reading random bytes: %v", err)
}
for i := 0; i < length; i++ {
result[i] = chars[int(result[i])%l]
}
return string(result)
}
// GenerateRandomString generate a random string with 32 byte length
func GenerateRandomString() string {
return GenerateRandomStringWithLen(32)
}
使用
# 自动生成 salt
./harbor-password -p yourpass
# 指定 salt
./harbor-password -p yourpass -salt yoursalt
# 指定加密算法,支持 sha1 和 sha256,默认 sha256
./harbor-password -p yourpass -alg sha1