Selectors implemented
* The DN that is passed along with the update command is checked against the list of DNs a certificate file uses. If it is not in the list, then the file is skipped.
This commit is contained in:
parent
658ee30bc6
commit
7eb865e306
2 changed files with 59 additions and 19 deletions
70
buildcert.go
70
buildcert.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -30,24 +31,39 @@ type (
|
||||||
// Certificate building, including the configuration, LDAP connection,
|
// Certificate building, including the configuration, LDAP connection,
|
||||||
// and the array of chunks that's being built.
|
// and the array of chunks that's being built.
|
||||||
tCertificateBuilder struct {
|
tCertificateBuilder struct {
|
||||||
config *tCertificateFileConfig
|
// The certificate file's current configuration
|
||||||
conn *tLdapConn
|
config *tCertificateFileConfig
|
||||||
logger *logrus.Entry
|
// The LDAP connection to read data from
|
||||||
data [][]byte
|
conn *tLdapConn
|
||||||
text []byte
|
// The command that caused the update
|
||||||
|
command TCommand
|
||||||
|
// The logger to use
|
||||||
|
logger *logrus.Entry
|
||||||
|
// The list of DNs that are involved in generating this certificate. If the
|
||||||
|
// command has a non-'*' selector, the list will be checked for a value
|
||||||
|
// matching the selector befor anything else is done.
|
||||||
|
dnList []string
|
||||||
|
// The various chunks of data that will be written to the resulting PEM file.
|
||||||
|
// Each chunk corresponds to a PEM block.
|
||||||
|
data [][]byte
|
||||||
|
// The output text
|
||||||
|
text []byte
|
||||||
|
// Information about the current file, if it exists.
|
||||||
existing *tExistingFileInfo
|
existing *tExistingFileInfo
|
||||||
changed bool
|
// Was the certificate file replaced?
|
||||||
|
changed bool
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize a certificate file building using a LDAP connection and
|
// Initialize a certificate file building using a LDAP connection and
|
||||||
// certificate file configuration.
|
// certificate file configuration.
|
||||||
func NewCertificateBuilder(conn *tLdapConn, config *tCertificateFileConfig) tCertificateBuilder {
|
func NewCertificateBuilder(conn *tLdapConn, config *tCertificateFileConfig, cmd *TCommand) tCertificateBuilder {
|
||||||
return tCertificateBuilder{
|
return tCertificateBuilder{
|
||||||
config: config,
|
config: config,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
logger: log.WithField("file", config.Path),
|
command: *cmd,
|
||||||
data: make([][]byte, 0),
|
logger: log.WithField("file", config.Path),
|
||||||
|
data: make([][]byte, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +94,25 @@ func (b *tCertificateBuilder) Build() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the data should be written to disk.
|
// Check whether the command's selector matches one of the current certificate
|
||||||
|
// file's DNs.
|
||||||
|
func (b *tCertificateBuilder) SelectorMatches() bool {
|
||||||
|
if b.command.Selector == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
sel := strings.ToLower(b.command.Selector)
|
||||||
|
for _, v := range b.dnList {
|
||||||
|
if strings.ToLower(v) == sel {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.logger.WithField("selector", b.command.Selector).Debug("Selector does not match.")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the data should be written to disk. This also caches the
|
||||||
|
// file's owner, group and mode. If the update is being forced it will return
|
||||||
|
// `true` even if nothing changed.
|
||||||
func (b *tCertificateBuilder) MustWrite() bool {
|
func (b *tCertificateBuilder) MustWrite() bool {
|
||||||
info, err := os.Lstat(b.config.Path)
|
info, err := os.Lstat(b.config.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,7 +126,7 @@ func (b *tCertificateBuilder) MustWrite() bool {
|
||||||
eif.group = sys_stat.Gid
|
eif.group = sys_stat.Gid
|
||||||
b.existing = eif
|
b.existing = eif
|
||||||
|
|
||||||
if sys_stat.Size != int64(len(b.text)) {
|
if b.command.Force || sys_stat.Size != int64(len(b.text)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
existing, err := ioutil.ReadFile(b.config.Path)
|
existing, err := ioutil.ReadFile(b.config.Path)
|
||||||
|
@ -254,6 +288,7 @@ func (b *tCertificateBuilder) appendCertificate() error {
|
||||||
dn = "," + dn
|
dn = "," + dn
|
||||||
}
|
}
|
||||||
dn = b.config.Certificate + dn
|
dn = b.config.Certificate + dn
|
||||||
|
b.dnList = append(b.dnList, strings.ToLower(dn))
|
||||||
b.logger.WithField("dn", dn).Debug("Adding EE certificate from LDAP")
|
b.logger.WithField("dn", dn).Debug("Adding EE certificate from LDAP")
|
||||||
data, err := b.conn.GetEndEntityCertificate(dn)
|
data, err := b.conn.GetEndEntityCertificate(dn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -283,13 +318,15 @@ func (b *tCertificateBuilder) appendListedCaCerts() error {
|
||||||
bdn = "," + bdn
|
bdn = "," + bdn
|
||||||
}
|
}
|
||||||
for _, dn := range b.config.CACertificates {
|
for _, dn := range b.config.CACertificates {
|
||||||
b.logger.WithField("dn", dn+bdn).Debug("Adding CA certificate from LDAP")
|
full_dn := dn + bdn
|
||||||
data, _, err := b.conn.GetCaCertificate(dn + bdn)
|
b.dnList = append(b.dnList, strings.ToLower(full_dn))
|
||||||
|
b.logger.WithField("dn", full_dn).Debug("Adding CA certificate from LDAP")
|
||||||
|
data, _, err := b.conn.GetCaCertificate(full_dn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return fmt.Errorf("No CA certificate at DN '%s'", dn)
|
return fmt.Errorf("No CA certificate at DN '%s'", full_dn)
|
||||||
}
|
}
|
||||||
b.data = append(b.data, data)
|
b.data = append(b.data, data)
|
||||||
}
|
}
|
||||||
|
@ -304,6 +341,7 @@ func (b *tCertificateBuilder) appendChainedCaCerts() error {
|
||||||
dn = dn + "," + b.conn.BaseDN()
|
dn = dn + "," + b.conn.BaseDN()
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
|
b.dnList = append(b.dnList, strings.ToLower(dn))
|
||||||
data, nextDn, err := b.conn.GetCaCertificate(dn)
|
data, nextDn, err := b.conn.GetCaCertificate(dn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -152,15 +152,17 @@ func executeUpdate(cfg *tConfiguration, cmd *TCommand) bool {
|
||||||
|
|
||||||
had_errors := false
|
had_errors := false
|
||||||
for i := range cfg.Certificates {
|
for i := range cfg.Certificates {
|
||||||
// TODO apply selector
|
builder := NewCertificateBuilder(conn, &cfg.Certificates[i], cmd)
|
||||||
builder := NewCertificateBuilder(conn, &cfg.Certificates[i])
|
|
||||||
err := builder.Build()
|
err := builder.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithField("error", err).Error("Failed to build data for certificate '", cfg.Certificates[i].Path, "'")
|
log.WithField("error", err).Error("Failed to build data for certificate '", cfg.Certificates[i].Path, "'")
|
||||||
had_errors = true
|
had_errors = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if builder.MustWrite() || cmd.Force {
|
if !builder.SelectorMatches() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if builder.MustWrite() {
|
||||||
err := builder.WriteFile()
|
err := builder.WriteFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithField("error", err).Error("Failed to write '", cfg.Certificates[i].Path, "'")
|
log.WithField("error", err).Error("Failed to write '", cfg.Certificates[i].Path, "'")
|
||||||
|
|
Loading…
Reference in a new issue