保护初始化完成后的正式凭据
This commit is contained in:
parent
c830bcebfa
commit
9a68fb80d9
@ -248,22 +248,39 @@ func (m *DatabaseVerificationManager) resolveSession(token string) (databaseVeri
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// DiscardAll 回收所有尚未消费的数据库验证令牌及其临时凭据。
|
||||
func (m *DatabaseVerificationManager) DiscardAll() {
|
||||
m.DiscardAllExcept()
|
||||
}
|
||||
|
||||
// DiscardAllExcept 回收全部尚未消费的数据库验证令牌,但保留已经成为正式配置依赖的凭据。
|
||||
func (m *DatabaseVerificationManager) DiscardAllExcept(protectedReferences ...string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
protected := protectedCredentialReferences(protectedReferences)
|
||||
m.mu.Lock()
|
||||
references := make([]string, 0, len(m.sessions))
|
||||
for token, session := range m.sessions {
|
||||
delete(m.sessions, token)
|
||||
if session.CredentialRef != "" {
|
||||
references = append(references, session.CredentialRef)
|
||||
if reference := strings.TrimSpace(session.CredentialRef); reference != "" && !protected[reference] {
|
||||
references = append(references, reference)
|
||||
}
|
||||
}
|
||||
m.mu.Unlock()
|
||||
m.deleteCredentials(references)
|
||||
}
|
||||
|
||||
func protectedCredentialReferences(references []string) map[string]bool {
|
||||
protected := make(map[string]bool, len(references))
|
||||
for _, reference := range references {
|
||||
if reference = strings.TrimSpace(reference); reference != "" {
|
||||
protected[reference] = true
|
||||
}
|
||||
}
|
||||
return protected
|
||||
}
|
||||
|
||||
func (m *DatabaseVerificationManager) reserve() error {
|
||||
now := m.now().UTC()
|
||||
m.mu.Lock()
|
||||
|
||||
@ -200,6 +200,44 @@ func TestDatabaseVerificationDiscardOnlyRemovesSelectedToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabaseVerificationDiscardAllExceptProtectsFormalCredential(t *testing.T) {
|
||||
base := config.Default(t.TempDir())
|
||||
store := &memoryDatabaseStore{}
|
||||
manager := NewDatabaseVerificationManager(base, store)
|
||||
manager.verify = func(context.Context, config.DatabaseConfig) error { return nil }
|
||||
|
||||
protected, err := manager.Verify(t.Context(), DatabaseInput{
|
||||
Driver: "mysql", Host: "db.example.test", Database: "scert",
|
||||
Username: "formal_user", Password: "formal-password", TLSMode: "true",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pending, err := manager.Verify(t.Context(), DatabaseInput{
|
||||
Driver: "postgres", Host: "db.example.test", Database: "scert",
|
||||
Username: "pending_user", Password: "pending-password", TLSMode: "verify-full",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
manager.DiscardAllExcept(" " + protected.CredentialRef + " ")
|
||||
|
||||
if _, err := manager.Resolve(protected.VerificationToken); err == nil {
|
||||
t.Fatal("批量清理后受保护凭据对应的验证令牌仍然有效")
|
||||
}
|
||||
if _, err := manager.Resolve(pending.VerificationToken); err == nil {
|
||||
t.Fatal("批量清理后待处理凭据对应的验证令牌仍然有效")
|
||||
}
|
||||
store.mu.Lock()
|
||||
_, protectedExists := store.values[protected.CredentialRef]
|
||||
_, pendingExists := store.values[pending.CredentialRef]
|
||||
store.mu.Unlock()
|
||||
if !protectedExists || pendingExists {
|
||||
t.Fatalf("数据库凭据保护范围错误:protected=%v pending=%v", protectedExists, pendingExists)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabaseVerificationResolveIsServerOnlyAndDoesNotConsumeToken(t *testing.T) {
|
||||
base := config.Default(t.TempDir())
|
||||
store := &memoryDatabaseStore{}
|
||||
|
||||
@ -225,15 +225,26 @@ func (m *DNSVerificationManager) Discard(token string) error {
|
||||
|
||||
// DiscardAll 回收所有尚未消费的 DNS 验证令牌及其临时凭据。
|
||||
func (m *DNSVerificationManager) DiscardAll() {
|
||||
m.DiscardAllExcept()
|
||||
}
|
||||
|
||||
// DiscardAllExcept 回收全部尚未消费的 DNS 验证令牌,但保留已经成为正式配置依赖的凭据。
|
||||
func (m *DNSVerificationManager) DiscardAllExcept(protectedReferences ...string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
protected := make(map[string]bool, len(protectedReferences))
|
||||
for _, reference := range protectedReferences {
|
||||
if reference = strings.TrimSpace(reference); reference != "" {
|
||||
protected[reference] = true
|
||||
}
|
||||
}
|
||||
m.mu.Lock()
|
||||
references := make([]string, 0, len(m.sessions))
|
||||
for token, session := range m.sessions {
|
||||
delete(m.sessions, token)
|
||||
if strings.TrimSpace(session.CredentialRef) != "" {
|
||||
references = append(references, session.CredentialRef)
|
||||
if reference := strings.TrimSpace(session.CredentialRef); reference != "" && !protected[reference] {
|
||||
references = append(references, reference)
|
||||
}
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
@ -191,6 +191,41 @@ func TestDNSVerificationDiscardAllRemovesPendingCredentials(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSVerificationDiscardAllExceptProtectsFormalCredential(t *testing.T) {
|
||||
store := &memorySecretWriter{}
|
||||
manager := NewDNSVerificationManager(fakeDNSTester{}, store)
|
||||
protected, err := manager.Verify(t.Context(), DNSVerificationInput{
|
||||
ProviderID: "aliyun", TestDomain: "formal.example.com",
|
||||
Credentials: map[string]string{"access_key_id": "formal-id", "access_key_secret": "formal-secret"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pending, err := manager.Verify(t.Context(), DNSVerificationInput{
|
||||
ProviderID: "aliyun", TestDomain: "pending.example.com",
|
||||
Credentials: map[string]string{"access_key_id": "pending-id", "access_key_secret": "pending-secret"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
manager.DiscardAllExcept(" " + protected.CredentialRef + " ")
|
||||
|
||||
if _, err := manager.Resolve(protected.VerificationToken); err == nil {
|
||||
t.Fatal("批量清理后受保护凭据对应的验证令牌仍然有效")
|
||||
}
|
||||
if _, err := manager.Resolve(pending.VerificationToken); err == nil {
|
||||
t.Fatal("批量清理后待处理凭据对应的验证令牌仍然有效")
|
||||
}
|
||||
store.mu.Lock()
|
||||
_, protectedExists := store.values[protected.CredentialRef]
|
||||
_, pendingExists := store.values[pending.CredentialRef]
|
||||
store.mu.Unlock()
|
||||
if !protectedExists || pendingExists {
|
||||
t.Fatalf("DNS 凭据保护范围错误:protected=%v pending=%v", protectedExists, pendingExists)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSVerificationManagerRejectsExpiredToken(t *testing.T) {
|
||||
store := &memorySecretWriter{}
|
||||
manager := NewDNSVerificationManager(fakeDNSTester{}, store)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user