From b73113a2db4a90da11d9a64193de438aaa082dc9 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Fri, 28 Jul 2023 07:52:00 -0500 Subject: [PATCH] WIP: Add registration API between origin and director This work-in-progress commit sketches out a new REST API for the origin to register itself (and its available namespaces) with the director. The bones on the server side are there; the invocation from the origin (and the generation of the data at the origin) are not. --- director/origin_api.go | 4 ++-- director/redirect.go | 46 ++++++++++++++++++++++++++++++++++++++++++ origin_ui/advertise.go | 25 +++++++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 origin_ui/advertise.go diff --git a/director/origin_api.go b/director/origin_api.go index 2d738bc02..67c51fba0 100644 --- a/director/origin_api.go +++ b/director/origin_api.go @@ -22,7 +22,7 @@ type ( OriginAdvertise struct { Name string `json:"name"` URL string `json:"url"` - Namespace string `json:"namespace"` + Namespaces []NamespaceAd `json:"namespaces"` } ) @@ -96,7 +96,7 @@ func VerifyAdvertiseToken(token, namespace string) (bool, error) { return false, err } - tok, err := jwt.Parse([]byte(token), jwt.WithKeySet(keyset)) + tok, err := jwt.Parse([]byte(token), jwt.WithKeySet(keyset), jwt.WithValidate(true)) if err != nil { return false, err } diff --git a/director/redirect.go b/director/redirect.go index f3dc93477..a7863cf68 100644 --- a/director/redirect.go +++ b/director/redirect.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" ) func getRedirectURL(reqPath string, ad ServerAd, requiresAuth bool) (redirectURL url.URL) { @@ -154,8 +155,53 @@ func ShortcutMiddleware() gin.HandlerFunc { } } +func RegisterOrigin (ctx *gin.Context) { + tokens, present := ctx.Request.Header["Authorization"] + if !present || len(tokens) == 0 { + ctx.JSON(401, gin.H{"error": "Bearer token not present in the 'Authorization' header"}) + return + } + ad := OriginAdvertise{} + if ctx.ShouldBind(&ad) != nil { + ctx.JSON(400, gin.H{"error": "Invalid origin registration"}) + return + } + + for _, namespace := range(ad.Namespaces) { + ok, err := VerifyAdvertiseToken(tokens[0], namespace.Path) + if err != nil { + log.Warningln("Failed to verify token:", err) + ctx.JSON(400, gin.H{"error": "Authorization token verification failed"}) + return + } + if !ok { + log.Warningf("Origin %v advertised to namespace %v without valid registration\n", + ad.Name, namespace.Path) + ctx.JSON(400, gin.H{"error": "Origin not authorized to advertise to this namespace"}) + return + } + } + + ad_url, err := url.Parse(ad.URL) + if err != nil { + log.Warningf("Failed to parse origin URL %v: %v\n", ad.URL, err) + ctx.JSON(400, gin.H{"error": "Invalid origin URL"}) + return + } + + originAd := ServerAd{ + Name: ad.Name, + AuthURL: *ad_url, + URL: *ad_url, + Type: OriginType, + } + RecordAd(originAd, &ad.Namespaces) + ctx.JSON(200, gin.H{"msg": "Successful registration"}) +} + func RegisterDirector(router *gin.RouterGroup) { // Establish the routes used for cache/origin redirection router.GET("/api/v1.0/director/object/*any", RedirectToCache) router.GET("/api/v1.0/director/origin/*any", RedirectToOrigin) + router.POST("/api/v1.0/director/registerOrigin", RegisterOrigin) } diff --git a/origin_ui/advertise.go b/origin_ui/advertise.go new file mode 100644 index 000000000..f22bb1208 --- /dev/null +++ b/origin_ui/advertise.go @@ -0,0 +1,25 @@ +package origin_ui + +import ( + "errors" + + "github.com/pelicanplatform/pelican/director" + "github.com/spf13/viper" +) + +func AdvertiseOrigin() error { + name := viper.GetString("Sitename") + if name == "" { + return errors.New("Origin name isn't set") + } + // TODO: waiting on a different branch to merge origin URL generation + url := "https://localhost:8444" + + ad := director.OriginAdvertise{ + Name: name, + URL: url, + Namespaces: make([]director.NamespaceAd, 0), + } + _ = ad + return nil +}