func (t *BackrunnerTest) NewRequest(method, handler, user, token, bucket, key string, body io.Reader) *http.Request { url := fmt.Sprintf("http://%s/%s", t.conf.Proxy.Address, handler) if bucket != "" { url += "/" + bucket } if key != "" { url += "/" + key } req, err := http.NewRequest(method, url, body) if err != nil { log.Fatalf("Could not create request: method: %s, url: '%s': %v\n", method, url, err) } if user != "" && token != "" { sign, err := auth.GenerateSignature(token, req.Method, req.URL, req.Header) if err != nil { log.Fatal("Could not generate signature: token: '%s', method: %s, url: %s, header: %v: %v\n", token, req.Method, req.URL.String(), req.Header, err) } req.Header.Add(auth.AuthHeaderStr, fmt.Sprintf("riftv1 %s:%s", user, sign)) } return req }
func (b *Bucket) check_auth(r *http.Request, required_flags uint64) (err error) { if len(b.Meta.Acl) == 0 { err = nil return } user, recv_auth, err := auth.GetAuthInfo(r) if err != nil { return } acl, ok := b.Meta.Acl[user] if !ok { err = errors.NewKeyError(r.URL.String(), http.StatusForbidden, fmt.Sprintf("auth: header: '%v': there is no user '%s' in ACL", r.Header[auth.AuthHeaderStr], user)) return } log.Printf("check-auth: url: %s, user: %s, token: %s, flags: %x, required: %x\n", r.URL.String(), acl.User, acl.Token, acl.Flags, required_flags) // only require required_flags check if its not @BucketAuthEmpty // @BucketAuthEmpty required_flags is set by reader, non BucketAuthEmpty required_flags are supposed to mean modifications if required_flags != BucketAuthEmpty { // there are no required flags in ACL if (acl.Flags & required_flags) == 0 { err = errors.NewKeyError(r.URL.String(), http.StatusForbidden, fmt.Sprintf("auth: header: '%v': user '%s' is not allowed to do action: acl-flags: 0x%x, required-flags: 0x%x", r.Header[auth.AuthHeaderStr], user, acl.Flags, required_flags)) return } } // skip authorization if special ACL flag is set if (acl.Flags & BucketAuthNoToken) != 0 { return } calc_auth, err := auth.GenerateSignature(acl.Token, r.Method, r.URL, r.Header) if err != nil { err = errors.NewKeyError(r.URL.String(), http.StatusForbidden, fmt.Sprintf("auth: header: '%v': hmac generation failed: %s", r.Header[auth.AuthHeaderStr], user)) return } if recv_auth != calc_auth { err = errors.NewKeyError(r.URL.String(), http.StatusForbidden, fmt.Sprintf("auth: header: '%v': user: %s, hmac mismatch: recv: '%s', calc: '%s'", r.Header[auth.AuthHeaderStr], user, recv_auth, calc_auth)) return } return }
func redirect_handler(w http.ResponseWriter, req *http.Request, string_keys ...string) Reply { if proxy.bctl.Conf.Proxy.RedirectPort == 0 || proxy.bctl.Conf.Proxy.RedirectPort >= 65536 { err := errors.NewKeyError(req.URL.String(), http.StatusServiceUnavailable, fmt.Sprintf("redirect is not allowed because of invalid redirect port %d", proxy.bctl.Conf.Proxy.RedirectPort)) return Reply{ err: err, status: errors.ErrorStatus(err), } } bname := string_keys[0] key := string_keys[1] reply, err := proxy.bctl.Lookup(bname, key, req) if err != nil { return Reply{ err: err, status: errors.ErrorStatus(err), } } srv := reply.Servers[rand.Intn(len(reply.Servers))] scheme := "http" if req.URL.Scheme != "" { scheme = req.URL.Scheme } if len(srv.Filename) == 0 { err := errors.NewKeyError(req.URL.String(), http.StatusServiceUnavailable, fmt.Sprintf("lookup returned invalid filename: %s", srv.Filename)) return Reply{ err: err, status: errors.ErrorStatus(err), } } filename := srv.Filename if len(proxy.bctl.Conf.Proxy.RedirectRoot) != 0 { if strings.HasPrefix(filename, proxy.bctl.Conf.Proxy.RedirectRoot) { filename = filename[len(proxy.bctl.Conf.Proxy.RedirectRoot):] } } slash := "/" if filename[0] == '/' { slash = "" } ranges, err := ranges.ParseRange(req.Header.Get("Range"), int64(srv.Size)) if err != nil { err = errors.NewKeyError(req.URL.String(), http.StatusBadRequest, fmt.Sprintf("upload: %v", err)) return Reply{ err: err, status: errors.ErrorStatus(err), } } offset, size, err := bucket.URIOffsetSize(req) if err != nil { err = errors.NewKeyError(req.URL.String(), http.StatusBadRequest, fmt.Sprintf("redirect: %v", err)) return Reply{ err: err, status: errors.ErrorStatus(err), } } if len(ranges) != 0 { offset = uint64(ranges[0].Start) size = uint64(ranges[0].Length) } if offset >= srv.Size { err = errors.NewKeyError(req.URL.String(), http.StatusBadRequest, fmt.Sprintf("redirect: offset is beyond size of the object: offset: %d, size: %d", offset, srv.Size)) return Reply{ err: err, status: errors.ErrorStatus(err), } } if size == 0 || offset+size >= srv.Size { size = srv.Size - offset } timestamp := time.Now().Unix() url_str := fmt.Sprintf("%s://%s:%d%s%s:%d:%d", scheme, srv.Server.HostString(), proxy.bctl.Conf.Proxy.RedirectPort, slash, filename, srv.Offset+offset, size) u, err := url.Parse(url_str) if err != nil { err := errors.NewKeyError(req.URL.String(), http.StatusServiceUnavailable, fmt.Sprintf("could not parse generated redirect url '%s'", url_str)) return Reply{ err: err, status: errors.ErrorStatus(err), } } req.URL = u w.Header().Set("X-Ell-Mtime", fmt.Sprintf("%d", srv.Info.Mtime.Unix())) w.Header().Set("X-Ell-Signtime", fmt.Sprintf("%d", timestamp)) w.Header().Set("X-Ell-Signature-Timeout", fmt.Sprintf("%d", proxy.bctl.Conf.Proxy.RedirectSignatureTimeout)) w.Header().Set("X-Ell-File-Offset", fmt.Sprintf("%d", srv.Offset)) w.Header().Set("X-Ell-Total-Size", fmt.Sprintf("%d", srv.Size)) w.Header().Set("X-Ell-File", filename) signature, err := auth.GenerateSignature(proxy.bctl.Conf.Proxy.RedirectToken, "GET", req.URL, w.Header()) if err != nil { err := errors.NewKeyError(req.URL.String(), http.StatusServiceUnavailable, fmt.Sprintf("could not generate signature for redirect url '%s': %v", url_str, err)) return Reply{ err: err, status: errors.ErrorStatus(err), } } w.Header().Set(auth.AuthHeaderStr, signature) http.Redirect(w, req, url_str, http.StatusFound) return GoodReply() }