Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cache/advertise.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ func (server *CacheServer) GetAdTokCfg(ctx context.Context) (adTokCfg server_str
}
adTokCfg.Audience = directorUrl
adTokCfg.Subject = param.Cache_Url.GetString()
adTokCfg.Issuer = param.Server_IssuerUrl.GetString()
issuer, err := config.GetServerIssuerURL()
if err != nil {
err = errors.Wrap(err, "unable to determine server's issuer URL, needed for server advertising token")
return
}
adTokCfg.Issuer = issuer

return
}
Expand Down
7 changes: 4 additions & 3 deletions client/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,11 @@ func TestGenerateSortedObjectServers(t *testing.T) {
func TestGetToken(t *testing.T) {
// Need a namespace for token acquisition
defer os.Unsetenv("PELICAN_FEDERATION_TOPOLOGYNAMESPACEURL")
os.Setenv("PELICAN_TOPOLOGY_NAMESPACE_URL", "https://topology.opensciencegrid.org/osdf/namespaces")
os.Setenv("PELICAN_FEDERATION_TOPOLOGYNAMESPACEURL", "https://topology.opensciencegrid.org/osdf/namespaces")
server_utils.ResetTestState()
err := config.InitClient()
assert.Nil(t, err)
defer server_utils.ResetTestState()

test_utils.InitClient(t, nil)

mock.MockTopology(t, config.GetTransport())

Expand Down
139 changes: 0 additions & 139 deletions cmd/fed_serve_cache_test.go

This file was deleted.

6 changes: 4 additions & 2 deletions cmd/origin_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/spf13/cobra"

"github.com/pelicanplatform/pelican/config"
"github.com/pelicanplatform/pelican/param"
"github.com/pelicanplatform/pelican/server_structs"
"github.com/pelicanplatform/pelican/token"
)
Expand Down Expand Up @@ -133,7 +132,10 @@ func cliTokenCreate(cmd *cobra.Command, args []string) error {

// If a custom issuer is provided, we need to add it to the claims. If there is none, we'll end up falling back to
// the issuer generated by config.go/GetServerIssuerURL()
issuer := param.Server_IssuerUrl.GetString()
issuer, err := config.GetServerIssuerURL()
if err != nil {
return errors.Wrap(err, "unable to determine which issuer to use in token")
}
if issuer != "" {
args = append(args, "iss="+issuer)
}
Expand Down
65 changes: 41 additions & 24 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,39 +560,56 @@ func setupTransport() {
}
}

// Return an audience string appropriate for the current server
func GetServerAudience() string {
return viper.GetString("Origin.AudienceURL")
}
// GetServerIssuerURL tries to determine the correct issuer URL for the server in order of precedence:
// - Server.IssuerUrl
// - Server.IssuerHostname and Server.IssuerPort
// - Server.ExternalWebUrl
// In general, functions should avoid using `param.Server_IssuerUrl.GetString()` directly and use this function instead.
func GetServerIssuerURL() (issuerUrl string, err error) {
// Even though we prefer using this function, we'll populate the config param
// based on whatever we determine here.
defer func() {
if err == nil && param.Server_IssuerUrl.GetString() == "" {
viper.Set(param.Server_IssuerUrl.GetName(), issuerUrl)
}
}()

func GetServerIssuerURL() (string, error) {
if issuerUrl := param.Server_IssuerUrl.GetString(); issuerUrl != "" {
_, err := url.Parse(param.Server_IssuerUrl.GetString())
if err != nil {
return "", errors.Wrapf(err, "Failed to parse the Server.IssuerUrl %s loaded from config", param.Server_IssuerUrl.GetString())
// Prefer the concretely configured param
if issuerUrl = param.Server_IssuerUrl.GetString(); issuerUrl != "" {
if _, err := url.Parse(issuerUrl); err != nil {
return "", errors.Wrapf(err, "failed to parse '%s' as issuer URL from config param '%s'",
param.Server_IssuerUrl.GetString(), param.Server_IssuerUrl.GetName())
}
log.Debugf("Populating server's issuer URL as '%s' from config param '%s'", issuerUrl, param.Server_IssuerUrl.GetName())
return issuerUrl, nil
}

// Next, try to piece it together based on concretely configured hostname:port
if param.Server_IssuerHostname.GetString() != "" {
if param.Server_IssuerPort.GetInt() != 0 { // Will be the default if not set
// We assume any issuer is running https, otherwise we're crazy
issuerUrl := url.URL{
Scheme: "https",
Host: fmt.Sprintf("%s:%d", param.Server_IssuerHostname.GetString(), param.Server_IssuerPort.GetInt()),
}
return issuerUrl.String(), nil
if param.Server_IssuerPort.GetInt() == 0 {
return "", errors.Errorf("if '%s' is configured, you must also configure a valid port via '%s'",
param.Server_IssuerHostname.GetName(), param.Server_IssuerPort.GetName())
}

// We assume any issuer is running https
issuerUrl := fmt.Sprintf("https://%s:%d", param.Server_IssuerHostname.GetString(), param.Server_IssuerPort.GetInt())
if _, err := url.Parse(issuerUrl); err != nil {
return "", errors.Wrapf(err, "failed to parse '%s' as issuer URL from config params '%s' and '%s'",
issuerUrl, param.Server_IssuerHostname.GetName(), param.Server_IssuerPort.GetName())
}
return "", errors.New("If Server.IssuerHostname is configured, you must provide a valid port")
log.Debugf("Populating server's issuer URL as '%s' from configured values of '%s' and '%s'",
issuerUrl, param.Server_IssuerHostname.GetName(), param.Server_IssuerPort.GetName())
return issuerUrl, nil
}

issuerUrlStr := param.Server_ExternalWebUrl.GetString()
issuerUrl, err := url.Parse(issuerUrlStr)
log.Debugln("GetServerIssuerURL:", issuerUrlStr)
if err != nil {
return "", errors.Wrap(err, "Failed to parse the issuer URL generated using the parsed Server.ExternalWebUrl")
// Finally, fall back to the external web URL
issuerUrl = param.Server_ExternalWebUrl.GetString()
if _, err := url.Parse(issuerUrl); err != nil {
return "", errors.Wrapf(err, "failed to parse '%s' as the issuer URL generated from config param '%s'",
issuerUrl, param.Server_ExternalWebUrl.GetName())
}
return issuerUrl.String(), nil
log.Debugf("Populating server's issuer URL as '%s' from configured value of '%s'", issuerUrl, param.Server_ExternalWebUrl.GetName())
return issuerUrl, nil
}

// function to get/setup the transport (only once)
Expand Down Expand Up @@ -1207,7 +1224,7 @@ func SetServerDefaults(v *viper.Viper) error {
// a `0` for the port number; to make the audience predictable (it goes into the xrootd
// configuration but we don't know the origin's port until after xrootd has started), we
// stash a copy of its value now.
v.SetDefault("Origin.AudienceURL", v.GetString(param.Origin_Url.GetName()))
v.SetDefault(param.Origin_TokenAudience.GetName(), v.GetString(param.Origin_Url.GetName()))

// Set defaults for Director, Registry, and Broker URLs only if the Discovery URL is not set.
// This is necessary because, in Viper, there is currently no way to check if a value is coming
Expand Down
31 changes: 25 additions & 6 deletions docs/parameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,9 @@ description: |+

- StoragePrefix: The relevant path from the object store, e.g. for posix /my/dir
- FederationPrefix: The namespace prefix that data from StoragePrefix is made available under within the federation
- IssuerUrls: A list of URLs that token requests to the federation prefix can use as issuers. These issuer URLs are used
to craft the Origin's Scitokens configuration file. If unset, the Origin will fall back to its own external web URL and
assume its server keys are also used for minting data access tokens.
- Capabilities: A list of the capabilities the origin is willing to support for the given export. Capabilities include:
["Reads", "PublicReads", "Writes", "Listings", "DirectReads"]
where each of these has the same effect as the corresponding "Origin.Enable*" configuration, except scoped to the
Expand All @@ -614,16 +617,18 @@ description: |+
If running in a containerized environment it should not be the name of the underlying physical host as that may change and lead to confusion.
You need to manually create a file under path to `StoragePrefix` with the same name as `SentinelLocation`.

Note that this parameter is only available for the POSIX backend.
Note that this parameter is only available for POSIX and S3 backends.

Example:

```yaml
Origin.Exports
- StoragePrefix: /home/foo/bar
FederationPrefix: /demo/project
Capabilities: ["Reads", "PublicReads", "Writes", "Listings", "DirectReads"]
SentinelLocation: demoproject_origin_A
Origin:
Exports:
- StoragePrefix: /home/foo/bar
FederationPrefix: /demo/project
Capabilities: ["Reads", "PublicReads", "Writes", "Listings", "DirectReads"]
SentinelLocation: demoproject_origin_A
IssuerUrls: ["https://issuer1.example.com", "https://issuer2.example.com"]
```

If Origin.StorageType == "s3", the following additional fields are available:
Expand Down Expand Up @@ -934,6 +939,20 @@ type: string
default: none
components: ["origin"]
---
name: Origin.TokenAudience
description: |+
This parameter can be used to configure accepted audiences for the Origin's SciTokens configuration, referenced when deciding
whether to accept a token for data access. When set, the Origin will only accept tokens with an audience that matches one of the
provided URLs.

For example, when set to `https://foo.com:8443`, the following will appear in the Origin's auto-generated scitokens configuration:
`[Global]
audience_json = ["https://foo.com:8443"]`
type: string
default: ${Origin.Url}
hidden: true
components: ["origin"]
---
name: Origin.XRootDPrefix
description: |+
The directory prefix for the XRootD origin configuration files.
Expand Down
Loading
Loading