|
|
@@ -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
|
|
|
+}
|