diff --git a/internal/config/config.go b/internal/config/config.go index 9c21115..4d5959d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -130,6 +130,8 @@ type Config struct { DefaultIconForActions string DefaultIconForDirectories string DefaultIconForBack string + AuthLoginUrl string + AuthAllowGuest bool usedConfigDir string } @@ -177,6 +179,7 @@ func DefaultConfigWithBasePort(basePort int) *Config { config.DefaultPermissions.Logs = true config.AuthJwtClaimUsername = "name" config.AuthJwtClaimUserGroup = "group" + config.AuthAllowGuest = true config.WebUIDir = "./webui" config.CronSupportForSeconds = false config.SectionNavigationStyle = "sidebar" diff --git a/internal/grpcapi/grpcApi.go b/internal/grpcapi/grpcApi.go index b239409..7f94909 100644 --- a/internal/grpcapi/grpcApi.go +++ b/internal/grpcapi/grpcApi.go @@ -269,6 +269,10 @@ func (api *oliveTinAPI) GetDashboardComponents(ctx ctx.Context, req *pb.GetDashb res.AuthenticatedUser = user.Username + if res.AuthenticatedUser == "guest" && !cfg.AuthAllowGuest { + return nil, status.Errorf(codes.PermissionDenied, "Unauthenticated") + } + return res, nil } diff --git a/internal/httpservers/restapi.go b/internal/httpservers/restapi.go index 3d9aee5..6be1322 100644 --- a/internal/httpservers/restapi.go +++ b/internal/httpservers/restapi.go @@ -5,7 +5,9 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" log "github.com/sirupsen/logrus" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" "google.golang.org/protobuf/encoding/protojson" "net/http" @@ -83,10 +85,21 @@ func startRestAPIServer(globalConfig *config.Config) error { return http.ListenAndServe(cfg.ListenAddressRestActions, cors.AllowCors(mux)) } +func errorHandler(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, r *http.Request, err error) { + log.Errorf("Error handling request: %v", err) + md, ok := runtime.ServerMetadataFromContext(ctx) + if ok && md.HeaderMD.Get("username") == nil { + err = status.Error(codes.Unauthenticated, "unauthenticated request") + } + + runtime.DefaultHTTPErrorHandler(ctx, mux, marshaler, w, r, err) +} + func newMux() *runtime.ServeMux { // The MarshalOptions set some important compatibility settings for the webui. See below. mux := runtime.NewServeMux( runtime.WithMetadata(parseRequestMetadata), + runtime.WithErrorHandler(errorHandler), runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{ Marshaler: &runtime.JSONPb{ MarshalOptions: protojson.MarshalOptions{ diff --git a/internal/httpservers/webuiServer.go b/internal/httpservers/webuiServer.go index c1087bf..32129e7 100644 --- a/internal/httpservers/webuiServer.go +++ b/internal/httpservers/webuiServer.go @@ -32,6 +32,7 @@ type webUISettings struct { SshFoundKey string SshFoundConfig string EnableCustomJs bool + AuthLoginUrl string } func findWebuiDir() string { @@ -117,6 +118,7 @@ func generateWebUISettings(w http.ResponseWriter, r *http.Request) { SshFoundKey: installationinfo.Runtime.SshFoundKey, SshFoundConfig: installationinfo.Runtime.SshFoundConfig, EnableCustomJs: cfg.EnableCustomJs, + AuthLoginUrl: cfg.AuthLoginUrl, }) w.Header().Add("Content-Type", "application/json") diff --git a/webui.dev/main.js b/webui.dev/main.js index 2b1459a..63c7281 100644 --- a/webui.dev/main.js +++ b/webui.dev/main.js @@ -58,6 +58,9 @@ function fetchGetDashboardComponents () { window.fetch(window.restBaseUrl + 'GetDashboardComponents', { cors: 'cors' }).then(res => { + if (!res.ok && res.status === 401) { + window.location.href = window.settings.AuthLoginUrl + } return res.json() }).then(res => { if (!window.restAvailable) {