@@ -372,6 +372,11 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
372372 return
373373 }
374374
375+ if request .Method != "PUT" {
376+ http .Error (writer , "Method Not Allowed" , http .StatusMethodNotAllowed )
377+ return
378+ }
379+
375380 vars := mux .Vars (request )
376381 id := & glue.EntityId {
377382 Name : strings .TrimSpace (vars ["name" ]),
@@ -428,6 +433,50 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
428433 http .Error (writer , "" , http .StatusOK )
429434 })
430435
436+ // DELETE /entity/{name}/{id}/grant/{type}/{user}
437+ r .HandleFunc ("/entity/{name}/{id}/grant/{type}/{user}" , func (writer http.ResponseWriter , request * http.Request ) {
438+ if stop := handleCors (writer , request ); stop {
439+ return
440+ }
441+
442+ if request .Method != "DELETE" {
443+ http .Error (writer , "Method Not Allowed" , http .StatusMethodNotAllowed )
444+ return
445+ }
446+
447+ vars := mux .Vars (request )
448+ id := & glue.EntityId {
449+ Name : strings .TrimSpace (vars ["name" ]),
450+ Id : strings .TrimSpace (vars ["id" ]),
451+ }
452+ stateId := id .ToStateId ()
453+
454+ r , err := rm .DiscoverResource (ctx , stateId , logger , true )
455+ if err != nil {
456+ logger .Error ("Failed to discover resource" , zap .Error (err ))
457+ http .Error (writer , "" , http .StatusNotFound )
458+ }
459+
460+ switch vars ["type" ] {
461+ case "user" :
462+ err = r .RevokeUser (auth .UserId (vars ["user" ]), ctx )
463+ case "role" :
464+ err = r .RevokeRole (auth .Role (vars ["user" ]), ctx )
465+ }
466+ if err != nil {
467+ logger .Error ("Failed to revoke resource" , zap .Error (err ))
468+ http .Error (writer , "" , http .StatusForbidden )
469+ }
470+
471+ err = r .Update (ctx , logger )
472+ if err != nil {
473+ logger .Error ("Failed to update resource" , zap .Error (err ))
474+ http .Error (writer , "" , http .StatusInternalServerError )
475+ }
476+
477+ http .Error (writer , "" , http .StatusOK )
478+ })
479+
431480 // GET /entity/{name}/{id}
432481 // get an entity state and status
433482 // PUT /entity/{name}/{id}
@@ -569,6 +618,168 @@ func Startup(ctx context.Context, js jetstream.JetStream, logger *zap.Logger, po
569618 processReq (ctx , writer , request , id .ToStateId (), glue .StartOrchestration , make (http.Header ))
570619 })
571620
621+ // PUT /orchestration/{name}/{id}/share/{userid}: share ownership of the resource with another user
622+ r .HandleFunc ("/orchestration/{name}/{id}/share/{userid}" , func (writer http.ResponseWriter , request * http.Request ) {
623+ if stop := handleCors (writer , request ); stop {
624+ return
625+ }
626+
627+ if request .Method != "PUT" {
628+ http .Error (writer , "Method Not Allowed" , http .StatusMethodNotAllowed )
629+ return
630+ }
631+
632+ ctx := getCorrelationId (ctx , & request .Header , nil )
633+ logRequest (logger , request , ctx )
634+
635+ vars := mux .Vars (request )
636+ id := & glue.OrchestrationId {
637+ InstanceId : strings .TrimSpace (vars ["name" ]),
638+ ExecutionId : strings .TrimSpace (vars ["id" ]),
639+ }
640+ stateId := id .ToStateId ()
641+
642+ // verify the user is authorized to access the resource
643+ ctx , done := authorize (writer , request , config , ctx , rm , stateId , logger , true , auth .Owner )
644+ if done {
645+ return
646+ }
647+
648+ r , err := rm .DiscoverResource (ctx , stateId , logger , true )
649+ if err != nil {
650+ logger .Error ("Failed to discover resource" , zap .Error (err ))
651+ http .Error (writer , "Not Found" , http .StatusNotFound )
652+ }
653+
654+ newUser := strings .TrimSpace (vars ["userid" ])
655+
656+ err = r .ShareOwnership (auth .UserId (newUser ), auth .GetUserFromContext (ctx ), true )
657+ if err != nil {
658+ logger .Error ("Failed to share ownership" , zap .Error (err ))
659+ http .Error (writer , "Internal Server Error" , http .StatusInternalServerError )
660+ }
661+
662+ err = r .Update (ctx , logger )
663+ if err != nil {
664+ logger .Error ("Failed to update resource" , zap .Error (err ))
665+ http .Error (writer , "Internal Server Error" , http .StatusInternalServerError )
666+ }
667+
668+ logger .Info ("Shared ownership" , zap .String ("id" , id .String ()), zap .String ("newUser" , newUser ))
669+ http .Error (writer , "" , http .StatusOK )
670+ })
671+
672+ // PUT /orchestration/{name}/{id}/grant/{user}/{operation}
673+ r .HandleFunc ("/orchestration/{name}/{id}/grant/{type}/{user}/{operation}" , func (writer http.ResponseWriter , request * http.Request ) {
674+ if stop := handleCors (writer , request ); stop {
675+ return
676+ }
677+
678+ if request .Method != "PUT" {
679+ http .Error (writer , "Method Not Allowed" , http .StatusMethodNotAllowed )
680+ return
681+ }
682+
683+ vars := mux .Vars (request )
684+ id := & glue.OrchestrationId {
685+ InstanceId : strings .TrimSpace (vars ["name" ]),
686+ ExecutionId : strings .TrimSpace (vars ["id" ]),
687+ }
688+ stateId := id .ToStateId ()
689+
690+ operation := auth .Owner
691+ switch strings .ToLower (vars ["operation" ]) {
692+ case "signal" :
693+ operation = auth .Signal
694+ break
695+ case "completion" :
696+ operation = auth .Completion
697+ break
698+ case "output" :
699+ operation = auth .Output
700+ case "call" :
701+ operation = auth .Call
702+ case "lock" :
703+ operation = auth .Lock
704+ case "sharePlus" :
705+ operation = auth .SharePlus
706+ case "shareMinus" :
707+ operation = auth .ShareMinus
708+ default :
709+ http .Error (writer , "" , http .StatusBadRequest )
710+ return
711+ }
712+
713+ r , err := rm .DiscoverResource (ctx , stateId , logger , true )
714+ if err != nil {
715+ logger .Error ("Failed to discover resource" , zap .Error (err ))
716+ http .Error (writer , "" , http .StatusNotFound )
717+ }
718+
719+ switch vars ["type" ] {
720+ case "user" :
721+ err = r .GrantUser (auth .UserId (vars ["user" ]), operation , ctx )
722+ case "role" :
723+ err = r .GrantRole (auth .Role (vars ["user" ]), operation , ctx )
724+ }
725+ if err != nil {
726+ logger .Error ("Failed to grant resource" , zap .Error (err ))
727+ http .Error (writer , "" , http .StatusForbidden )
728+ }
729+
730+ err = r .Update (ctx , logger )
731+ if err != nil {
732+ logger .Error ("Failed to update resource" , zap .Error (err ))
733+ http .Error (writer , "" , http .StatusInternalServerError )
734+ }
735+
736+ http .Error (writer , "" , http .StatusOK )
737+ })
738+
739+ // DELETE /orchestration/{name}/{id}/grant/{type}/{user}
740+ r .HandleFunc ("/entity/{name}/{id}/grant/{type}/{user}" , func (writer http.ResponseWriter , request * http.Request ) {
741+ if stop := handleCors (writer , request ); stop {
742+ return
743+ }
744+
745+ if request .Method != "DELETE" {
746+ http .Error (writer , "Method Not Allowed" , http .StatusMethodNotAllowed )
747+ return
748+ }
749+
750+ vars := mux .Vars (request )
751+ id := & glue.OrchestrationId {
752+ InstanceId : strings .TrimSpace (vars ["name" ]),
753+ ExecutionId : strings .TrimSpace (vars ["id" ]),
754+ }
755+ stateId := id .ToStateId ()
756+
757+ r , err := rm .DiscoverResource (ctx , stateId , logger , true )
758+ if err != nil {
759+ logger .Error ("Failed to discover resource" , zap .Error (err ))
760+ http .Error (writer , "" , http .StatusNotFound )
761+ }
762+
763+ switch vars ["type" ] {
764+ case "user" :
765+ err = r .RevokeUser (auth .UserId (vars ["user" ]), ctx )
766+ case "role" :
767+ err = r .RevokeRole (auth .Role (vars ["user" ]), ctx )
768+ }
769+ if err != nil {
770+ logger .Error ("Failed to revoke resource" , zap .Error (err ))
771+ http .Error (writer , "" , http .StatusForbidden )
772+ }
773+
774+ err = r .Update (ctx , logger )
775+ if err != nil {
776+ logger .Error ("Failed to update resource" , zap .Error (err ))
777+ http .Error (writer , "" , http .StatusInternalServerError )
778+ }
779+
780+ http .Error (writer , "" , http .StatusOK )
781+ })
782+
572783 // PUT /orchestration/{name}/{id}
573784 // start a new orchestration
574785 // GET /orchestration/{name}/{id}?wait=??
0 commit comments