Exemple #1
0
func (h *shareHandler) serveHTTP(rw http.ResponseWriter, req *http.Request) error {
	var err error
	pathSuffix := httputil.PathSuffix(req)
	if len(pathSuffix) == 0 {
		// This happens during testing because we don't go through PrefixHandler
		pathSuffix = strings.TrimLeft(req.URL.Path, "/")
	}
	pathParts := strings.SplitN(pathSuffix, "/", 2)
	blobRef, ok := blob.Parse(pathParts[0])
	if !ok {
		err = &shareError{code: invalidURL, response: badRequest,
			message: fmt.Sprintf("Malformed share pathSuffix: %s", pathSuffix)}
	} else {
		err = handleGetViaSharing(rw, req, blobRef, h.fetcher)
	}
	if se, ok := err.(*shareError); ok {
		switch se.response {
		case badRequest:
			httputil.BadRequestError(rw, err.Error())
		case unauthorizedRequest:
			log.Print(err)
			auth.SendUnauthorized(rw, req)
		}
	}
	return err
}
Exemple #2
0
func (a *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == a.masterqueryURLPath {
		a.handleMasterQuery(w, r)
		return
	}
	if a.configURLPath != "" && r.URL.Path == a.configURLPath {
		if a.auth.AllowedAccess(r)&auth.OpGet == auth.OpGet {
			camhttputil.ReturnJSON(w, a.appConfig)
		} else {
			auth.SendUnauthorized(w, r)
		}
		return
	}
	trimmedPath := strings.TrimPrefix(r.URL.Path, a.prefix)
	if strings.HasPrefix(trimmedPath, "/search") {
		a.handleSearch(w, r)
		return
	}

	if a.proxy == nil {
		http.Error(w, "no proxy for the app", 500)
		return
	}
	a.proxy.ServeHTTP(w, r)
}
Exemple #3
0
func (a *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if camhttputil.PathSuffix(req) == "config.json" {
		if a.auth.AllowedAccess(req)&auth.OpGet == auth.OpGet {
			camhttputil.ReturnJSON(rw, a.appConfig)
		} else {
			auth.SendUnauthorized(rw, req)
		}
		return
	}
	if a.proxy == nil {
		http.Error(rw, "no proxy for the app", 500)
		return
	}
	a.proxy.ServeHTTP(rw, req)
}
Exemple #4
0
// handleMasterQuery allows an app to register the master query that defines the
// domain limiting all subsequent search queries.
func (a *Handler) handleMasterQuery(w http.ResponseWriter, r *http.Request) {
	if !(a.auth.AllowedAccess(r)&auth.OpAll == auth.OpAll) {
		auth.SendUnauthorized(w, r)
		return
	}
	if r.Method != http.MethodPost {
		http.Error(w, "not a POST", http.StatusMethodNotAllowed)
		return
	}
	if a.sh == nil {
		http.Error(w, "app proxy has no search handler", 500)
		return
	}
	if refresh, _ := strconv.ParseBool(r.FormValue("refresh")); refresh {
		if err := a.refreshDomainBlobs(); err != nil {
			if err == errRefreshSuppress {
				http.Error(w, "too many refresh requests", http.StatusTooManyRequests)
			} else {
				http.Error(w, fmt.Sprintf("%v", err), 500)
			}
			return
		}
		w.Write([]byte("OK"))
		return
	}
	sq := new(search.SearchQuery)
	if err := sq.FromHTTP(r); err != nil {
		http.Error(w, fmt.Sprintf("error reading master query: %v", err), 500)
		return
	}
	var masterQuery search.SearchQuery = *(sq)
	des := *(masterQuery.Describe)
	masterQuery.Describe = &des
	sr, err := a.sh.Query(sq)
	if err != nil {
		http.Error(w, fmt.Sprintf("error running master query: %v", err), 500)
		return
	}
	a.masterQueryMu.Lock()
	defer a.masterQueryMu.Unlock()
	a.masterQuery = &masterQuery
	a.domainBlobs = make(map[blob.Ref]bool, len(sr.Describe.Meta))
	for _, v := range sr.Describe.Meta {
		a.domainBlobs[v.BlobRef] = true
	}
	a.domainBlobsRefresh = time.Now()
	w.Write([]byte("OK"))
}
Exemple #5
0
func (h *Handler) ServeHTTP(conn http.ResponseWriter, req *http.Request) {
	blobRef := blobFromUrlPath(req.URL.Path)
	if blobRef == nil {
		http.Error(conn, "Malformed GET URL.", 400)
		return
	}

	switch {
	case h.AllowGlobalAccess || auth.Allowed(req, auth.OpGet):
		serveBlobRef(conn, req, blobRef, h.Fetcher)
	case auth.TriedAuthorization(req):
		log.Printf("Attempted authorization failed on %s", req.URL)
		auth.SendUnauthorized(conn, req)
	default:
		handleGetViaSharing(conn, req, blobRef, h.Fetcher)
	}
}
Exemple #6
0
func (rh *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if wantsDiscovery(r) {
		if auth.Allowed(r, auth.OpDiscovery) {
			rh.serveDiscovery(w, r)
			return
		}
		if !rh.Stealth {
			auth.SendUnauthorized(w, r)
		}
		return
	}

	if rh.Stealth {
		return
	}
	if r.RequestURI == "/" && rh.ui != nil {
		http.Redirect(w, r, "/ui/", http.StatusMovedPermanently)
		return
	}
	if r.URL.Path == "/favicon.ico" {
		ServeStaticFile(w, r, Files, "favicon.ico")
		return
	}
	f := func(p string, a ...interface{}) {
		fmt.Fprintf(w, p, a...)
	}
	f("<html><body><p>This is camlistored (%s), a "+
		"<a href='http://camlistore.org'>Camlistore</a> server.</p>", buildinfo.Version())
	if rh.ui != nil {
		f("<p>To manage your content, access the <a href='%s'>%s</a>.</p>", rh.ui.prefix, rh.ui.prefix)
	}
	if rh.statusRoot != "" {
		f("<p>To view status, see <a href='%s'>%s</a>.</p>", rh.statusRoot, rh.statusRoot)
	}
	if rh.helpRoot != "" {
		f("<p>To view more information on accessing the server, see <a href='%s'>%s</a>.</p>", rh.helpRoot, rh.helpRoot)
	}
	fmt.Fprintf(w, "</body></html>")
}
Exemple #7
0
// Unauthenticated user.  Be paranoid.
func handleGetViaSharing(conn http.ResponseWriter, req *http.Request,
	blobRef *blobref.BlobRef, fetcher blobref.StreamingFetcher) {

	if w, ok := fetcher.(blobserver.ContextWrapper); ok {
		fetcher = w.WrapContext(req)
	}

	viaPathOkay := false
	startTime := time.Now()
	defer func() {
		if !viaPathOkay {
			// Insert a delay, to hide timing attacks probing
			// for the existence of blobs.
			sleep := fetchFailureDelayNs - (time.Now().Sub(startTime))
			if sleep > 0 {
				time.Sleep(sleep)
			}
		}
	}()
	viaBlobs := make([]*blobref.BlobRef, 0)
	if via := req.FormValue("via"); via != "" {
		for _, vs := range strings.Split(via, ",") {
			if br := blobref.Parse(vs); br == nil {
				httputil.BadRequestError(conn, "Malformed blobref in via param")
				return
			} else {
				viaBlobs = append(viaBlobs, br)
			}
		}
	}

	fetchChain := make([]*blobref.BlobRef, 0)
	fetchChain = append(fetchChain, viaBlobs...)
	fetchChain = append(fetchChain, blobRef)
	for i, br := range fetchChain {
		switch i {
		case 0:
			file, size, err := fetcher.FetchStreaming(br)
			if err != nil {
				log.Printf("Fetch chain 0 of %s failed: %v", br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			defer file.Close()
			if size > maxJSONSize {
				log.Printf("Fetch chain 0 of %s too large", br.String())
				auth.SendUnauthorized(conn, req)
				return
			}
			jd := json.NewDecoder(file)
			m := make(map[string]interface{})
			if err := jd.Decode(&m); err != nil {
				log.Printf("Fetch chain 0 of %s wasn't JSON: %v", br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			if m["camliType"].(string) != "share" {
				log.Printf("Fetch chain 0 of %s wasn't a share", br.String())
				auth.SendUnauthorized(conn, req)
				return
			}
			if len(fetchChain) > 1 && fetchChain[1].String() != m["target"].(string) {
				log.Printf("Fetch chain 0->1 (%s -> %q) unauthorized, expected hop to %q",
					br.String(), fetchChain[1].String(), m["target"])
				auth.SendUnauthorized(conn, req)
				return
			}
		case len(fetchChain) - 1:
			// Last one is fine (as long as its path up to here has been proven, and it's
			// not the first thing in the chain)
			continue
		default:
			file, _, err := fetcher.FetchStreaming(br)
			if err != nil {
				log.Printf("Fetch chain %d of %s failed: %v", i, br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			defer file.Close()
			lr := io.LimitReader(file, maxJSONSize)
			slurpBytes, err := ioutil.ReadAll(lr)
			if err != nil {
				log.Printf("Fetch chain %d of %s failed in slurp: %v", i, br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			saught := fetchChain[i+1].String()
			if bytes.IndexAny(slurpBytes, saught) == -1 {
				log.Printf("Fetch chain %d of %s failed; no reference to %s",
					i, br.String(), saught)
				auth.SendUnauthorized(conn, req)
				return
			}
		}
	}

	viaPathOkay = true

	serveBlobRef(conn, req, blobRef, fetcher)

}
Exemple #8
0
// Unauthenticated user.  Be paranoid.
func handleGetViaSharing(conn http.ResponseWriter, req *http.Request,
	blobRef blob.Ref, fetcher blob.StreamingFetcher) {
	if req.Method != "GET" && req.Method != "HEAD" {
		httputil.BadRequestError(conn, "Invalid method")
		return
	}

	viaPathOkay := false
	startTime := time.Now()
	defer func() {
		if !viaPathOkay {
			// Insert a delay, to hide timing attacks probing
			// for the existence of blobs.
			sleep := fetchFailureDelay - (time.Now().Sub(startTime))
			time.Sleep(sleep)
		}
	}()
	viaBlobs := make([]blob.Ref, 0)
	if via := req.FormValue("via"); via != "" {
		for _, vs := range strings.Split(via, ",") {
			if br, ok := blob.Parse(vs); ok {
				viaBlobs = append(viaBlobs, br)
			} else {
				httputil.BadRequestError(conn, "Malformed blobref in via param")
				return
			}
		}
	}

	fetchChain := make([]blob.Ref, 0)
	fetchChain = append(fetchChain, viaBlobs...)
	fetchChain = append(fetchChain, blobRef)
	for i, br := range fetchChain {
		switch i {
		case 0:
			file, size, err := fetcher.FetchStreaming(br)
			if err != nil {
				log.Printf("Fetch chain 0 of %s failed: %v", br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			defer file.Close()
			if size > schema.MaxSchemaBlobSize {
				log.Printf("Fetch chain 0 of %s too large", br.String())
				auth.SendUnauthorized(conn, req)
				return
			}
			blob, err := schema.BlobFromReader(br, file)
			if err != nil {
				log.Printf("Can't create a blob from %v: %v", br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			share, ok := blob.AsShare()
			if !ok {
				log.Printf("Fetch chain 0 of %s wasn't a valid Share", br.String())
				auth.SendUnauthorized(conn, req)
				return
			}
			if len(fetchChain) > 1 && fetchChain[1].String() != share.Target().String() {
				log.Printf("Fetch chain 0->1 (%s -> %q) unauthorized, expected hop to %q",
					br.String(), fetchChain[1].String(), share.Target().String())
				auth.SendUnauthorized(conn, req)
				return
			}
		case len(fetchChain) - 1:
			// Last one is fine (as long as its path up to here has been proven, and it's
			// not the first thing in the chain)
			continue
		default:
			file, _, err := fetcher.FetchStreaming(br)
			if err != nil {
				log.Printf("Fetch chain %d of %s failed: %v", i, br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			defer file.Close()
			lr := io.LimitReader(file, schema.MaxSchemaBlobSize)
			slurpBytes, err := ioutil.ReadAll(lr)
			if err != nil {
				log.Printf("Fetch chain %d of %s failed in slurp: %v", i, br.String(), err)
				auth.SendUnauthorized(conn, req)
				return
			}
			saught := fetchChain[i+1].String()
			if bytes.IndexAny(slurpBytes, saught) == -1 {
				log.Printf("Fetch chain %d of %s failed; no reference to %s",
					i, br.String(), saught)
				auth.SendUnauthorized(conn, req)
				return
			}
		}
	}

	viaPathOkay = true

	gethandler.ServeBlobRef(conn, req, blobRef, fetcher)
}