14965: Fixes rmdir and rename op encoding
[arvados.git] / lib / controller / fed_containers.go
index 32ae25fc4b87dd26c128d8d4e2a52edd382c0a3c..7fd5b25ad22b8b946f7a36e57859cce1896d80e7 100644 (file)
@@ -9,8 +9,8 @@ import (
        "encoding/json"
        "fmt"
        "io/ioutil"
-       "log"
        "net/http"
+       "strings"
 
        "git.curoverse.com/arvados.git/sdk/go/auth"
        "git.curoverse.com/arvados.git/sdk/go/httpserver"
@@ -25,45 +25,89 @@ func remoteContainerRequestCreate(
        w http.ResponseWriter,
        req *http.Request) bool {
 
-       if effectiveMethod != "POST" || uuid != "" || remainder != "" ||
-               *clusterId == "" || *clusterId == h.handler.Cluster.ClusterID {
+       if effectiveMethod != "POST" || uuid != "" || remainder != "" {
                return false
        }
 
-       defer req.Body.Close()
-       var request map[string]interface{}
-       err := json.NewDecoder(req.Body).Decode(&request)
+       // First make sure supplied token is valid.
+       creds := auth.NewCredentials()
+       creds.LoadTokensFromHTTPRequest(req)
 
-       containerRequest, ok := request["container_request"].(map[string]interface{})
-       if !ok {
-               log.Printf("wah wah")
+       currentUser, err := h.handler.validateAPItoken(req, creds.Tokens[0])
+       if err != nil {
+               httpserver.Error(w, err.Error(), http.StatusForbidden)
+               return true
+       }
+
+       if *clusterId == "" {
+               *clusterId = h.handler.Cluster.ClusterID
+       }
+
+       if strings.HasPrefix(currentUser.Authorization.UUID, h.handler.Cluster.ClusterID) &&
+               *clusterId == h.handler.Cluster.ClusterID {
+               // local user submitting container request to local cluster
                return false
        }
 
-       // If runtime_token is not set, create a new token
-       if _, ok := containerRequest["runtime_token"]; !ok {
-               log.Printf("ok %v", ok)
+       if req.Header.Get("Content-Type") != "application/json" {
+               httpserver.Error(w, "Expected Content-Type: application/json, got "+req.Header.Get("Content-Type"), http.StatusBadRequest)
+               return true
+       }
 
-               // First make sure supplied token is valid.
-               creds := auth.NewCredentials()
-               creds.LoadTokensFromHTTPRequest(req)
+       originalBody := req.Body
+       defer originalBody.Close()
+       var request map[string]interface{}
+       err = json.NewDecoder(req.Body).Decode(&request)
+       if err != nil {
+               httpserver.Error(w, err.Error(), http.StatusBadRequest)
+               return true
+       }
 
-               currentUser, err := h.handler.validateAPItoken(req, creds.Tokens[0])
+       crString, ok := request["container_request"].(string)
+       if ok {
+               var crJson map[string]interface{}
+               err := json.Unmarshal([]byte(crString), &crJson)
                if err != nil {
-                       httpserver.Error(w, err.Error(), http.StatusForbidden)
+                       httpserver.Error(w, err.Error(), http.StatusBadRequest)
                        return true
                }
 
+               request["container_request"] = crJson
+       }
+
+       containerRequest, ok := request["container_request"].(map[string]interface{})
+       if !ok {
+               // Use toplevel object as the container_request object
+               containerRequest = request
+       }
+
+       // If runtime_token is not set, create a new token
+       if _, ok := containerRequest["runtime_token"]; !ok {
                if len(currentUser.Authorization.Scopes) != 1 || currentUser.Authorization.Scopes[0] != "all" {
-                       return false
+                       httpserver.Error(w, "Token scope is not [all]", http.StatusForbidden)
+                       return true
                }
 
-               newtok, err := h.handler.createAPItoken(req, currentUser.UUID, nil)
-               if err != nil {
-                       httpserver.Error(w, err.Error(), http.StatusForbidden)
-                       return true
+               if strings.HasPrefix(currentUser.Authorization.UUID, h.handler.Cluster.ClusterID) {
+                       // Local user, submitting to a remote cluster.
+                       // Create a new time-limited token.
+                       newtok, err := h.handler.createAPItoken(req, currentUser.UUID, nil)
+                       if err != nil {
+                               httpserver.Error(w, err.Error(), http.StatusForbidden)
+                               return true
+                       }
+                       containerRequest["runtime_token"] = newtok.TokenV2()
+               } else {
+                       // Remote user. Container request will use the
+                       // current token, minus the trailing portion
+                       // (optional container uuid).
+                       sp := strings.Split(creds.Tokens[0], "/")
+                       if len(sp) >= 3 {
+                               containerRequest["runtime_token"] = strings.Join(sp[0:3], "/")
+                       } else {
+                               containerRequest["runtime_token"] = creds.Tokens[0]
+                       }
                }
-               containerRequest["runtime_token"] = newtok.TokenV2()
        }
 
        newbody, err := json.Marshal(request)