...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/eagateway/server/server.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/eagateway/server

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"os"
    10  
    11  	"github.com/gin-contrib/requestid"
    12  	"github.com/gin-gonic/gin"
    13  	"github.com/go-logr/logr"
    14  	"github.com/peterbourgon/ff/v3"
    15  
    16  	"edge-infra.dev/pkg/edge/api/middleware"
    17  	"edge-infra.dev/pkg/lib/fog"
    18  	"edge-infra.dev/pkg/sds/emergencyaccess/client"
    19  	"edge-infra.dev/pkg/sds/emergencyaccess/config"
    20  	"edge-infra.dev/pkg/sds/emergencyaccess/eaconst"
    21  	"edge-infra.dev/pkg/sds/emergencyaccess/eagateway"
    22  	eamiddleware "edge-infra.dev/pkg/sds/emergencyaccess/middleware"
    23  	"edge-infra.dev/pkg/sds/emergencyaccess/msgsvc"
    24  	"edge-infra.dev/pkg/sds/emergencyaccess/remotecli"
    25  	"edge-infra.dev/pkg/sds/emergencyaccess/requestservice"
    26  )
    27  
    28  const (
    29  	defaultAuthorizeCommandPath = "authorizeCommand"
    30  	defaultAuthorizeRequestPath = "authorizeRequest"
    31  	defaultAuthorizeTargetPath  = "authorizeTarget"
    32  	defaultAuthorizeUserPath    = "authorizeUser"
    33  	defaultResolveTargetPath    = "resolveTarget"
    34  )
    35  
    36  var (
    37  	ErrUnauthorizedUser = fmt.Errorf("user is unauthorized")
    38  )
    39  
    40  type GatewayServer struct {
    41  	GinEngine      *gin.Engine
    42  	rcli           eagateway.RemoteCLI
    43  	log            logr.Logger
    44  	client         *http.Client
    45  	requestService *requestservice.RequestService
    46  
    47  	authorizeCommandURL *url.URL
    48  	authorizeRequestURL *url.URL
    49  	resolveTargetURL    *url.URL
    50  	authorizeTargetURL  *url.URL
    51  	authorizeUserURL    *url.URL
    52  }
    53  
    54  // New returns an EAGAteway service with our standard pattern. Function will
    55  // return an error if setAuthServiceURL fails.
    56  func New(config eagateway.Config, router *gin.Engine, log logr.Logger, rcli eagateway.RemoteCLI, requestService *requestservice.RequestService, checks ...func() error) (server *GatewayServer, err error) {
    57  	cl := client.New()
    58  	server = &GatewayServer{
    59  		GinEngine:      router,
    60  		rcli:           rcli,
    61  		requestService: requestService,
    62  		log:            log,
    63  		client:         cl,
    64  	}
    65  	err = server.setAuthServiceURLs(config)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	server.newGinServer(checks...)
    70  	return server, nil
    71  }
    72  
    73  func (server *GatewayServer) setAuthServiceURLs(config eagateway.Config) error {
    74  	host, err := url.Parse("http://" + config.AuthServiceHost)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	server.authorizeCommandURL = host.JoinPath(defaultAuthorizeCommandPath)
    79  	server.authorizeRequestURL = host.JoinPath(defaultAuthorizeRequestPath)
    80  	server.resolveTargetURL = host.JoinPath(defaultResolveTargetPath)
    81  	server.authorizeTargetURL = host.JoinPath(defaultAuthorizeTargetPath)
    82  	server.authorizeUserURL = host.JoinPath(defaultAuthorizeUserPath)
    83  	return nil
    84  }
    85  
    86  func (server *GatewayServer) newGinServer(checks ...func() error) {
    87  	router := server.GinEngine
    88  	router.ContextWithFallback = true
    89  
    90  	router.Use(middleware.SetRequestContext())
    91  	router.Use(gin.Recovery())
    92  
    93  	// public endpoints
    94  	router.Any("/health", eamiddleware.HealthCheck(checks...))
    95  
    96  	router.Any("/ready", func(c *gin.Context) {
    97  		c.String(http.StatusOK, "ok")
    98  	})
    99  
   100  	public := router.Group("/ea")
   101  	public.Use(requestid.New(requestid.WithCustomHeaderStrKey(eamiddleware.CorrelationIDKey)))
   102  	public.Use(eamiddleware.VerifyAPIVersion(eaconst.APIVersion))
   103  	public.Use(eamiddleware.SetLoggerInContext(server.log))
   104  	public.Use(eamiddleware.RequestBookendLogs())
   105  	public.Use(eamiddleware.SaveAuthToContext())
   106  
   107  	// authorized endpoints
   108  	authorized := public.Group("/")
   109  
   110  	authorized.POST("/startSession", server.StartSession)
   111  	authorized.POST("/sendCommand", server.SendCommand)
   112  	authorized.POST("/endSession", server.EndSession)
   113  }
   114  
   115  func Run() error {
   116  	conf := Config{}
   117  	flags := flag.NewFlagSet("eagateway", flag.ExitOnError)
   118  	conf.BindFlags(flags)
   119  	// flags passed as --auth-service-host from cli or AUTH_SERVICE_HOST in env will be parsed here.
   120  	if err := ff.Parse(flags, os.Args[1:], ff.WithEnvVarNoPrefix(), ff.WithIgnoreUndefined(true)); err != nil {
   121  		return err
   122  	}
   123  
   124  	router := gin.New()
   125  	log := newLogger()
   126  
   127  	// Remotecli uses the global logger from context for some log messages
   128  	ctx := fog.IntoContext(context.Background(), log)
   129  
   130  	ms, err := msgsvc.NewMessageService(ctx)
   131  	if err != nil {
   132  		return fmt.Errorf("failed to initialise message service: %w", err)
   133  	}
   134  
   135  	rcli := remotecli.New(ctx, ms)
   136  
   137  	db, check, err := config.DB(conf.SQL)
   138  	if err != nil {
   139  		return fmt.Errorf("error connecting to database: %w", err)
   140  	}
   141  	requestService, err := requestservice.New(db)
   142  	if err != nil {
   143  		return fmt.Errorf("failed to initialise request service: %w", err)
   144  	}
   145  
   146  	server, err := New(conf.EAGAteway, router, log, rcli, requestService, check)
   147  	if err != nil {
   148  		return err
   149  	}
   150  	return server.GinEngine.Run()
   151  }
   152  

View as plain text