diff --git a/authorization/plugin/allow_types.go b/authorization/plugin/allow_types.go index 3cd1e2e..a01f969 100644 --- a/authorization/plugin/allow_types.go +++ b/authorization/plugin/allow_types.go @@ -26,6 +26,8 @@ func NewAllowTypesPlugin(args []string) (*AllowTypesPlugin, error) { reqType = authorization.RequestType_REQUEST_TYPE_GET_METADATA case "list": reqType = authorization.RequestType_REQUEST_TYPE_LIST + case "delete": + reqType = authorization.RequestType_REQUEST_TYPE_DELETE default: return nil, status.Error(codes.InvalidArgument, "unknown request type: "+arg) } diff --git a/authorization/v1/authorization.pb.go b/authorization/v1/authorization.pb.go index 01e9293..878870a 100644 --- a/authorization/v1/authorization.pb.go +++ b/authorization/v1/authorization.pb.go @@ -28,6 +28,7 @@ const ( RequestType_REQUEST_TYPE_UPLOAD RequestType = 2 RequestType_REQUEST_TYPE_GET_METADATA RequestType = 3 RequestType_REQUEST_TYPE_LIST RequestType = 4 + RequestType_REQUEST_TYPE_DELETE RequestType = 5 ) // Enum value maps for RequestType. @@ -38,6 +39,7 @@ var ( 2: "REQUEST_TYPE_UPLOAD", 3: "REQUEST_TYPE_GET_METADATA", 4: "REQUEST_TYPE_LIST", + 5: "REQUEST_TYPE_DELETE", } RequestType_value = map[string]int32{ "REQUEST_TYPE_UNSPECIFIED": 0, @@ -45,6 +47,7 @@ var ( "REQUEST_TYPE_UPLOAD": 2, "REQUEST_TYPE_GET_METADATA": 3, "REQUEST_TYPE_LIST": 4, + "REQUEST_TYPE_DELETE": 5, } ) @@ -261,7 +264,7 @@ var file_authorization_v1_authorization_proto_rawDesc = []byte{ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x13, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x95, 0x01, 0x0a, 0x0b, 0x52, + 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0xae, 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x51, 0x55, @@ -271,17 +274,19 @@ var file_authorization_v1_authorization_proto_rawDesc = []byte{ 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x45, 0x54, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x49, 0x53, 0x54, - 0x10, 0x04, 0x32, 0x6c, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, - 0x68, 0x65, 0x6c, 0x65, 0x65, 0x65, 0x6f, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x62, 0x75, 0x74, - 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x32, 0x6c, 0x0a, 0x14, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x12, 0x22, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x68, 0x65, 0x6c, 0x65, 0x65, 0x65, 0x6f, + 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x62, 0x75, 0x74, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/mocks/provider.go b/mocks/provider.go index fdb7b10..c33769a 100644 --- a/mocks/provider.go +++ b/mocks/provider.go @@ -87,3 +87,12 @@ func (p *Provider) ListObjects(ctx context.Context, prefix string) (provider.Lis return called.Get(0).(provider.ListObjectsResponse), called.Error(1) } + +func (p *Provider) DeleteObject(ctx context.Context, key string) error { + called := p.Called(ctx, key) + if called.Get(0) == nil { + return nil + } + + return called.Error(0) +} diff --git a/proto/authorization/v1/authorization.proto b/proto/authorization/v1/authorization.proto index 0d20c26..2b0a310 100644 --- a/proto/authorization/v1/authorization.proto +++ b/proto/authorization/v1/authorization.proto @@ -13,6 +13,7 @@ enum RequestType { REQUEST_TYPE_UPLOAD = 2; REQUEST_TYPE_GET_METADATA = 3; REQUEST_TYPE_LIST = 4; + REQUEST_TYPE_DELETE = 5; } message AuthorizeRequest { diff --git a/provider/gocloud.go b/provider/gocloud.go index 8567e86..fb38913 100644 --- a/provider/gocloud.go +++ b/provider/gocloud.go @@ -126,3 +126,15 @@ func (n *GocloudProvider) ListObjects(ctx context.Context, prefix string) (ListO Keys: files, }, nil } + +func (n *GocloudProvider) DeleteObject(ctx context.Context, key string) error { + if err := n.bucket.Delete(ctx, key); err != nil { + if gcerrors.Code(err) == gcerrors.NotFound { + return ErrNotFound + } + + return err + } + + return nil +} diff --git a/provider/log.go b/provider/log.go index e336926..1274cf2 100644 --- a/provider/log.go +++ b/provider/log.go @@ -60,3 +60,8 @@ func (n *LogProvider) ListObjects(ctx context.Context, prefix string) (ListObjec log.Printf("ListObjects %s\n", prefix) return ListObjectsResponse{}, nil } + +func (n *LogProvider) DeleteObject(ctx context.Context, key string) error { + log.Printf("DeleteObject %s\n", key) + return nil +} diff --git a/provider/provider.go b/provider/provider.go index 2f8b9c6..f92374f 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -54,6 +54,7 @@ type Provider interface { PutObject(ctx context.Context, key string, data io.Reader, opts PutOptions) error GetTags(ctx context.Context, key string) (map[string]string, error) ListObjects(ctx context.Context, prefix string) (ListObjectsResponse, error) + DeleteObject(ctx context.Context, key string) error } type GetOptions struct { diff --git a/provider/s3.go b/provider/s3.go index 2c519cf..8196618 100644 --- a/provider/s3.go +++ b/provider/s3.go @@ -232,3 +232,16 @@ func (s *S3Provider) ListObjects(ctx context.Context, prefix string) (ListObject Keys: files, }, nil } + +func (s *S3Provider) DeleteObject(ctx context.Context, key string) error { + _, err := s.client.DeleteObject(ctx, &s3.DeleteObjectInput{ + Bucket: &s.bucketName, + Key: &key, + }) + if err != nil { + // S3 seems to return a 200 OK even if the object does not exist so no need to check for that. + return err + } + + return nil +} diff --git a/provider/void.go b/provider/void.go index 15a5a0e..dbd00d1 100644 --- a/provider/void.go +++ b/provider/void.go @@ -45,3 +45,7 @@ func (n *VoidProvider) GetTags(ctx context.Context, key string) (map[string]stri func (n *VoidProvider) ListObjects(ctx context.Context, prefix string) (ListObjectsResponse, error) { return ListObjectsResponse{}, nil } + +func (n *VoidProvider) DeleteObject(ctx context.Context, key string) error { + return nil +} diff --git a/server/handlers.go b/server/handlers.go index 44fea7d..42da0f2 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -28,6 +28,8 @@ func (s *Server) handleFile(w http.ResponseWriter, r *http.Request) { reqType = authorization.RequestType_REQUEST_TYPE_DOWNLOAD case http.MethodPut, http.MethodPost: reqType = authorization.RequestType_REQUEST_TYPE_UPLOAD + case http.MethodDelete: + reqType = authorization.RequestType_REQUEST_TYPE_DELETE default: http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) return @@ -84,8 +86,28 @@ func (s *Server) handleFile(w http.ResponseWriter, r *http.Request) { return } - if err := s.handleUpload(r, p, key); err != nil { - lerr.ToHTTP(w, err) + if reqType == authorization.RequestType_REQUEST_TYPE_UPLOAD { + if err := s.handleUpload(r, p, key); err != nil { + lerr.ToHTTP(w, err) + return + } + + w.WriteHeader(http.StatusOK) + return + } + + if reqType == authorization.RequestType_REQUEST_TYPE_DELETE { + if err := p.DeleteObject(r.Context(), key); err != nil { + if errors.Is(err, provider.ErrNotFound) { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) return } @@ -177,14 +199,14 @@ func getDataSource(r *http.Request, allowRawBody bool) (io.ReadCloser, error) { if err := r.ParseMultipartForm(10 << 20); err != nil { log.Println("error parsing multipart form:", err) - return nil, lerr.Wrap(err, http.StatusBadRequest, "error parsing multipart form:") + return nil, lerr.Wrap(err, http.StatusBadRequest, "error parsing multipart form") } file, _, err := r.FormFile("file") if err != nil { log.Println("error getting file from form:", err) - return nil, lerr.Wrap(err, http.StatusBadRequest, "error getting file from form:") + return nil, lerr.Wrap(err, http.StatusBadRequest, "error getting file from form") } data = file } else { @@ -257,11 +279,7 @@ func (s *Server) authorizeRequest(ctx context.Context, reqType authorization.Req } if err := authPlugin.Authorize(ctx, req); err != nil { - s, ok := status.FromError(err) - if !ok { - return lerr.Newf(http.StatusInternalServerError, "plugin error not a grpc status! error=%s", err.Error()) - } - + s := status.Convert(err) if s.Code() == codes.Unauthenticated { return lerr.Newf(http.StatusUnauthorized, "Unauthenticated: %s", s.Message()) } diff --git a/server/middlewares.go b/server/middlewares.go index 0f379f9..7c06f97 100644 --- a/server/middlewares.go +++ b/server/middlewares.go @@ -26,6 +26,8 @@ func InternalErrorRedacter(next http.Handler) http.Handler { return } + log.Printf("%s %s %d", r.Method, r.URL.Path, respCatcher.Code) + copyHeaders(w.Header(), respCatcher.Header()) w.WriteHeader(respCatcher.Code) _, _ = w.Write(respCatcher.Body.Bytes())