18676: make v2 token check more strict, and add the ["GET /"] scope to
[arvados.git] / lib / config / load.go
index c2eb55554488f465a7dc990b87ad6da450459a4d..8d498af170f2180881fac496c82900b1bd764d7f 100644 (file)
@@ -299,9 +299,10 @@ func (ldr *Loader) Load() (*arvados.Config, error) {
                for _, err = range []error{
                        ldr.checkClusterID(fmt.Sprintf("Clusters.%s", id), id, false),
                        ldr.checkClusterID(fmt.Sprintf("Clusters.%s.Login.LoginCluster", id), cc.Login.LoginCluster, true),
-                       ldr.checkToken(fmt.Sprintf("Clusters.%s.ManagementToken", id), cc.ManagementToken),
-                       ldr.checkToken(fmt.Sprintf("Clusters.%s.SystemRootToken", id), cc.SystemRootToken),
-                       ldr.checkToken(fmt.Sprintf("Clusters.%s.Collections.BlobSigningKey", id), cc.Collections.BlobSigningKey),
+                       ldr.checkToken(fmt.Sprintf("Clusters.%s.ManagementToken", id), cc.ManagementToken, true, false),
+                       ldr.checkToken(fmt.Sprintf("Clusters.%s.SystemRootToken", id), cc.SystemRootToken, true, false),
+                       ldr.checkToken(fmt.Sprintf("Clusters.%s.Users.AnonymousUserToken", id), cc.Users.AnonymousUserToken, false, true),
+                       ldr.checkToken(fmt.Sprintf("Clusters.%s.Collections.BlobSigningKey", id), cc.Collections.BlobSigningKey, true, false),
                        checkKeyConflict(fmt.Sprintf("Clusters.%s.PostgreSQL.Connection", id), cc.PostgreSQL.Connection),
                        ldr.checkEnum("Containers.LocalKeepLogsToContainerLog", cc.Containers.LocalKeepLogsToContainerLog, "none", "all", "errors"),
                        ldr.checkEmptyKeepstores(cc),
@@ -315,6 +316,11 @@ func (ldr *Loader) Load() (*arvados.Config, error) {
                                return nil, err
                        }
                }
+               if strings.Count(cc.Users.AnonymousUserToken, "/") == 3 {
+                       // V2 token, strip it to just a secret
+                       tmp := strings.Split(cc.Users.AnonymousUserToken, "/")
+                       cc.Users.AnonymousUserToken = tmp[2]
+               }
        }
        return &cfg, nil
 }
@@ -333,13 +339,32 @@ func (ldr *Loader) checkClusterID(label, clusterID string, emptyStringOk bool) e
 var acceptableTokenRe = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
 var acceptableTokenLength = 32
 
-func (ldr *Loader) checkToken(label, token string) error {
-       if token == "" {
-               if ldr.Logger != nil {
-                       ldr.Logger.Warnf("%s: secret token is not set (use %d+ random characters from a-z, A-Z, 0-9)", label, acceptableTokenLength)
+func (ldr *Loader) checkToken(label, token string, mandatory bool, acceptV2 bool) error {
+       if len(token) == 0 {
+               if !mandatory {
+                       // when a token is not mandatory, the acceptable length and content is only checked if its length is non-zero
+                       return nil
+               } else {
+                       if ldr.Logger != nil {
+                               ldr.Logger.Warnf("%s: secret token is not set (use %d+ random characters from a-z, A-Z, 0-9)", label, acceptableTokenLength)
+                       }
                }
        } else if !acceptableTokenRe.MatchString(token) {
-               return fmt.Errorf("%s: unacceptable characters in token (only a-z, A-Z, 0-9 are acceptable)", label)
+               if !acceptV2 {
+                       return fmt.Errorf("%s: unacceptable characters in token (only a-z, A-Z, 0-9 are acceptable)", label)
+               }
+               // Test for a proper V2 token
+               tmp := strings.SplitN(token, "/", 3)
+               if len(tmp) != 3 {
+                       return fmt.Errorf("%s: unacceptable characters in token (only a-z, A-Z, 0-9 are acceptable)", label)
+               }
+               if !strings.HasPrefix(token, "v2/") {
+                       return fmt.Errorf("%s: unacceptable characters in token (only a-z, A-Z, 0-9 are acceptable)", label)
+               }
+               ldr.Logger.Warnf("%s: token is a full V2 token, should just be a secret (remove everything up to and including the last forward slash)", label)
+               if !acceptableTokenRe.MatchString(tmp[2]) {
+                       return fmt.Errorf("%s: unacceptable characters in V2 token secret (only a-z, A-Z, 0-9 are acceptable)", label)
+               }
        } else if len(token) < acceptableTokenLength {
                if ldr.Logger != nil {
                        ldr.Logger.Warnf("%s: token is too short (should be at least %d characters)", label, acceptableTokenLength)