github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/info/handler.go (about) 1 package info 2 3 import ( 4 "context" 5 "crypto/x509" 6 "net/http" 7 "strings" 8 9 "github.com/kyma-incubator/compass/components/director/pkg/certloader" 10 "github.com/kyma-incubator/compass/components/director/pkg/log" 11 "github.com/pkg/errors" 12 13 ord "github.com/kyma-incubator/compass/components/director/internal/open_resource_discovery" 14 15 "github.com/kyma-incubator/compass/components/director/pkg/httputils" 16 ) 17 18 const ( 19 plusDelimiter = "+" 20 commaDelimiter = "," 21 ) 22 23 // Config contains the data that should be exported on the info endpoint 24 type Config struct { 25 APIEndpoint string `envconfig:"APP_INFO_API_ENDPOINT,default=/v1/info" json:"-"` 26 RootCA string `envconfig:"APP_INFO_ROOT_CA"` 27 ExternalClientCertSecretName string `envconfig:"APP_EXTERNAL_CLIENT_CERT_SECRET_NAME"` 28 } 29 30 type responseData struct { 31 Issuer string `json:"certIssuer"` 32 Subject string `json:"certSubject"` 33 RootCA string `json:"rootCA"` 34 OrdVersion string `json:"ordAggregatorVersion"` 35 } 36 37 // NewInfoHandler returns handler which gives information about the CMP client certificate. 38 // The issuer and the subject are dynamically loaded from the certificate itself (reading the cert from the cert cache every time the endpoint is hit) rather than using hardcoded env values. 39 func NewInfoHandler(ctx context.Context, c Config, certCache certloader.Cache) func(writer http.ResponseWriter, request *http.Request) { 40 return func(w http.ResponseWriter, r *http.Request) { 41 responseData, err := prepareResponseData(c, certCache) 42 if err != nil { 43 log.C(ctx).Errorf("Error while processing client certificate from cache: %v", err) 44 w.WriteHeader(http.StatusInternalServerError) 45 return 46 } 47 48 if r.Method != http.MethodGet { 49 w.WriteHeader(http.StatusMethodNotAllowed) 50 return 51 } 52 httputils.RespondWithBody(ctx, w, http.StatusOK, responseData) 53 } 54 } 55 56 func prepareResponseData(c Config, certCache certloader.Cache) (responseData, error) { 57 clientCert := certCache.Get()[c.ExternalClientCertSecretName] 58 if clientCert == nil || len(clientCert.Certificate) == 0 { 59 return responseData{}, errors.New("did not find client certificate in the cache") 60 } 61 62 parsedClientCert, err := x509.ParseCertificate(clientCert.Certificate[0]) 63 if err != nil { 64 return responseData{}, errors.New("error while parsing client certificate") 65 } 66 67 certIssuer := replaceDelimiter(parsedClientCert.Issuer.String()) 68 certSubject := replaceDelimiter(parsedClientCert.Subject.String()) 69 70 return responseData{ 71 Issuer: certIssuer, 72 Subject: certSubject, 73 RootCA: c.RootCA, 74 OrdVersion: ord.SpecVersion, 75 }, nil 76 } 77 78 func replaceDelimiter(input string) string { 79 return strings.ReplaceAll(input, plusDelimiter, commaDelimiter) 80 }