Compare commits
30 Commits
setup_test
...
master
Author | SHA1 | Date |
---|---|---|
|
0fccacdd77 | 2 months ago |
|
109afb27b8 | 2 months ago |
|
19d91e33c7 | 2 months ago |
|
08eaf393d6 | 5 months ago |
|
1d7036649f | 5 months ago |
|
3362d1e165 | 5 months ago |
|
31477710d8 | 5 months ago |
|
4ddbbfeab7 | 5 months ago |
|
c1f77c5422 | 7 months ago |
|
3f939af80c | 7 months ago |
|
43fafbcf6b | 7 months ago |
|
25a58573b8 | 7 months ago |
|
0a1996d220 | 7 months ago |
|
0bdeb31c66 | 7 months ago |
|
2a52381dc0 | 7 months ago |
|
9210dcfc84 | 7 months ago |
|
5096ae4475 | 7 months ago |
|
dd35c6bdd6 | 7 months ago |
|
0f6961df27 | 8 months ago |
|
5075e21972 | 9 months ago |
|
e72c081ede | 9 months ago |
|
7926084e8c | 1 year ago |
|
78abc2c76b | 1 year ago |
|
d4c070c9f9 | 1 year ago |
|
86eb48e096 | 1 year ago |
|
fd12aca4c9 | 1 year ago |
|
493fbbdd70 | 1 year ago |
|
f7cb59d4bd | 1 year ago |
|
16816ee445 | 1 year ago |
|
51079f9416 | 1 year ago |
50 changed files with 1673 additions and 493 deletions
@ -0,0 +1,72 @@
|
||||
package db |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"log" |
||||
"time" |
||||
|
||||
"go.etcd.io/bbolt" |
||||
) |
||||
|
||||
var ( |
||||
collectiveBucket = []byte("collective") |
||||
) |
||||
|
||||
type collective struct { |
||||
Name string |
||||
CreationDate time.Time |
||||
} |
||||
|
||||
// AddCollective stores in the db the collective that was created by host
|
||||
func (db *DB) AddCollective(name string, host string) error { |
||||
var collectives []collective |
||||
err := db.get(collectiveBucket, host, &collectives) |
||||
if err != nil && !errors.Is(err, notFoundError{}) { |
||||
return err |
||||
} |
||||
|
||||
collectives = append(collectives, collective{name, time.Now()}) |
||||
return db.put(collectiveBucket, host, collectives) |
||||
} |
||||
|
||||
// CountCollectives returns the nubmer of collectives created by host
|
||||
func (db *DB) CountCollectives(host string) (int, error) { |
||||
var collectives []collective |
||||
err := db.get(collectiveBucket, host, &collectives) |
||||
if errors.Is(err, notFoundError{}) { |
||||
return 0, nil |
||||
} |
||||
return len(collectives), err |
||||
} |
||||
|
||||
// ExpireCollectives older than duration
|
||||
func (db *DB) ExpireCollectives(duration time.Duration) error { |
||||
return db.bolt.Update(func(tx *bbolt.Tx) error { |
||||
b := tx.Bucket(collectiveBucket) |
||||
return b.ForEach(func(k, v []byte) error { |
||||
var collectives []collective |
||||
err := json.Unmarshal(v, &collectives) |
||||
if err != nil { |
||||
log.Printf("Error unmarshalling %s: %v", string(k), err) |
||||
return nil |
||||
} |
||||
|
||||
newCollectives := []collective{} |
||||
for _, c := range collectives { |
||||
if c.CreationDate.Add(duration).After(time.Now()) { |
||||
newCollectives = append(newCollectives, c) |
||||
} |
||||
} |
||||
if len(newCollectives) == len(collectives) { |
||||
return nil |
||||
} |
||||
|
||||
encodedValue, err := json.Marshal(newCollectives) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return b.Put(k, encodedValue) |
||||
}) |
||||
}) |
||||
} |
@ -0,0 +1,85 @@
|
||||
package db |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
collectiveName = "collective" |
||||
collectiveHost = "host" |
||||
) |
||||
|
||||
func TestAddCountCollective(t *testing.T) { |
||||
db := initTestDB(t) |
||||
defer delTestDB(db) |
||||
|
||||
count, err := db.CountCollectives(collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error counting collectives: %v", err) |
||||
} |
||||
if count != 0 { |
||||
t.Errorf("Got an unexpected number of collectives: %d", count) |
||||
} |
||||
|
||||
err = db.AddCollective(collectiveName, collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error adding a collective: %v", err) |
||||
} |
||||
|
||||
count, err = db.CountCollectives(collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error counting collectives: %v", err) |
||||
} |
||||
if count != 1 { |
||||
t.Errorf("Got an unexpected number of collectives: %d", count) |
||||
} |
||||
|
||||
err = db.AddCollective(collectiveName+"1", collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error adding a collective: %v", err) |
||||
} |
||||
err = db.AddCollective(collectiveName+"2", collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error adding a collective: %v", err) |
||||
} |
||||
|
||||
count, err = db.CountCollectives(collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error counting collectives: %v", err) |
||||
} |
||||
if count != 3 { |
||||
t.Errorf("Got an unexpected number of collectives: %d", count) |
||||
} |
||||
} |
||||
|
||||
func TestExpireCollectives(t *testing.T) { |
||||
db := initTestDB(t) |
||||
defer delTestDB(db) |
||||
|
||||
err := db.AddCollective(collectiveName, collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error adding a collective: %v", err) |
||||
} |
||||
|
||||
count, err := db.CountCollectives(collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error counting collectives: %v", err) |
||||
} |
||||
if count != 1 { |
||||
t.Errorf("Got an unexpected number of collectives: %d", count) |
||||
} |
||||
|
||||
err = db.ExpireCollectives(time.Microsecond) |
||||
if err != nil { |
||||
t.Fatalf("Got an error expiring invites: %v", err) |
||||
} |
||||
|
||||
count, err = db.CountCollectives(collectiveHost) |
||||
if err != nil { |
||||
t.Fatalf("Got an error counting collectives: %v", err) |
||||
} |
||||
if count != 0 { |
||||
t.Errorf("Got an unexpected number of collectives: %d", count) |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
package db |
||||
|
||||
import ( |
||||
"errors" |
||||
"time" |
||||
) |
||||
|
||||
var ( |
||||
openpgpNotificationsBucket = []byte("openpgp-notifications") |
||||
) |
||||
|
||||
type openpgpNotification struct { |
||||
Fingerprint string |
||||
CreationDate time.Time |
||||
} |
||||
|
||||
// AddOpenpgpNotification stores in the db the dn being notified for their key being expired
|
||||
func (db *DB) AddOpenpgpNotification(dn string, fingerprint string) error { |
||||
return db.put(openpgpNotificationsBucket, dn, openpgpNotification{fingerprint, time.Now()}) |
||||
} |
||||
|
||||
// GetOpenpgpNotification gets the fingerprint latest notification for the dn
|
||||
func (db *DB) GetOpenpgpNotification(dn string) (string, error) { |
||||
var notif openpgpNotification |
||||
err := db.get(openpgpNotificationsBucket, dn, ¬if) |
||||
if errors.Is(err, notFoundError{}) { |
||||
err = nil |
||||
} |
||||
return notif.Fingerprint, err |
||||
} |
||||
|
||||
// ExpireOpenpgpNotifications older than duration
|
||||
func (db *DB) ExpireOpenpgpNotifications(duration time.Duration) error { |
||||
return db.expire(openpgpNotificationsBucket, duration) |
||||
} |
@ -0,0 +1,68 @@
|
||||
package db |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
user = "user" |
||||
fingerprint = "AABBCCDDEEFF1122334455" |
||||
) |
||||
|
||||
func TestAddOpenPGPNotification(t *testing.T) { |
||||
db := initTestDB(t) |
||||
defer delTestDB(db) |
||||
|
||||
fp, err := db.GetOpenpgpNotification(user) |
||||
if err != nil { |
||||
t.Fatalf("Got an error getting openpgp notification: %v", err) |
||||
} |
||||
if fp != "" { |
||||
t.Errorf("Got an unexpected fingerprint: %s", fp) |
||||
} |
||||
|
||||
err = db.AddOpenpgpNotification(user, fingerprint) |
||||
if err != nil { |
||||
t.Fatalf("Got an error adding a openpgp notification: %v", err) |
||||
} |
||||
|
||||
fp, err = db.GetOpenpgpNotification(user) |
||||
if err != nil { |
||||
t.Fatalf("Got an error getting openpgp notification: %v", err) |
||||
} |
||||
if fp != fingerprint { |
||||
t.Errorf("Got an unexpected fingerprint: %s", fp) |
||||
} |
||||
} |
||||
|
||||
func TestExpireOpenpgpNofications(t *testing.T) { |
||||
db := initTestDB(t) |
||||
defer delTestDB(db) |
||||
|
||||
err := db.AddOpenpgpNotification(user, fingerprint) |
||||
if err != nil { |
||||
t.Fatalf("Got an error adding a openpgp notification: %v", err) |
||||
} |
||||
|
||||
fp, err := db.GetOpenpgpNotification(user) |
||||
if err != nil { |
||||
t.Fatalf("Got an error getting openpgp notification: %v", err) |
||||
} |
||||
if fp != fingerprint { |
||||
t.Errorf("Got an unexpected fingerprint: %s", fp) |
||||
} |
||||
|
||||
err = db.ExpireOpenpgpNotifications(time.Microsecond) |
||||
if err != nil { |
||||
t.Fatalf("Got an error expiring openpgp notifications: %v", err) |
||||
} |
||||
|
||||
fp, err = db.GetOpenpgpNotification(user) |
||||
if err != nil { |
||||
t.Fatalf("Got an error getting openpgp notification: %v", err) |
||||
} |
||||
if fp != "" { |
||||
t.Errorf("Got an unexpected fingerprint: %s", fp) |
||||
} |
||||
} |
@ -1,9 +0,0 @@
|
||||
dn: cn=sindominio,cn=schema,cn=config |
||||
objectClass: olcSchemaConfig |
||||
cn: sindominio |
||||
olcAttributeTypes: ( 1.3.6.1.4.1.42023.11 NAME 'sdRole' DESC 'Rol en SinDominio' |
||||
SUP name SINGLE-VALUE ) |
||||
olcAttributeTypes: ( 1.3.6.1.4.1.42023.12 NAME 'sdLocked' |
||||
DESC 'Cuenta de SinDominio bloqueada' SUP name ) |
||||
olcObjectClasses: ( 1.3.6.1.4.1.42023.10 NAME 'sdPerson' |
||||
DESC 'Personas de SinDominio' SUP top AUXILIARY MUST sdRole MAY sdLocked ) |
@ -1,13 +0,0 @@
|
||||
attributetype ( 1.3.6.1.4.1.42023.11 NAME 'sdRole' |
||||
DESC 'Rol en SinDominio' |
||||
SUP name SINGLE-VALUE) |
||||
|
||||
attributetype ( 1.3.6.1.4.1.42023.12 NAME 'sdLocked' |
||||
DESC 'Cuenta de SinDominio bloqueada' |
||||
SUP name) |
||||
|
||||
objectclass ( 1.3.6.1.4.1.42023.10 NAME 'sdPerson' |
||||
DESC 'Personas de SinDominio' |
||||
SUP top AUXILIARY |
||||
MUST sdRole |
||||
MAY sdLocked) |
@ -0,0 +1,8 @@
|
||||
package ldap |
||||
|
||||
import ( |
||||
"errors" |
||||
) |
||||
|
||||
var ErrAlreadyExist = errors.New("Already exist an entry with this uid/cn") |
||||
var ErrNotFound = errors.New("Can't find the record in the ldap") |
@ -0,0 +1,101 @@
|
||||
package ldap |
||||
|
||||
import ( |
||||
"errors" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/go-ldap/ldap/v3" |
||||
) |
||||
|
||||
var openPGPAttributes = []string{"openPGPKey", "openPGPId", "openPGPExpiry", "openPGPKeyHash"} |
||||
|
||||
type OpenPGPkey struct { |
||||
Fingerprint string |
||||
Expiry time.Time |
||||
Key []byte |
||||
WkdHash string |
||||
} |
||||
|
||||
func (l Ldap) changeOpenPGPkey(dn string, fingerprint string, expiry time.Time, key []byte, wkdHash string, email string) error { |
||||
conn, err := l.connect() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer conn.Close() |
||||
|
||||
modifyRequest := ldap.NewModifyRequest(dn, nil) |
||||
_, err = l.getOpenPGPKey(dn, conn) |
||||
if err != nil { |
||||
if errors.Is(err, ErrNotFound) { |
||||
modifyRequest.Add("objectClass", []string{"openPGP"}) |
||||
} else { |
||||
return err |
||||
} |
||||
} |
||||
modifyRequest.Replace("openPGPId", []string{fingerprint}) |
||||
modifyRequest.Replace("openPGPExpiry", []string{expiry.Format(dateFormat)}) |
||||
modifyRequest.Replace("openPGPKey", []string{string(key)}) |
||||
modifyRequest.Replace("openPGPKeyHash", []string{wkdHash}) |
||||
if email != "" { |
||||
modifyRequest.Replace("mail", []string{email}) |
||||
} |
||||
return conn.Modify(modifyRequest) |
||||
} |
||||
|
||||
func (l Ldap) DeleteOpenPGPkey(dn string) error { |
||||
conn, err := l.connect() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer conn.Close() |
||||
|
||||
modifyRequest := ldap.NewModifyRequest(dn, nil) |
||||
modifyRequest.Delete("objectClass", []string{"openPGP"}) |
||||
modifyRequest.Delete("openPGPId", []string{}) |
||||
modifyRequest.Delete("openPGPExpiry", []string{}) |
||||
modifyRequest.Delete("openPGPKey", []string{}) |
||||
modifyRequest.Delete("openPGPKeyHash", []string{}) |
||||
if strings.Contains(strings.ToLower(dn), "ou=group") { |
||||
modifyRequest.Delete("mail", []string{}) |
||||
} |
||||
return conn.Modify(modifyRequest) |
||||
} |
||||
|
||||
func (l Ldap) getOpenPGPKey(dn string, conn *ldap.Conn) (*OpenPGPkey, error) { |
||||
searchRequest := ldap.NewSearchRequest( |
||||
dn, |
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, |
||||
"((objectClass=openPGP))", |
||||
openPGPAttributes, |
||||
nil, |
||||
) |
||||
sr, err := conn.Search(searchRequest) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
switch len(sr.Entries) { |
||||
case 1: |
||||
entry := sr.Entries[0] |
||||
return openPGPkey(entry), nil |
||||
case 0: |
||||
return nil, ErrNotFound |
||||
default: |
||||
return nil, errors.New("More than one user found!!!") |
||||
} |
||||
} |
||||
|
||||
func openPGPkey(entry *ldap.Entry) *OpenPGPkey { |
||||
openPGPexpiry, _ := time.Parse(dateFormat, entry.GetAttributeValue("openPGPExpiry")) |
||||
key := OpenPGPkey{ |
||||
Fingerprint: entry.GetAttributeValue("openPGPId"), |
||||
Expiry: openPGPexpiry, |
||||
Key: []byte(entry.GetAttributeValue("openPGPKey")), |
||||
WkdHash: entry.GetAttributeValue("openPGPKeyHash"), |
||||
} |
||||
|
||||
if len(key.Key) == 0 || key.Fingerprint == "" || key.WkdHash == "" { |
||||
return nil |
||||
} |
||||
return &key |
||||
} |
@ -0,0 +1,143 @@
|
||||
package ldap |
||||
|
||||
import ( |
||||
"bytes" |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
fingerprint = "AABBCCDDEEFF1122334455" |
||||
wkdHash = "hashhash" |
||||
) |
||||
|
||||
var ( |
||||
key = []byte("openpgpkey") |
||||
) |
||||
|
||||
func TestOpenPGPuser(t *testing.T) { |
||||
l := testLdap(t) |
||||
u, err := l.GetUser(user) |
||||
if err != nil { |
||||
t.Errorf("GetUser() failed: %v", err) |
||||
} |
||||
if u.OpenPGPkey != nil { |
||||
t.Errorf("user already has a key") |
||||
} |
||||
|
||||
dn := l.userDN(user) |
||||
err = l.changeOpenPGPkey(dn, fingerprint, time.Time{}, key, wkdHash, "") |
||||
if err != nil { |
||||
t.Errorf("ChangeOpenPGPkey() failed: %v", err) |
||||
} |
||||
|
||||
u, err = l.GetUser(user) |
||||
if err != nil { |
||||
t.Errorf("GetUser() failed: %v", err) |
||||
} |
||||
if u.OpenPGPkey == nil { |
||||
t.Fatal("user doesn't have a key") |
||||
} |
||||
if u.OpenPGPkey.Fingerprint != fingerprint { |
||||
t.Errorf("fingeprint doesn't match: %s", u.OpenPGPkey.Fingerprint) |
||||
} |
||||
if !bytes.Equal(u.OpenPGPkey.Key, key) { |
||||
t.Errorf("key doesn't match: %s", u.OpenPGPkey.Key) |
||||
} |
||||
if u.OpenPGPkey.WkdHash != wkdHash { |
||||
t.Errorf("wkdHash doesn't match: %s", u.OpenPGPkey.WkdHash) |
||||
} |
||||
if !u.OpenPGPkey.Expiry.IsZero() { |
||||
t.Errorf("expiry is not zero: %v", u.OpenPGPkey.Expiry) |
||||
} |
||||
|
||||
err = l.DeleteOpenPGPkey(dn) |
||||
if err != nil { |
||||
t.Errorf("DeleteOpenPGPkey() failed: %v", err) |
||||
} |
||||
|
||||
u, err = l.GetUser(user) |
||||
if err != nil { |
||||
t.Errorf("GetUser() failed: %v", err) |
||||
} |
||||
if u.OpenPGPkey != nil { |
||||
t.Errorf("user already has a key") |
||||
} |
||||
} |
||||
|
||||
func TestOpenPGPgroup(t *testing.T) { |
||||
l := testLdap(t) |
||||
g, err := l.GetGroup(group) |
||||
if err != nil { |
||||
t.Errorf("GetGRoup() failed: %v", err) |
||||
} |
||||
if g.OpenPGPkey != nil { |
||||
t.Errorf("user already has a key") |
||||
} |
||||
|
||||
dn := l.groupDN(group) |
||||
err = l.changeOpenPGPkey(dn, fingerprint, time.Time{}, key, wkdHash, group+"@nodomain") |
||||
if err != nil { |
||||
t.Errorf("ChangeOpenPGPkey() failed: %v", err) |
||||
} |
||||
|
||||
g, err = l.GetGroup(group) |
||||
if err != nil { |
||||
t.Errorf("GetGRoup() failed: %v", err) |
||||
} |
||||
if g.OpenPGPkey == nil { |
||||
t.Fatal("user doesn't have a key") |
||||
} |
||||
if g.OpenPGPkey.Fingerprint != fingerprint { |
||||
t.Errorf("fingeprint doesn't match: %s", g.OpenPGPkey.Fingerprint) |
||||
} |
||||
if !bytes.Equal(g.OpenPGPkey.Key, key) { |
||||
t.Errorf("key doesn't match: %s", g.OpenPGPkey.Key) |
||||
} |
||||
if g.OpenPGPkey.WkdHash != wkdHash { |
||||
t.Errorf("wkdHash doesn't match: %s", g.OpenPGPkey.WkdHash) |
||||
} |
||||
if !g.OpenPGPkey.Expiry.IsZero() { |
||||
t.Errorf("expiry is not zero: %v", g.OpenPGPkey.Expiry) |
||||
} |
||||
|
||||
err = l.DeleteOpenPGPkey(dn) |
||||
if err != nil { |
||||
t.Errorf("DeleteOpenPGPkey() failed: %v", err) |
||||
} |
||||
|
||||
g, err = l.GetGroup(group) |
||||
if err != nil { |
||||
t.Errorf("GetGRoup() failed: %v", err) |
||||
} |
||||
if g.OpenPGPkey != nil { |
||||
t.Errorf("user already has a key") |
||||
} |
||||
} |
||||
|
||||
func TestUpdateOpenPGP(t *testing.T) { |
||||
l := testLdap(t) |
||||
u, err := l.GetUser(user) |
||||
if err != nil { |
||||
t.Errorf("GetUser() failed: %v", err) |
||||
} |
||||
if u.OpenPGPkey != nil { |
||||
t.Errorf("user already has a key") |
||||
} |
||||
|
||||
dn := l.userDN(user) |
||||
err = l.changeOpenPGPkey(dn, fingerprint, time.Time{}, key, wkdHash, "") |
||||
if err != nil { |
||||
t.Errorf("ChangeOpenPGPkey() failed: %v", err) |
||||
} |
||||
|
||||
err = l.changeOpenPGPkey(dn, fingerprint, time.Time{}, key, wkdHash, "") |
||||
if err != nil { |
||||
t.Errorf("ChangeOpenPGPkey() failed: %v", err) |
||||
} |
||||
|
||||
err = l.DeleteOpenPGPkey(dn) |
||||
if err != nil { |
||||
t.Errorf("DeleteOpenPGPkey() failed: %v", err) |
||||
} |
||||
} |