Просмотр исходного кода

update terraform endpoints to use basic auth

Alexander Belanger 4 лет назад
Родитель
Сommit
e754815c39

+ 1 - 1
provisioner/server/authn/authn.go

@@ -110,7 +110,7 @@ func NewAuthNPorterTokenFactory(
 // NewAuthenticated creates a new instance of `AuthN` that implements the http.Handler
 // interface.
 func (f *AuthNPorterTokenFactory) NewAuthenticated(next http.Handler) http.Handler {
-	return &AuthNStatic{next, f.config}
+	return &AuthNPorterToken{next, f.config}
 }
 
 // AuthNPorterToken implements the authentication middleware

+ 81 - 0
provisioner/server/authn/basic.go

@@ -0,0 +1,81 @@
+package authn
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"strconv"
+
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/provisioner/server/config"
+)
+
+// AuthNFactory generates a middleware handler `AuthN`
+type AuthNBasicFactory struct {
+	config *config.Config
+}
+
+// NewAuthNBasicFactory returns an `AuthNBasicFactory` that uses the passed-in server
+// config
+func NewAuthNBasicFactory(
+	config *config.Config,
+) *AuthNBasicFactory {
+	return &AuthNBasicFactory{config}
+}
+
+// NewAuthenticated creates a new instance of `AuthN` that implements the http.Handler
+// interface.
+func (f *AuthNBasicFactory) NewAuthenticated(next http.Handler) http.Handler {
+	return &AuthNBasic{next, f.config}
+}
+
+// AuthNStatic implements the authentication middleware
+type AuthNBasic struct {
+	next   http.Handler
+	config *config.Config
+}
+
+// ServeHTTP calls next if the authentication token is valid,
+// or serves a forbidden error.
+func (authn *AuthNBasic) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	porterTokenIDStr, porterToken, ok := r.BasicAuth()
+
+	if ok {
+		if porterToken == "" {
+			authn.sendForbiddenError(fmt.Errorf("porter token does not exist"), w, r)
+			return
+		}
+
+		porterTokenID, err := strconv.ParseUint(porterTokenIDStr, 10, 64)
+
+		if err != nil {
+			authn.sendForbiddenError(err, w, r)
+			return
+		}
+
+		ceToken, err := ValidatePorterToken(authn.config, uint(porterTokenID), porterToken)
+
+		if err != nil {
+			authn.sendForbiddenError(err, w, r)
+			return
+		}
+
+		// attach ce token to context
+		ctx := r.Context()
+		ctx = context.WithValue(ctx, "ce_token", ceToken)
+		r = r.Clone(ctx)
+
+		authn.next.ServeHTTP(w, r)
+		return
+	}
+
+	authn.sendForbiddenError(fmt.Errorf("no basic auth credentials"), w, r)
+	return
+}
+
+func (authn *AuthNBasic) sendForbiddenError(err error, w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
+	reqErr := apierrors.NewErrForbidden(err)
+	apierrors.HandleAPIError(authn.config.Logger, authn.config.Alerter, w, r, reqErr, true)
+	return
+}

+ 10 - 2
provisioner/server/router/router.go

@@ -19,6 +19,7 @@ func NewAPIRouter(config *config.Config) *chi.Mux {
 		r.Use(middleware.ContentTypeJSON)
 
 		// create new group for raw state endpoints which use workspace authz middleware
+		basicAuth := authn.NewAuthNBasicFactory(config)
 		staticTokenAuth := authn.NewAuthNStaticFactory(config)
 		porterTokenAuth := authn.NewAuthNPorterTokenFactory(config)
 		workspaceAuth := authz.NewWorkspaceScopedFactory(config)
@@ -29,14 +30,21 @@ func NewAPIRouter(config *config.Config) *chi.Mux {
 				r.Use(porterTokenAuth.NewAuthenticated)
 				r.Use(workspaceAuth.Middleware)
 
-				r.Method("GET", "/{workspace_id}/tfstate", state.NewRawStateGetHandler(config))
-				r.Method("POST", "/{workspace_id}/tfstate", state.NewRawStateUpdateHandler(config))
 				r.Method("POST", "/{workspace_id}/resource", state.NewCreateResourceHandler(config))
 				r.Method("DELETE", "/{workspace_id}/resource", state.NewDeleteResourceHandler(config))
 				r.Method("POST", "/{workspace_id}/error", state.NewReportErrorHandler(config))
 				r.Method("GET", "/{workspace_id}/credentials", credentials.NewCredentialsGetHandler(config))
 			})
 
+			// This group is meant to be called from Terraform via basic auth
+			r.Group(func(r chi.Router) {
+				r.Use(basicAuth.NewAuthenticated)
+				r.Use(workspaceAuth.Middleware)
+
+				r.Method("GET", "/{workspace_id}/tfstate", state.NewRawStateGetHandler(config))
+				r.Method("POST", "/{workspace_id}/tfstate", state.NewRawStateUpdateHandler(config))
+			})
+
 			// This group is meant to be called via the API server
 			r.Group(func(r chi.Router) {
 				r.Use(staticTokenAuth.NewAuthenticated)