diff --git a/config/resources/osdf.yaml b/config/resources/osdf.yaml index de9c88037..32bd8a6e0 100644 --- a/config/resources/osdf.yaml +++ b/config/resources/osdf.yaml @@ -26,3 +26,8 @@ Federation: Registry: RequireCacheApproval: true RequireOriginApproval: true +Director: + X509ClientAuthenticationPrefixes: + - /xenon/PROTECTED/ + - /user/ligo/ + - /igwn/ diff --git a/director/director.go b/director/director.go index b160fc361..2ec3a29a2 100644 --- a/director/director.go +++ b/director/director.go @@ -798,6 +798,13 @@ func redirectToOrigin(ginCtx *gin.Context) { ginCtx.Header("X-Pelican-Broker", brokerUrl.String()) } + for _, prefix := range param.Director_X509ClientAuthenticationPrefixes.GetStringSlice() { + if strings.HasPrefix(reqPath, prefix) { + ginCtx.Writer.Header().Add("X-Osdf-X509", "true") + break + } + } + // See note in RedirectToCache as to why we only add the authz query parameter to this URL, // not those in the `Link`. ginCtx.Redirect(http.StatusTemporaryRedirect, getFinalRedirectURL(redirectURL, reqParams)) diff --git a/director/prom_query.go b/director/prom_query.go index 8c4475c0f..59543eb6c 100644 --- a/director/prom_query.go +++ b/director/prom_query.go @@ -147,7 +147,7 @@ func parsePromRes(res promQLRes) (promParsed promQLParsed, err error) { ResultType: data.ResultType, } - if data.Result != nil && len(data.Result) > 0 { + if len(data.Result) > 0 { switch data.Result[0].(type) { case float64: // result: [unixtime, value] if len(data.Result) == 2 && (data.ResultType == "scalar" || data.ResultType == "string") { diff --git a/docs/parameters.yaml b/docs/parameters.yaml index a4ce75510..37c87417a 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -1402,6 +1402,19 @@ type: bool default: false components: ["director"] --- +name: Director.X509ClientAuthenticationPrefixes +description: |+ + A list of object prefixes where the origin uses X.509 client authentication. + + If a cache requests an object starting with one of these prefixes, then it will be instructed by the director + to use X.509 client authentication if available. + + This setting allows for compatibility with specific legacy OSDF origins and is not needed for new origins. +type: stringSlice +default: none +components: ["director"] +hidden: true +--- ############################ # Registry-level configs # ############################ diff --git a/local_cache/local_cache.go b/local_cache/local_cache.go index fe3cd5f9b..40fb7af43 100644 --- a/local_cache/local_cache.go +++ b/local_cache/local_cache.go @@ -803,7 +803,7 @@ func (cr *cacheReader) peekError(ctx context.Context) (err error) { } func (cr *cacheReader) Read(p []byte) (n int, err error) { - if cr.buf != nil && len(cr.buf) > 0 { + if len(cr.buf) > 0 { bytesCopied := copy(p, cr.buf) if len(cr.buf) > bytesCopied { cr.buf = cr.buf[bytesCopied:] diff --git a/param/parameters.go b/param/parameters.go index 32360b1ef..82f8c6adb 100644 --- a/param/parameters.go +++ b/param/parameters.go @@ -279,6 +279,7 @@ var ( Director_CacheResponseHostnames = StringSliceParam{"Director.CacheResponseHostnames"} Director_FilteredServers = StringSliceParam{"Director.FilteredServers"} Director_OriginResponseHostnames = StringSliceParam{"Director.OriginResponseHostnames"} + Director_X509ClientAuthenticationPrefixes = StringSliceParam{"Director.X509ClientAuthenticationPrefixes"} Issuer_GroupRequirements = StringSliceParam{"Issuer.GroupRequirements"} Monitoring_AggregatePrefixes = StringSliceParam{"Monitoring.AggregatePrefixes"} Origin_ExportVolumes = StringSliceParam{"Origin.ExportVolumes"} diff --git a/param/parameters_struct.go b/param/parameters_struct.go index 32eb78faf..ac4d51a58 100644 --- a/param/parameters_struct.go +++ b/param/parameters_struct.go @@ -78,6 +78,7 @@ type Config struct { StatTimeout time.Duration `mapstructure:"stattimeout"` SupportContactEmail string `mapstructure:"supportcontactemail"` SupportContactUrl string `mapstructure:"supportcontacturl"` + X509ClientAuthenticationPrefixes []string `mapstructure:"x509clientauthenticationprefixes"` } `mapstructure:"director"` DisableHttpProxy bool `mapstructure:"disablehttpproxy"` DisableProxyFallback bool `mapstructure:"disableproxyfallback"` @@ -372,6 +373,7 @@ type configWithType struct { StatTimeout struct { Type string; Value time.Duration } SupportContactEmail struct { Type string; Value string } SupportContactUrl struct { Type string; Value string } + X509ClientAuthenticationPrefixes struct { Type string; Value []string } } DisableHttpProxy struct { Type string; Value bool } DisableProxyFallback struct { Type string; Value bool } diff --git a/registry/custom_reg_fields.go b/registry/custom_reg_fields.go index 0cf78f3da..58c7d3559 100644 --- a/registry/custom_reg_fields.go +++ b/registry/custom_reg_fields.go @@ -282,7 +282,7 @@ func InitCustomRegistrationFields() error { return errors.New(fmt.Sprintf("Bad custom registration field, unsupported field type: %q with %q", conf.Name, conf.Type)) } if conf.Type == "enum" { - if (conf.Options == nil || len(conf.Options) == 0) && conf.OptionsUrl == "" { + if len(conf.Options) == 0 && conf.OptionsUrl == "" { return errors.New(fmt.Sprintf("Bad custom registration field, 'enum' type field does not have options or optionsUrl set: %q", conf.Name)) } } diff --git a/xrootd/launch.go b/xrootd/launch.go index 76cce7924..a1ec277a6 100644 --- a/xrootd/launch.go +++ b/xrootd/launch.go @@ -84,6 +84,8 @@ func makeUnprivilegedXrootdLauncher(daemonName string, configPath string, isCach "XRD_PELICANBROKERSOCKET=" + filepath.Join(xrootdRun, "cache-reversal.sock"), "XRD_PLUGINCONFDIR=" + filepath.Join(xrootdRun, "cache-client.plugins.d"), "X509_CERT_FILE=" + filepath.Join(xrootdRun, "ca-bundle.crt"), + "XRD_PELICANCLIENTCERTFILE=" + filepath.Join(xrootdRun, "copied-tls-creds.crt"), + "XRD_PELICANCLIENTKEYFILE=" + filepath.Join(xrootdRun, "copied-tls-creds.crt"), } } return