1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 11:55:40 +01:00

Merge pull request #424 from csaf-poc/aggregator-client-certs

Aggregator: Add support for client certificates and extra header
This commit is contained in:
JanHoefelmeyer 2023-08-17 10:05:08 +02:00 committed by GitHub
commit f4d00cd9d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 112 additions and 24 deletions

View file

@ -20,6 +20,7 @@ import (
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/csaf-poc/csaf_distribution/v2/csaf" "github.com/csaf-poc/csaf_distribution/v2/csaf"
"github.com/csaf-poc/csaf_distribution/v2/internal/certs"
"github.com/csaf-poc/csaf_distribution/v2/internal/filter" "github.com/csaf-poc/csaf_distribution/v2/internal/filter"
"github.com/csaf-poc/csaf_distribution/v2/internal/options" "github.com/csaf-poc/csaf_distribution/v2/internal/options"
"github.com/csaf-poc/csaf_distribution/v2/util" "github.com/csaf-poc/csaf_distribution/v2/util"
@ -52,6 +53,15 @@ type provider struct {
// IgnorePattern is a list of patterns of advisory URLs to be ignored. // IgnorePattern is a list of patterns of advisory URLs to be ignored.
IgnorePattern []string `toml:"ignorepattern"` IgnorePattern []string `toml:"ignorepattern"`
// ExtraHeader adds extra HTTP header fields to client
ExtraHeader http.Header `toml:"header"`
ClientCert *string `toml:"client_cert"`
ClientKey *string `toml:"client_key"`
ClientPassphrase *string `toml:"client_passphrase"`
clientCerts []tls.Certificate
ignorePattern filter.PatternMatcher ignorePattern filter.PatternMatcher
} }
@ -74,6 +84,10 @@ type config struct {
Passphrase *string `toml:"passphrase"` Passphrase *string `toml:"passphrase"`
AllowSingleProvider bool `toml:"allow_single_provider"` AllowSingleProvider bool `toml:"allow_single_provider"`
ClientCert *string `toml:"client_cert"`
ClientKey *string `toml:"client_key"`
ClientPassphrase *string `toml:"client_passphrase"`
// LockFile tries to lock to a given file. // LockFile tries to lock to a given file.
LockFile *string `toml:"lock_file"` LockFile *string `toml:"lock_file"`
@ -97,13 +111,18 @@ type config struct {
// IgnorePattern is a list of patterns of advisory URLs to be ignored. // IgnorePattern is a list of patterns of advisory URLs to be ignored.
IgnorePattern []string `toml:"ignorepattern"` IgnorePattern []string `toml:"ignorepattern"`
ignorePattern filter.PatternMatcher
// ExtraHeader adds extra HTTP header fields to client
ExtraHeader http.Header `toml:"header"`
Config string `short:"c" long:"config" description:"Path to config TOML file" value-name:"TOML-FILE" toml:"-"` Config string `short:"c" long:"config" description:"Path to config TOML file" value-name:"TOML-FILE" toml:"-"`
keyMu sync.Mutex keyMu sync.Mutex
key *crypto.Key key *crypto.Key
keyErr error keyErr error
clientCerts []tls.Certificate
ignorePattern filter.PatternMatcher
} }
// configPaths are the potential file locations of the config file. // configPaths are the potential file locations of the config file.
@ -217,20 +236,44 @@ func (c *config) privateOpenPGPKey() (*crypto.Key, error) {
func (c *config) httpClient(p *provider) util.Client { func (c *config) httpClient(p *provider) util.Client {
hClient := http.Client{} hClient := http.Client{}
var tlsConfig tls.Config
if p.Insecure != nil && *p.Insecure || c.Insecure != nil && *c.Insecure { if p.Insecure != nil && *p.Insecure || c.Insecure != nil && *c.Insecure {
hClient.Transport = &http.Transport{ tlsConfig.InsecureSkipVerify = true
TLSClientConfig: &tls.Config{ }
InsecureSkipVerify: true,
}, // Use client certs if needed.
switch {
// Provider has precedence over global.
case len(p.clientCerts) != 0:
tlsConfig.Certificates = p.clientCerts
case len(c.clientCerts) != 0:
tlsConfig.Certificates = c.clientCerts
}
hClient.Transport = &http.Transport{
TLSClientConfig: &tlsConfig,
}
client := util.Client(&hClient)
// Add extra headers.
switch {
// Provider has precedence over global.
case len(p.ExtraHeader) > 0:
client = &util.HeaderClient{
Client: client,
Header: p.ExtraHeader,
}
case len(c.ExtraHeader) > 0:
client = &util.HeaderClient{
Client: client,
Header: c.ExtraHeader,
} }
} }
var client util.Client
if c.Verbose { if c.Verbose {
client = &util.LoggingClient{Client: &hClient} client = &util.LoggingClient{Client: client}
} else {
client = &hClient
} }
if p.Rate == nil && c.Rate == nil { if p.Rate == nil && c.Rate == nil {
@ -325,7 +368,7 @@ func (c *config) setDefaults() {
func (p *provider) compileIgnorePatterns() error { func (p *provider) compileIgnorePatterns() error {
pm, err := filter.NewPatternMatcher(p.IgnorePattern) pm, err := filter.NewPatternMatcher(p.IgnorePattern)
if err != nil { if err != nil {
return err return fmt.Errorf("invalid ignore patterns for %q: %w", p.Name, err)
} }
p.ignorePattern = pm p.ignorePattern = pm
return nil return nil
@ -342,7 +385,37 @@ func (c *config) compileIgnorePatterns() error {
// Compile the patterns of the providers. // Compile the patterns of the providers.
for _, p := range c.Providers { for _, p := range c.Providers {
if err := p.compileIgnorePatterns(); err != nil { if err := p.compileIgnorePatterns(); err != nil {
return fmt.Errorf("invalid ignore patterns for %q: %w", p.Name, err) return err
}
}
return nil
}
// prepareCertificates loads the provider specific client side certificates
// used by the HTTP client.
func (p *provider) prepareCertificates() error {
cert, err := certs.LoadCertificate(
p.ClientCert, p.ClientKey, p.ClientPassphrase)
if err != nil {
return fmt.Errorf("invalid certificates for %q: %w", p.Name, err)
}
p.clientCerts = cert
return nil
}
// prepareCertificates loads the client side certificates used by the HTTP client.
func (c *config) prepareCertificates() error {
// Global certificates
cert, err := certs.LoadCertificate(
c.ClientCert, c.ClientKey, c.ClientPassphrase)
if err != nil {
return err
}
c.clientCerts = cert
// Provider certificates
for _, p := range c.Providers {
if err := p.prepareCertificates(); err != nil {
return err
} }
} }
return nil return nil
@ -355,17 +428,16 @@ func (c *config) prepare() error {
return errors.New("no providers given in configuration") return errors.New("no providers given in configuration")
} }
if err := c.compileIgnorePatterns(); err != nil { for _, prepare := range []func() error{
return err c.prepareCertificates,
c.compileIgnorePatterns,
c.Aggregator.Validate,
c.checkProviders,
c.checkMirror,
} {
if err := prepare(); err != nil {
return err
}
} }
return nil
if err := c.Aggregator.Validate(); err != nil {
return err
}
if err := c.checkProviders(); err != nil {
return err
}
return c.checkMirror()
} }

View file

@ -95,6 +95,10 @@ interim_years // limiting the years for which interim documents are se
verbose // print more diagnostic output, e.g. https requests (default false) verbose // print more diagnostic output, e.g. https requests (default false)
allow_single_provider // debugging option (default false) allow_single_provider // debugging option (default false)
ignorepattern // patterns of advisory URLs to be ignored ignorepattern // patterns of advisory URLs to be ignored
client_cert // path to client certificate to access access-protected advisories
client_key // path to client key to access access-protected advisories
client_passphrase // client passphrase to access access-protected advisories
header // adds extra HTTP header fields to the client
``` ```
Next we have two TOML _tables_: Next we have two TOML _tables_:
@ -125,6 +129,10 @@ update_interval
create_service_document create_service_document
categories categories
ignorepattern ignorepattern
client_cert
client_key
client_passphrase
header
``` ```
Where valid `name` and `domain` settings are required. Where valid `name` and `domain` settings are required.
@ -196,6 +204,10 @@ insecure = true
# rate = 1.2 # rate = 1.2
# insecure = true # insecure = true
write_indices = true write_indices = true
client_cert = "./../devca1/testclient1.crt"
client_key = "./../devca1/testclient1-key.pem"
# client_passphrase =
# header =
[[providers]] [[providers]]
name = "local-dev-provider3" name = "local-dev-provider3"

View file

@ -38,6 +38,10 @@ insecure = true
# rate = 1.2 # rate = 1.2
# insecure = true # insecure = true
write_indices = true write_indices = true
client_cert = "./../devca1/testclient1.crt"
client_key = "./../devca1/testclient1-key.pem"
# client_passphrase =
# header =
[[providers]] [[providers]]
name = "local-dev-provider3" name = "local-dev-provider3"