18676: tolerate V2 anonymous tokens in config.yml, but generate a
authorWard Vandewege <ward@curii.com>
Thu, 17 Feb 2022 16:07:20 +0000 (11:07 -0500)
committerWard Vandewege <ward@curii.com>
Thu, 17 Feb 2022 16:07:20 +0000 (11:07 -0500)
       warning.

Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward@curii.com>

doc/admin/upgrading.html.textile.liquid
lib/config/load.go

index 05b932a116bea3578dbf3e21563f6745eef80208..61068ca24d0a2e92eeca4858eb4fee04ef47ef9a 100644 (file)
@@ -41,7 +41,7 @@ h2(#main). development main (as of 2022-02-10)
 
 h3. Anonymous token changes
 
 
 h3. Anonymous token changes
 
-The anonymous token configured in @Users.AnonymousUserToken@ must now be 32 characters or longer. This was already the suggestion in the documentation, now it is enforced. The @script/get_anonymous_user_token.rb@ script that was needed to register the anonymous user token in the database has been removed. Registration of the anonymous token is no longer necessary.
+The anonymous token configured in @Users.AnonymousUserToken@ must now be 32 characters or longer. This was already the suggestion in the documentation, now it is enforced. The @script/get_anonymous_user_token.rb@ script that was needed to register the anonymous user token in the database has been removed. Registration of the anonymous token is no longer necessary. If the anonymous token in @config.yml@ is specified as a full V2 token, that will now generate a warning - it should be updated to list just the secret (i.e. the part after the last forward slash).
 
 h3. Preemptible instance types are used automatically, if any are configured
 
 
 h3. Preemptible instance types are used automatically, if any are configured
 
index aa7520ca29e7d6fe2d4040e50ae11f3416b98c77..e412c87ff93ac073c2fe2ae78f0ee72b4232936a 100644 (file)
@@ -299,10 +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),
                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, true),
-                       ldr.checkToken(fmt.Sprintf("Clusters.%s.SystemRootToken", id), cc.SystemRootToken, true),
-                       ldr.checkToken(fmt.Sprintf("Clusters.%s.Users.AnonymousUserToken", id), cc.Users.AnonymousUserToken, false),
-                       ldr.checkToken(fmt.Sprintf("Clusters.%s.Collections.BlobSigningKey", id), cc.Collections.BlobSigningKey, true),
+                       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),
                        checkKeyConflict(fmt.Sprintf("Clusters.%s.PostgreSQL.Connection", id), cc.PostgreSQL.Connection),
                        ldr.checkEnum("Containers.LocalKeepLogsToContainerLog", cc.Containers.LocalKeepLogsToContainerLog, "none", "all", "errors"),
                        ldr.checkEmptyKeepstores(cc),
@@ -316,6 +316,11 @@ func (ldr *Loader) Load() (*arvados.Config, error) {
                                return nil, err
                        }
                }
                                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
 }
        }
        return &cfg, nil
 }
@@ -334,7 +339,7 @@ func (ldr *Loader) checkClusterID(label, clusterID string, emptyStringOk bool) e
 var acceptableTokenRe = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
 var acceptableTokenLength = 32
 
 var acceptableTokenRe = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
 var acceptableTokenLength = 32
 
-func (ldr *Loader) checkToken(label, token string, mandatory bool) error {
+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
        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
@@ -345,7 +350,18 @@ func (ldr *Loader) checkToken(label, token string, mandatory bool) error {
                        }
                }
        } else if !acceptableTokenRe.MatchString(token) {
                        }
                }
        } 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)
+               }
+               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)
        } 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)