func (s *server) Rm(ctx context.Context, req *pb.RmReq) (*pb.Void, error) { traceID, err := getTraceID(ctx) if err != nil { rus.Error(err) return &pb.Void{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "rm", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := authlib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Void{}, unauthenticatedError } log.Infof("%s", idt) p := path.Clean(req.Path) log.Infof("path is %s", p) if !isUnderHome(p, idt) { log.Error(permissionDenied) return &pb.Void{}, permissionDenied } if p == getHome(idt) { return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot remove home directory") } pp := s.getPhysicalPath(p) log.Infof("physical path is %s", pp) err = os.RemoveAll(pp) if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("removed %s", pp) resource, err := s.grpcPool.Get("") if err != nil { log.Error(err) return &pb.Void{}, err } defer resource.Release() handle, err := resource.Handle() if err != nil { log.Error(err) return &pb.Void{}, err } con := handle.(*grpc.ClientConn) log.Infof("created connection to %s", s.p.prop) client := proppb.NewPropClient(con) in := &proppb.RmReq{} in.Path = p in.AccessToken = req.AccessToken _, err = client.Rm(ctx, in) if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("paths with prefix %s removed from prop", p) return &pb.Void{}, nil }
func (s *server) Home(ctx context.Context, req *pb.HomeReq) (*pb.Void, error) { traceID, err := getTraceID(ctx) if err != nil { rus.Error(err) return &pb.Void{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "home", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := authlib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Void{}, unauthenticatedError } log.Infof("%s", idt) home := getHome(idt) log.Infof("user home is %s", home) pp := s.getPhysicalPath(home) log.Infof("user physical home is %s", pp) resource, err := s.grpcPool.Get("") if err != nil { log.Error(err) return &pb.Void{}, err } defer resource.Release() handle, err := resource.Handle() if err != nil { log.Error(err) return &pb.Void{}, err } con := handle.(*grpc.ClientConn) log.Infof("created connection to %s", s.p.prop) client := proppb.NewPropClient(con) _, err = os.Stat(pp) // Create home dir if not exists if os.IsNotExist(err) { log.Infof("user physical home %s does not exist", pp) err = os.MkdirAll(pp, dirPerm) if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("user physical home created at %s", pp) // trigger file id creation on xattr // if it is not set _, err = s.getMeta(pp) if err != nil { return &pb.Void{}, err } in := &proppb.GetReq{} in.Path = home in.AccessToken = req.AccessToken in.ForceCreation = true _, err = client.Get(ctx, in) if err != nil { return &pb.Void{}, nil } log.Info("home saved to %s", s.p.prop) return &pb.Void{}, nil } if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("user physical home at %s already created") // trigger file id creation on xattr // if it is not set _, err = s.getMeta(pp) if err != nil { return &pb.Void{}, err } in := &proppb.GetReq{} in.Path = home in.AccessToken = req.AccessToken in.ForceCreation = true _, err = client.Get(ctx, in) if err != nil { return &pb.Void{}, nil } return &pb.Void{}, nil }
func (s *server) Stat(ctx context.Context, req *pb.StatReq) (*pb.Metadata, error) { traceID, err := getTraceID(ctx) if err != nil { rus.Error(err) return &pb.Metadata{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "stat", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := authlib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Metadata{}, unauthenticatedError } log.Infof("%s", idt) p := path.Clean(req.Path) log.Infof("path is %s", p) // The hierarchy is /local/users/d/demo // All paths in the hierarchy above the user home directory must be // accessible for all logged in users if isCommonDomain(p) { } else { // it must be under /local/users/{letter} if isUnderOtherHome(p, idt) { if req.Children == true { // TODO(labkode) Sharing return &pb.Metadata{}, permissionDenied } } else { // asset is under logged in user home directory if !isUnderHome(p, idt) { log.WithField("criticial", "").Errorf("path %s has not been handled correclty or fake path", p) return &pb.Metadata{}, permissionDenied } } } /* if !isUnderHome(p, idt) { // constrained to /local/users/d/demo/... log.Error(permissionDenied) return &pb.Metadata{}, permissionDenied } */ pp := s.getPhysicalPath(p) log.Infof("physical path is %s", pp) parentMeta, err := s.getMeta(pp) if err != nil { log.Error(err) return &pb.Metadata{}, err } log.Infof("stated parent %s", pp) resource, err := s.grpcPool.Get("") if err != nil { log.Error(err) return &pb.Metadata{}, err } defer resource.Release() handle, err := resource.Handle() if err != nil { log.Error(err) return &pb.Metadata{}, err } con := handle.(*grpc.ClientConn) log.Infof("created connection to %s", s.p.prop) client := proppb.NewPropClient(con) in := &proppb.GetReq{} in.Path = p in.AccessToken = req.AccessToken in.ForceCreation = true rec, err := client.Get(ctx, in) if err != nil { log.Error(err) return &pb.Metadata{}, err } parentMeta.Etag = rec.Etag parentMeta.Modified = rec.Modified if !parentMeta.IsContainer || req.Children == false { return parentMeta, nil } dir, err := os.Open(pp) if err != nil { log.Error(err) return &pb.Metadata{}, err } log.Infof("opened dir %s", pp) defer dir.Close() names, err := dir.Readdirnames(0) if err != nil { log.Error(err) return &pb.Metadata{}, err } log.Infof("dir %s has %d entries", pp, len(names)) for _, n := range names { cp := path.Join(parentMeta.Path, path.Clean(n)) cpp := s.getPhysicalPath(cp) m, err := s.getMeta(cpp) if err != nil { log.Error(err) } else { in := &proppb.GetReq{} in.Path = cp in.AccessToken = req.AccessToken in.ForceCreation = true rec, err := client.Get(ctx, in) if err != nil { log.Errorf("path %s has not been added because %s", p, err.Error()) } else { m.Etag = rec.Etag m.Modified = rec.Modified parentMeta.Children = append(parentMeta.Children, m) log.Infof("added %s to parent", m.Path) } } } log.Infof("added %d entries to parent", len(parentMeta.Children)) return parentMeta, nil }
func (s *server) Mv(ctx context.Context, req *pb.MvReq) (*pb.Void, error) { traceID, err := getTraceID(ctx) if err != nil { rus.Error(err) return &pb.Void{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "mv", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := authlib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Void{}, unauthenticatedError } log.Infof("%s", idt) src := path.Clean(req.Src) dst := path.Clean(req.Dst) log.Infof("src is %s", src) log.Info("dst is %s", dst) if !isUnderHome(src, idt) { log.Error(permissionDenied) return &pb.Void{}, permissionDenied } if !isUnderHome(dst, idt) { log.Error(permissionDenied) return &pb.Void{}, permissionDenied } if src == getHome(idt) || dst == getHome(idt) { return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot rename from/to home directory") } psrc := s.getPhysicalPath(src) pdst := s.getPhysicalPath(dst) log.Infof("physical src is %s", psrc) log.Infof("physical dst is %s", pdst) err = os.Rename(psrc, pdst) if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("renamed from %s to %s", psrc, pdst) resource, err := s.grpcPool.Get("") if err != nil { log.Error(err) return &pb.Void{}, err } defer resource.Release() handle, err := resource.Handle() if err != nil { log.Error(err) return &pb.Void{}, err } con := handle.(*grpc.ClientConn) log.Infof("created connection to %s", s.p.prop) client := proppb.NewPropClient(con) in := &proppb.MvReq{} in.Src = src in.Dst = dst in.AccessToken = req.AccessToken _, err = client.Mv(ctx, in) if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("renamed %s to %s in prop", src, dst) return &pb.Void{}, nil }
func (s *server) Get(ctx context.Context, req *pb.GetReq) (*pb.Record, error) { traceID, err := getGRPCTraceID(ctx) if err != nil { rus.Error(err) return &pb.Record{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newGRPCTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "get", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Record{}, unauthenticatedError } log.Infof("%s", idt) p := path.Clean(req.Path) log.Infof("path is %s", p) var rec *record rec, err = s.getByPath(p) if err != nil { log.Error(err) if err != gorm.RecordNotFound { return &pb.Record{}, err } if !req.ForceCreation { return &pb.Record{}, err } if req.ForceCreation { in := &pb.PutReq{} in.AccessToken = req.AccessToken in.Path = req.Path _, e := s.Put(ctx, in) if e != nil { return &pb.Record{}, err } rec, err = s.getByPath(p) if err != nil { return &pb.Record{}, nil } } } r := &pb.Record{} r.Id = rec.ID r.Path = rec.Path r.Etag = rec.ETag r.Modified = rec.MTime r.Checksum = rec.Checksum return r, nil }
func (s *server) getIdentityFromReq(r *http.Request) (*authlib.Identity, error) { return authlib.ParseToken(s.getTokenFromReq(r), s.p.sharedSecret) }
func (s *server) Put(ctx context.Context, req *pb.PutReq) (*pb.Void, error) { traceID, err := getGRPCTraceID(ctx) if err != nil { rus.Error(err) return &pb.Void{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newGRPCTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "put", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Void{}, unauthenticatedError } log.Infof("%s", idt) p := path.Clean(req.Path) log.Infof("path is %s", p) var id string rawEtag, err := uuid.NewV4() if err != nil { log.Error(err) return &pb.Void{}, err } etag := rawEtag.String() var mtime = uint32(time.Now().Unix()) r, err := s.getByPath(p) if err != nil { log.Error(err) if err == gorm.RecordNotFound { rawEtag, err := uuid.NewV4() if err != nil { log.Error(err) return &pb.Void{}, err } id = rawEtag.String() } else { return &pb.Void{}, err } } else { id = r.ID } log.Infof("new record will have id=%s path=%s checksum=%s etag=%s mtime=%d", id, p, req.Checksum, etag, mtime) err = s.insert(id, p, req.Checksum, etag, mtime) if err != nil { log.Error(err) return &pb.Void{}, err } log.Infof("new record saved to db") err = s.propagateChanges(ctx, p, etag, mtime, "") if err != nil { log.Error(err) } log.Infof("propagated changes till ancestor %s", "") return &pb.Void{}, nil }
func (s *server) Rm(ctx context.Context, req *pb.RmReq) (*pb.Void, error) { traceID, err := getGRPCTraceID(ctx) if err != nil { rus.Error(err) return &pb.Void{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newGRPCTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "rm", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Void{}, unauthenticatedError } log.Infof("%s", idt) p := path.Clean(req.Path) log.Infof("path is %s", p) ts := time.Now().Unix() err = s.db.Where("(path LIKE ? OR path=? ) AND m_time < ?", p+"/%", p, ts).Delete(record{}).Error if err != nil { log.Error(err) return &pb.Void{}, err } etag, err := uuid.NewV4() if err != nil { return &pb.Void{}, err } err = s.propagateChanges(ctx, p, etag.String(), uint32(ts), "") if err != nil { log.Error(err) } log.Infof("propagated changes till %s", "") return &pb.Void{}, nil }
func (s *server) Mv(ctx context.Context, req *pb.MvReq) (*pb.Void, error) { traceID, err := getGRPCTraceID(ctx) if err != nil { rus.Error(err) return &pb.Void{}, err } if err != nil { rus.Error(err) return &pb.Void{}, err } log := rus.WithField("trace", traceID).WithField("svc", serviceID) ctx = newGRPCTraceContext(ctx, traceID) log.Info("request started") // Time request reqStart := time.Now() defer func() { // Compute request duration reqDur := time.Since(reqStart) // Log access info log.WithFields(rus.Fields{ "method": "mv", "type": "grpcaccess", "duration": reqDur.Seconds(), }).Info("request finished") }() idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret) if err != nil { log.Error(err) return &pb.Void{}, unauthenticatedError } log.Infof("%s", idt) src := path.Clean(req.Src) dst := path.Clean(req.Dst) log.Infof("src path is %s", src) log.Infof("dst path is %s", dst) recs, err := s.getRecordsWithPathPrefix(src) if err != nil { log.Error(err) return &pb.Void{}, nil } tx := s.db.Begin() for _, rec := range recs { newPath := path.Join(dst, path.Clean(strings.TrimPrefix(rec.Path, src))) log.Infof("src path %s will be renamed to %s", rec.Path, newPath) err = s.db.Model(record{}).Where("id=?", rec.ID).Updates(record{Path: newPath}).Error if err != nil { log.Error(err) tx.Rollback() return &pb.Void{}, err } } tx.Commit() log.Infof("renamed %d entries", len(recs)) etag, err := uuid.NewV4() if err != nil { log.Error(err) return &pb.Void{}, err } mtime := uint32(time.Now().Unix()) err = s.propagateChanges(ctx, dst, etag.String(), mtime, "") if err != nil { log.Error(err) } log.Infof("propagated changes till %s", "") return &pb.Void{}, nil }
// authHandler validates the access token sent in the Cookie or if not present sends // a the Basic Auth params to the auth service to authenticate the request. func (s *server) authHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, next func(ctx context.Context, w http.ResponseWriter, r *http.Request)) { logger := MustFromLogContext(ctx) idt, err := getIdentityFromReq(r, s.p.sharedSecret) if err == nil { logger.Info(idt) ctx = authlib.NewContext(ctx, idt) ctx = authlib.NewTokenContext(ctx, getTokenFromReq(r)) next(ctx, w, r) } else { // Authenticate against auth service // if basic credentials are found user, pass, ok := r.BasicAuth() if !ok { logger.Error("no credentials found in request") w.Header().Set("WWW-Authenticate", "Basic Realm='ClawIO credentials'") http.Error(w, "", http.StatusUnauthorized) return } con, err := getConnection(s.p.authServer) if err != nil { logger.Error(err) http.Error(w, "", http.StatusInternalServerError) return } defer con.Close() logger.Infof("connected to %s", s.p.authServer) client := authpb.NewAuthClient(con) in := &authpb.AuthRequest{} in.Username = user in.Password = pass res, err := client.Authenticate(ctx, in) if err != nil { logger.Error(err) if grpc.Code(err) == codes.Unauthenticated { w.Header().Set("WWW-Authenticate", "Basic Realm='ClawIO credentials'") http.Error(w, "", http.StatusUnauthorized) return } http.Error(w, "", http.StatusInternalServerError) return } logger.Infof("basic auth successful for username %s", user) idt, err := authlib.ParseToken(res.Token, s.p.sharedSecret) if err != nil { logger.Error(err) http.Error(w, "", http.StatusInternalServerError) return } logger.Info(idt) cookie := &http.Cookie{} cookie.Name = "OC_SessionPassphrase" cookie.Value = res.Token http.SetCookie(w, cookie) // token added to the request because when proxied // no all servers will handle basic auth, but all will handle // the access token r.Header.Set("Authorization", "Bearer "+res.Token) ctx = authlib.NewContext(ctx, idt) ctx = authlib.NewTokenContext(ctx, res.Token) next(ctx, w, r) } }
func getIdentityFromReq(r *http.Request, secret string) (*authlib.Identity, error) { return authlib.ParseToken(getTokenFromReq(r), secret) }