mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 11:55:40 +01:00
Pwacc (#218)
* Adds option to require Client Certificate and a Password to aquire write access in provider * Removed unnecessary flavourtext from provider markdown file * Fixed and simplified the auth middleware Co-authored-by: Jan Höfelmeyer <Jan Höfelmeyer jhoefelmeyer@intevation.de> Co-authored-by: Sascha L. Teichmann <sascha.teichmann@intevation.de>
This commit is contained in:
parent
50024915f4
commit
2ac7940206
3 changed files with 47 additions and 24 deletions
|
|
@ -48,6 +48,7 @@ type config struct {
|
|||
TLPs []tlp `toml:"tlps"`
|
||||
UploadSignature bool `toml:"upload_signature"`
|
||||
CanonicalURLPrefix string `toml:"canonical_url_prefix"`
|
||||
CertificateAndPassword bool `toml:"certificate_and_password"`
|
||||
NoPassphrase bool `toml:"no_passphrase"`
|
||||
NoValidation bool `toml:"no_validation"`
|
||||
NoWebUI bool `toml:"no_web_ui"`
|
||||
|
|
|
|||
|
|
@ -72,36 +72,57 @@ func (c *controller) bind(pim *pathInfoMux) {
|
|||
pim.handleFunc("/api/create", c.auth(api(c.create)))
|
||||
}
|
||||
|
||||
// auth wraps the given http.HandlerFunc and returns an new one after authenticating the
|
||||
// password contained in the header "X-CSAF-PROVIDER-AUTH" with the "password" config value
|
||||
// if set, otherwise returns the given http.HandlerFunc.
|
||||
// authenticate checks if the incoming request confirms with the
|
||||
// configured authentication mechanism.
|
||||
func (c *controller) authenticate(r *http.Request) bool {
|
||||
|
||||
verify := os.Getenv("SSL_CLIENT_VERIFY")
|
||||
log.Printf("SSL_CLIENT_VERIFY: %s\n", verify)
|
||||
if verify == "SUCCESS" || strings.HasPrefix(verify, "FAILED") {
|
||||
// potentially we want to see the Issuer when there is a problem
|
||||
// but it is not clear if we get this far in case of "FAILED".
|
||||
// docs (accessed 2022-03-31 when 1.20.2 was current stable):
|
||||
// https://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_verify
|
||||
log.Printf("SSL_CLIENT_I_DN: %s\n", os.Getenv("SSL_CLIENT_I_DN"))
|
||||
}
|
||||
|
||||
checkCert := func() bool {
|
||||
return verify == "SUCCESS" && (c.cfg.Issuer == nil || *c.cfg.Issuer == os.Getenv("SSL_CLIENT_I_DN"))
|
||||
}
|
||||
|
||||
checkPassword := func() bool {
|
||||
return c.cfg.checkPassword(r.Header.Get("X-CSAF-PROVIDER-AUTH"))
|
||||
}
|
||||
|
||||
if c.cfg.CertificateAndPassword {
|
||||
if c.cfg.Password == nil {
|
||||
log.Println("No password set, declining access.")
|
||||
return false
|
||||
}
|
||||
log.Printf("user: %s\n", os.Getenv("SSL_CLIENT_S_DN"))
|
||||
return checkPassword() && checkCert()
|
||||
}
|
||||
|
||||
switch {
|
||||
case checkCert():
|
||||
log.Printf("user: %s\n", os.Getenv("SSL_CLIENT_S_DN"))
|
||||
case c.cfg.Password == nil:
|
||||
log.Println("No password set, declining access.")
|
||||
return false
|
||||
default:
|
||||
return checkPassword()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// auth is a middleware to decorate endpoints with authentication.
|
||||
func (c *controller) auth(
|
||||
fn func(http.ResponseWriter, *http.Request),
|
||||
) func(http.ResponseWriter, *http.Request) {
|
||||
return func(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
verify := os.Getenv("SSL_CLIENT_VERIFY")
|
||||
log.Printf("SSL_CLIENT_VERIFY: %s\n", verify)
|
||||
if verify == "SUCCESS" || strings.HasPrefix(verify, "FAILED") {
|
||||
// potentially we want to see the Issuer when there is a problem
|
||||
// but it is not clear if we get this far in case of "FAILED".
|
||||
// docs (accessed 2022-03-31 when 1.20.2 was current stable):
|
||||
// https://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_verify
|
||||
log.Printf("SSL_CLIENT_I_DN: %s\n", os.Getenv("SSL_CLIENT_I_DN"))
|
||||
}
|
||||
|
||||
switch {
|
||||
case verify == "SUCCESS" && (c.cfg.Issuer == nil || *c.cfg.Issuer == os.Getenv("SSL_CLIENT_I_DN")):
|
||||
log.Printf("user: %s\n", os.Getenv("SSL_CLIENT_S_DN"))
|
||||
case c.cfg.Password == nil:
|
||||
log.Println("No password set, declining access.")
|
||||
if !c.authenticate(r) {
|
||||
http.Error(rw, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
||||
return
|
||||
default:
|
||||
if pa := r.Header.Get("X-CSAF-PROVIDER-AUTH"); !c.cfg.checkPassword(pa) {
|
||||
http.Error(rw, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
fn(rw, r)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Following options are supported in the config file:
|
|||
- web: Specify the web folder. Default: `/var/www/html`.
|
||||
- upload_signature: Send signature with the request, an additional input-field in the web interface will be shown to let user enter an ascii armored signature. Default: `false`.
|
||||
- canonical_url_prefix: start of the URL where contents shall be accessible from the internet. Default: `https://$SERVER_NAME`.
|
||||
- certificate_and_password: Require password and a valid Client Certificate for write access. Default: false
|
||||
- no_passphrase: Let the user send the request without having to send a password. If set to true, the input-field in the web interface will be omitted. Default: `false`.
|
||||
- no_validation: Skip validation of the uploaded CSAF document against the JSON schema. Default: `false`.
|
||||
- no_web_ui: Disable the web interface. Default: `false`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue