Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Origin requires multiple scitokens #1989

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
16 changes: 16 additions & 0 deletions origin/advertise.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,19 @@ func (server *OriginServer) GetAuthorizedPrefixes() ([]string, error) {

return prefixes, nil
}

func (server *OriginServer) GetPublicReadOnlyPrefixes() ([]string, error) {
var prefixes []string
originExports, err := server_utils.GetOriginExports()
if err != nil {
return nil, err
}

for _, export := range originExports {
if export.Capabilities.PublicReads && !export.Capabilities.DirectReads && !export.Capabilities.Writes {
prefixes = append(prefixes, export.FederationPrefix)
}
}

return prefixes, nil
}
40 changes: 35 additions & 5 deletions xrootd/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type (
DefaultUser string
UsernameClaim string
NameMapfile string
FedIssuer bool
}

// Top-level configuration object for the template
Expand Down Expand Up @@ -299,7 +300,7 @@ func EmitAuthfile(server server_structs.XRootDServer) error {
}

for _, export := range originExports {
if export.Capabilities.PublicReads {
if export.Capabilities.DirectReads {
outStr += export.FederationPrefix + " lr "
}
}
Expand All @@ -314,7 +315,7 @@ func EmitAuthfile(server server_structs.XRootDServer) error {
output.Write([]byte(lineContents + "\n"))
}
}
// If Origin has no authfile already exists, add the ./well-known to the authfile
// If Origin has no authfile already, add the ./well-known to the authfile
if !foundPublicLine && server.GetServerType().IsEnabled(server_structs.OriginType) {
outStr := "u * /.well-known lr"

Expand All @@ -325,7 +326,7 @@ func EmitAuthfile(server server_structs.XRootDServer) error {
}

for _, export := range originExports {
if export.Capabilities.PublicReads {
if export.Capabilities.DirectReads {
outStr += " " + export.FederationPrefix + " lr"
}
}
Expand Down Expand Up @@ -482,6 +483,19 @@ func GenerateOriginIssuer(exportedPaths []string) (issuer Issuer, err error) {
return
}

func GenerateFederationIssuer(authPaths []string, publicPaths []string) (issuer Issuer) {
if len(authPaths) == 0 && len(publicPaths) == 0 {
return
}

issuer.Name = "Registry"
issuer.Issuer = param.Federation_DiscoveryUrl.GetString()
issuer.BasePaths = append(authPaths, publicPaths...)
issuer.FedIssuer = true

return
}

// We have a special issuer just for director-based monitoring of the origin.
func GenerateDirectorMonitoringIssuer() (issuer Issuer, err error) {
fedInfo, err := config.GetFederation(context.Background())
Expand Down Expand Up @@ -536,7 +550,11 @@ func EmitScitokensConfig(server server_structs.XRootDServer) error {
if err != nil {
return err
}
return WriteOriginScitokensConfig(authedPrefixes)
publicReadsPrefixes, err := originServer.GetPublicReadOnlyPrefixes()
if err != nil {
return err
}
return WriteOriginScitokensConfig(authedPrefixes, publicReadsPrefixes)
} else if cacheServer, ok := server.(*cache.CacheServer); ok {
directorAds := cacheServer.GetNamespaceAds()
if param.Cache_SelfTest.GetBool() {
Expand Down Expand Up @@ -564,7 +582,7 @@ func EmitScitokensConfig(server server_structs.XRootDServer) error {
}

// Writes out the origin's scitokens.cfg configuration
func WriteOriginScitokensConfig(authedPaths []string) error {
func WriteOriginScitokensConfig(authedPaths []string, publicReadPaths []string) error {
cfg, err := makeSciTokensCfg()
if err != nil {
return err
Expand All @@ -585,6 +603,18 @@ func WriteOriginScitokensConfig(authedPaths []string) error {
return errors.Wrap(err, "failed to generate xrootd issuer for the origin")
}

if issuer := GenerateFederationIssuer(authedPaths, publicReadPaths); len(issuer.Name) > 0 {
if val, ok := cfg.IssuerMap[issuer.Issuer]; ok {
val.BasePaths = append(val.BasePaths, issuer.BasePaths...)
val.Name += " and " + issuer.Name
cfg.IssuerMap[issuer.Issuer] = val
} else {
cfg.IssuerMap[issuer.Issuer] = issuer
}
} else if err != nil {
return errors.Wrap(err, "failed to generate xrootd registry issuer for the origin")
}

if issuer, err := GenerateMonitoringIssuer(); err == nil && len(issuer.Name) > 0 {
if val, ok := cfg.IssuerMap[issuer.Issuer]; ok {
val.BasePaths = append(val.BasePaths, issuer.BasePaths...)
Expand Down
68 changes: 66 additions & 2 deletions xrootd/authorization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,68 @@ func TestEmitAuthfile(t *testing.T) {
}
}

func TestEmitOriginAuthfileWithCapabilities(t *testing.T) {
tests := []struct {
desc string
name string
authOut string
capabilities []string
}{
{
desc: "public-reads",
name: "/public",
authOut: "u * /.well-known lr\n",
capabilities: []string{"Origin.EnablePublicReads"},
},
{
desc: "direct-reads",
name: "/direct",
authOut: "u * /.well-known lr /direct lr\n",
capabilities: []string{"Origin.EnableDirectReads"},
},
{
desc: "direct-and-public-reads",
name: "/direct-public",
authOut: "u * /.well-known lr /direct-public lr\n",
capabilities: []string{"Origin.EnablePublicReads", "Origin.EnableDirectReads"},
},
{
desc: "no-public-access",
name: "/private",
authOut: "u * /.well-known lr\n",
capabilities: []string{"Origin.EnableReads"},
},
}
for _, testInput := range tests {
t.Run(testInput.desc, func(t *testing.T) {
dirName := t.TempDir()
server_utils.ResetTestState()

defer server_utils.ResetTestState()

viper.Set("Xrootd.Authfile", filepath.Join(dirName, "authfile"))
viper.Set("Origin.RunLocation", dirName)
viper.Set("Origin.FederationPrefix", testInput.name)
viper.Set("Origin.StoragePrefix", "/")
for _, cap := range testInput.capabilities {
viper.Set(cap, true)
}
originServer := &origin.OriginServer{}

err := os.WriteFile(filepath.Join(dirName, "authfile"), []byte(""), fs.FileMode(0600))
require.NoError(t, err)

err = EmitAuthfile(originServer)
require.NoError(t, err)

contents, err := os.ReadFile(filepath.Join(dirName, "authfile-origin-generated"))
require.NoError(t, err)

assert.Equal(t, testInput.authOut, string(contents))
})
}
}

func TestEmitCfg(t *testing.T) {
dirname := t.TempDir()
server_utils.ResetTestState()
Expand Down Expand Up @@ -611,7 +673,7 @@ func TestWriteOriginAuthFiles(t *testing.T) {

t.Run("EmptyAuth", originAuthTester(originServer, "", "u * /.well-known lr\n"))

viper.Set("Origin.EnablePublicReads", true)
viper.Set("Origin.EnableDirectReads", true)
viper.Set("Origin.FederationPrefix", "/foo/bar")
t.Run("PublicAuth", originAuthTester(originServer, "", "u * /.well-known lr /foo/bar lr\n"))
}
Expand Down Expand Up @@ -753,7 +815,9 @@ func TestWriteOriginScitokensConfig(t *testing.T) {
err = os.WriteFile(scitokensCfg, []byte(toMergeOutput), 0640)
require.NoError(t, err)

err = WriteOriginScitokensConfig([]string{"/foo/bar"})
viper.Set("Federation.DiscoveryUrl", "fed.discovery.com")

err = WriteOriginScitokensConfig([]string{"/foo/bar"}, []string{"/public"})
require.NoError(t, err)

genCfg, err := os.ReadFile(filepath.Join(dirname, "scitokens-origin-generated.cfg"))
Expand Down
4 changes: 4 additions & 0 deletions xrootd/resources/scitokens.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ name_mapfile = {{.NameMapfile}}
{{- if .UsernameClaim}}
username_claim = {{.UsernameClaim}}
{{- end}}
{{- if .FedIssuer}}
required_authorization = all
acceptable_authorization = none
{{- end}}

{{end -}}
# End of config
6 changes: 6 additions & 0 deletions xrootd/resources/test-scitokens-monitoring.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
[Global]
audience_json = ["test_audience","https://origin.example.com:8443"]

[Issuer Registry]
issuer = fed.discovery.com
base_path = /foo/bar, /public
required_authorization = all
acceptable_authorization = none

[Issuer Demo]
issuer = https://demo.scitokens.org
base_path = /bar, /foo
Expand Down
6 changes: 5 additions & 1 deletion xrootd/xrootd_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,11 @@ func CheckOriginXrootdEnv(exportPath string, server server_structs.XRootDServer,
if err != nil {
return err
}
err = WriteOriginScitokensConfig(authedPrefixes)
publicReadPrefixes, err := originServer.GetPublicReadOnlyPrefixes()
if err != nil {
return err
}
err = WriteOriginScitokensConfig(authedPrefixes, publicReadPrefixes)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions xrootd/xrootd_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ func TestUpdateAuth(t *testing.T) {
viper.Set("Xrootd.ScitokensConfig", scitokensName)
viper.Set("Origin.FederationPrefix", "/test")
viper.Set("Origin.StoragePrefix", "/")
viper.Set("Origin.EnableDirectReads", false)
config.InitConfig()

err := config.InitServer(ctx, server_structs.OriginType)
Expand Down
Loading