github.com/pelicanplatform/pelican@v1.0.5/director/authentication.go (about)

     1  /***************************************************************
     2   *
     3   * Copyright (C) 2023, Pelican Project, Morgridge Institute for Research
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License"); you
     6   * may not use this file except in compliance with the License.  You may
     7   * obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   ***************************************************************/
    18  
    19  package director
    20  
    21  import (
    22  	"encoding/json"
    23  
    24  	"github.com/gin-gonic/gin"
    25  	"github.com/pelicanplatform/pelican/config"
    26  	"github.com/pelicanplatform/pelican/param"
    27  	log "github.com/sirupsen/logrus"
    28  )
    29  
    30  type DiscoveryResponse struct {
    31  	Issuer  string `json:"issuer"`
    32  	JwksUri string `json:"jwks_uri"`
    33  }
    34  
    35  const (
    36  	directorDiscoveryPath string = "/.well-known/openid-configuration"
    37  	directorJWKSPath      string = "/.well-known/issuer.jwks"
    38  )
    39  
    40  // Returns links related to director's authentication, including the link
    41  // to get the public key from the director
    42  func discoveryHandler(ctx *gin.Context) {
    43  	directorUrl := param.Federation_DirectorUrl.GetString()
    44  	if len(directorUrl) == 0 {
    45  		ctx.JSON(500, gin.H{"error": "Bad server configuration: Director URL is not set"})
    46  		return
    47  	}
    48  	rs := DiscoveryResponse{
    49  		Issuer:  directorUrl,
    50  		JwksUri: directorUrl + directorJWKSPath,
    51  	}
    52  	jsonData, err := json.MarshalIndent(rs, "", "  ")
    53  	if err != nil {
    54  		ctx.JSON(500, gin.H{"error": "Failed to marshal director's discovery response"})
    55  		return
    56  	}
    57  	// Append a new line to the JSON data
    58  	jsonData = append(jsonData, '\n')
    59  	ctx.Header("Content-Disposition", "attachment; filename=pelican-director-configuration.json")
    60  	ctx.Data(200, "application/json", jsonData)
    61  }
    62  
    63  // Returns director's public key
    64  func jwksHandler(ctx *gin.Context) {
    65  	key, err := config.GetIssuerPublicJWKS()
    66  	if err != nil {
    67  		log.Errorf("Failed to load director's public key: %v", err)
    68  		ctx.JSON(500, gin.H{"error": "Failed to load director's public key"})
    69  	} else {
    70  		jsonData, err := json.MarshalIndent(key, "", "  ")
    71  		if err != nil {
    72  			ctx.JSON(500, gin.H{"error": "Failed to marshal director's public key"})
    73  			return
    74  		}
    75  		// Append a new line to the JSON data
    76  		jsonData = append(jsonData, '\n')
    77  		ctx.Header("Content-Disposition", "attachment; filename=public-signing-key.jwks")
    78  		ctx.Data(200, "application/json", jsonData)
    79  	}
    80  }
    81  
    82  func RegisterDirectorAuth(router *gin.RouterGroup) {
    83  	router.GET(directorDiscoveryPath, discoveryHandler)
    84  	router.GET(directorJWKSPath, jwksHandler)
    85  }