From 25daec55167da673911524e3f60955f971a5e41b Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Thu, 9 May 2024 23:40:46 +0800 Subject: [PATCH 01/16] refactor: sbi server --- cmd/main.go | 19 +++- internal/logger/logger.go | 2 + internal/sbi/server.go | 123 +++++++++++++++++++++++++ pkg/app/app.go | 18 ++++ pkg/factory/config.go | 54 +++++++++++ pkg/service/init.go | 189 ++++++++++++++++++++++---------------- 6 files changed, 325 insertions(+), 80 deletions(-) create mode 100644 internal/sbi/server.go create mode 100644 pkg/app/app.go diff --git a/cmd/main.go b/cmd/main.go index 8f0bdb4..acbfef8 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,9 +9,12 @@ package main import ( + "context" "os" + "os/signal" "path/filepath" "runtime/debug" + "syscall" "github.com/urfave/cli" @@ -60,19 +63,31 @@ func action(cliCtx *cli.Context) error { logger.MainLog.Infoln("AUSF version: ", version.GetVersion()) + ctx, cancel := context.WithCancel(context.Background()) + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + + go func() { + <-sigCh // Wait for interrupt signal to gracefully shutdown + cancel() // Notify each goroutine and wait them stopped + }() + cfg, err := factory.ReadConfig(cliCtx.String("config")) if err != nil { + sigCh <- nil return err } factory.AusfConfig = cfg - ausf, err := service.NewApp(cfg) + ausf, err := service.NewApp(ctx, cfg, tlsKeyLogPath) if err != nil { + sigCh <- nil return err } AUSF = ausf - ausf.Start(tlsKeyLogPath) + ausf.Start() + AUSF.WaitRoutineStopped() return nil } diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 90993e0..76327e9 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -13,6 +13,7 @@ var ( InitLog *logrus.Entry CfgLog *logrus.Entry CtxLog *logrus.Entry + SBILog *logrus.Entry GinLog *logrus.Entry ConsumerLog *logrus.Entry UeAuthLog *logrus.Entry @@ -33,6 +34,7 @@ func init() { InitLog = NfLog.WithField(logger_util.FieldCategory, "Init") CfgLog = NfLog.WithField(logger_util.FieldCategory, "CFG") CtxLog = NfLog.WithField(logger_util.FieldCategory, "CTX") + SBILog = NfLog.WithField(logger_util.FieldCategory, "SBI") GinLog = NfLog.WithField(logger_util.FieldCategory, "GIN") ConsumerLog = NfLog.WithField(logger_util.FieldCategory, "Consumer") UeAuthLog = NfLog.WithField(logger_util.FieldCategory, "UeAuth") diff --git a/internal/sbi/server.go b/internal/sbi/server.go new file mode 100644 index 0000000..5498f43 --- /dev/null +++ b/internal/sbi/server.go @@ -0,0 +1,123 @@ +package sbi + +import ( + "context" + "fmt" + "log" + "net/http" + "runtime/debug" + "sync" + "time" + + "github.com/free5gc/ausf/pkg/app" + "github.com/free5gc/ausf/pkg/factory" + + ausf_context "github.com/free5gc/ausf/internal/context" + "github.com/free5gc/ausf/internal/logger" + "github.com/free5gc/ausf/internal/sbi/consumer" + "github.com/free5gc/ausf/internal/sbi/processor" + "github.com/free5gc/ausf/internal/util" + "github.com/free5gc/openapi/models" + "github.com/free5gc/util/httpwrapper" + logger_util "github.com/free5gc/util/logger" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" +) + +type ServerAusf interface { + app.App + + Consumer() *consumer.Consumer + Processor() *processor.Processor +} + +type Server struct { + ServerAusf + + httpServer *http.Server + router *gin.Engine +} + +func NewServer(ausf ServerAusf, tlsKeyLogPath string) (*Server, error) { + s := &Server{ + ServerAusf: ausf, + router: logger_util.NewGinWithLogrus(logger.GinLog), + } + + routes := s.getUeAuthenticationRoutes() + group := s.router.Group(factory.AusfAuthResUriPrefix) + routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_AUTH) + group.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) + }) + applyRoutes(group, routes) + + cfg := s.Config() + bindAddr := cfg.GetSbiBindingAddr() + logger.SBILog.Infof("Binding addr: [%s]", bindAddr) + var err error + if s.httpServer, err = httpwrapper.NewHttp2Server(bindAddr, tlsKeyLogPath, s.router); err != nil { + logger.InitLog.Errorf("Initialize HTTP server failed: %v", err) + return nil, err + } + s.httpServer.ErrorLog = log.New(logger.SBILog.WriterLevel(logrus.ErrorLevel), "HTTP2: ", 0) + + return s, nil +} + +func (s *Server) Run(traceCtx context.Context, wg *sync.WaitGroup) error { + var err error + _, s.Context().NfId, err = s.Consumer().RegisterNFInstance(context.Background()) + if err != nil { + logger.InitLog.Errorf("AUSF register to NRF Error[%s]", err.Error()) + } + + wg.Add(1) + go s.startServer(wg) + + return nil +} + +func (s *Server) Stop() { + const defaultShutdownTimeout time.Duration = 2 * time.Second + + if s.httpServer != nil { + logger.SBILog.Infof("Stop SBI server (listen on %s)", s.httpServer.Addr) + toCtx, cancel := context.WithTimeout(context.Background(), defaultShutdownTimeout) + defer cancel() + if err := s.httpServer.Shutdown(toCtx); err != nil { + logger.SBILog.Errorf("Could not close SBI server: %#v", err) + } + } +} + +func (s *Server) startServer(wg *sync.WaitGroup) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.SBILog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + s.Terminate() + } + wg.Done() + }() + + logger.SBILog.Infof("Start SBI server (listen on %s)", s.httpServer.Addr) + + var err error + cfg := s.Config() + scheme := cfg.GetSbiScheme() + if scheme == "http" { + err = s.httpServer.ListenAndServe() + } else if scheme == "https" { + err = s.httpServer.ListenAndServeTLS( + cfg.GetCertPemPath(), + cfg.GetCertKeyPath()) + } else { + err = fmt.Errorf("No support this scheme[%s]", scheme) + } + + if err != nil && err != http.ErrServerClosed { + logger.SBILog.Errorf("SBI server error: %v", err) + } + logger.SBILog.Warnf("SBI server (listen on %s) stopped", s.httpServer.Addr) +} diff --git a/pkg/app/app.go b/pkg/app/app.go new file mode 100644 index 0000000..ef2cbe9 --- /dev/null +++ b/pkg/app/app.go @@ -0,0 +1,18 @@ +package app + +import ( + ausf_context "github.com/free5gc/ausf/internal/context" + "github.com/free5gc/ausf/pkg/factory" +) + +type App interface { + SetLogEnable(enable bool) + SetLogLevel(level string) + SetReportCaller(reportCaller bool) + + Start() + Terminate() + + Context() *ausf_context.AUSFContext + Config() *factory.Config +} diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 983da78..e61b852 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -7,6 +7,7 @@ package factory import ( "errors" "fmt" + "os" "strconv" "sync" @@ -235,3 +236,56 @@ func (c *Config) GetLogReportCaller() bool { } return c.Logger.ReportCaller } + +func (c *Config) GetSbiBindingAddr() string { + c.RLock() + defer c.RUnlock() + return c.GetSbiBindingIP() + ":" + strconv.Itoa(c.GetSbiPort()) +} + +func (c *Config) GetSbiBindingIP() string { + c.RLock() + defer c.RUnlock() + bindIP := "0.0.0.0" + if c.Configuration == nil || c.Configuration.Sbi == nil { + return bindIP + } + if c.Configuration.Sbi.BindingIPv4 != "" { + if bindIP = os.Getenv(c.Configuration.Sbi.BindingIPv4); bindIP != "" { + logger.CfgLog.Infof("Parsing ServerIPv4 [%s] from ENV Variable", bindIP) + } else { + bindIP = c.Configuration.Sbi.BindingIPv4 + } + } + return bindIP +} + +func (c *Config) GetSbiPort() int { + c.RLock() + defer c.RUnlock() + if c.Configuration != nil && c.Configuration.Sbi != nil && c.Configuration.Sbi.Port != 0 { + return c.Configuration.Sbi.Port + } + return AusfSbiDefaultPort +} + +func (c *Config) GetSbiScheme() string { + c.RLock() + defer c.RUnlock() + if c.Configuration != nil && c.Configuration.Sbi != nil && c.Configuration.Sbi.Scheme != "" { + return c.Configuration.Sbi.Scheme + } + return AusfSbiDefaultScheme +} + +func (c *Config) GetCertPemPath() string { + c.RLock() + defer c.RUnlock() + return c.Configuration.Sbi.Tls.Pem +} + +func (c *Config) GetCertKeyPath() string { + c.RLock() + defer c.RUnlock() + return c.Configuration.Sbi.Tls.Key +} diff --git a/pkg/service/init.go b/pkg/service/init.go index ac478e8..4e59f92 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -1,41 +1,99 @@ package service import ( - "fmt" + "context" "io" "os" - "os/signal" "runtime/debug" - "syscall" + "sync" "github.com/sirupsen/logrus" ausf_context "github.com/free5gc/ausf/internal/context" "github.com/free5gc/ausf/internal/logger" + "github.com/free5gc/ausf/internal/sbi" "github.com/free5gc/ausf/internal/sbi/consumer" - "github.com/free5gc/ausf/internal/sbi/ueauthentication" + "github.com/free5gc/ausf/internal/sbi/processor" + "github.com/free5gc/ausf/pkg/app" "github.com/free5gc/ausf/pkg/factory" - "github.com/free5gc/util/httpwrapper" - logger_util "github.com/free5gc/util/logger" ) +var AUSF *AusfApp + +var _ app.App = &AusfApp{} + type AusfApp struct { - cfg *factory.Config + app.App + consumer.ConsumerAusf + processor.ProcessorAusf + sbi.ServerAusf + ausfCtx *ausf_context.AUSFContext + cfg *factory.Config + + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup + + sbiServer *sbi.Server + consumer *consumer.Consumer + processor *processor.Processor } -func NewApp(cfg *factory.Config) (*AusfApp, error) { - ausf := &AusfApp{cfg: cfg} +func NewApp(ctx context.Context, cfg *factory.Config, tlsKeyLogPath string) (*AusfApp, error) { + ausf := &AusfApp{ + cfg: cfg, + wg: sync.WaitGroup{}, + } ausf.SetLogEnable(cfg.GetLogEnable()) ausf.SetLogLevel(cfg.GetLogLevel()) ausf.SetReportCaller(cfg.GetLogReportCaller()) - ausf_context.Init() + + processor, err_p := processor.NewProcessor(ausf) + if err_p != nil { + return ausf, err_p + } + ausf.processor = processor + + consumer, err := consumer.NewConsumer(ausf) + if err != nil { + return ausf, err + } + ausf.consumer = consumer + + ausf.ctx, ausf.cancel = context.WithCancel(ctx) ausf.ausfCtx = ausf_context.GetSelf() + + if ausf.sbiServer, err = sbi.NewServer(ausf, tlsKeyLogPath); err != nil { + return nil, err + } + AUSF = ausf + return ausf, nil } -func (a *AusfApp) SetLogEnable(enable bool) { +func (a *AusfApp) CancelContext() context.Context { + return a.ctx +} + +func (a *AusfApp) Consumer() *consumer.Consumer { + return a.consumer +} + +func (a *AusfApp) Processor() *processor.Processor { + return a.processor +} + +func (a *AusfApp) Context() *ausf_context.AUSFContext { + return a.ausfCtx +} + +func (a *AusfApp) Config() *factory.Config { + return a.cfg +} + +func (c *AusfApp) SetLogEnable(enable bool) { logger.MainLog.Infof("Log enable is set to [%v]", enable) if enable && logger.Log.Out == os.Stderr { return @@ -43,15 +101,16 @@ func (a *AusfApp) SetLogEnable(enable bool) { return } - a.cfg.SetLogEnable(enable) + c.Config().SetLogEnable(enable) if enable { logger.Log.SetOutput(os.Stderr) } else { logger.Log.SetOutput(io.Discard) + } } -func (a *AusfApp) SetLogLevel(level string) { +func (c *AusfApp) SetLogLevel(level string) { lvl, err := logrus.ParseLevel(level) if err != nil { logger.MainLog.Warnf("Log level [%s] is invalid", level) @@ -63,95 +122,69 @@ func (a *AusfApp) SetLogLevel(level string) { return } - a.cfg.SetLogLevel(level) + c.Config().SetLogLevel(level) logger.Log.SetLevel(lvl) } -func (a *AusfApp) SetReportCaller(reportCaller bool) { +func (c *AusfApp) SetReportCaller(reportCaller bool) { logger.MainLog.Infof("Report Caller is set to [%v]", reportCaller) if reportCaller == logger.Log.ReportCaller { return } - a.cfg.SetLogReportCaller(reportCaller) + c.Config().SetLogReportCaller(reportCaller) logger.Log.SetReportCaller(reportCaller) } -func (a *AusfApp) Start(tlsKeyLogPath string) { +// tlsKeyLogPath have to remove after all NFs are refactor +func (a *AusfApp) Start() { logger.InitLog.Infoln("Server started") - router := logger_util.NewGinWithLogrus(logger.GinLog) - ueauthentication.AddService(router) + a.wg.Add(1) + go a.listenShutdownEvent() - pemPath := factory.AusfDefaultCertPemPath - keyPath := factory.AusfDefaultPrivateKeyPath - sbi := factory.AusfConfig.Configuration.Sbi - if sbi.Tls != nil { - pemPath = sbi.Tls.Pem - keyPath = sbi.Tls.Key - } - - self := a.ausfCtx - // Register to NRF - profile, err := consumer.BuildNFInstance(self) - if err != nil { - logger.InitLog.Error("Build AUSF Profile Error") - } - _, self.NfId, err = consumer.SendRegisterNFInstance(self.NrfUri, self.NfId, profile) - if err != nil { - logger.InitLog.Errorf("AUSF register to NRF Error[%s]", err.Error()) + if err := a.sbiServer.Run(context.Background(), &a.wg); err != nil { + logger.MainLog.Fatalf("Run SBI server failed: %+v", err) } +} - addr := fmt.Sprintf("%s:%d", self.BindingIPv4, self.SBIPort) - - signalChannel := make(chan os.Signal, 1) - signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) - go func() { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - <-signalChannel - a.Terminate() - os.Exit(0) +func (a *AusfApp) listenShutdownEvent() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.MainLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + a.wg.Done() }() - server, err := httpwrapper.NewHttp2Server(addr, tlsKeyLogPath, router) - if server == nil { - logger.InitLog.Errorf("Initialize HTTP server failed: %+v", err) - return - } - - if err != nil { - logger.InitLog.Warnf("Initialize HTTP server: +%v", err) - } - - serverScheme := factory.AusfConfig.Configuration.Sbi.Scheme - if serverScheme == "http" { - err = server.ListenAndServe() - } else if serverScheme == "https" { - err = server.ListenAndServeTLS(pemPath, keyPath) - } - - if err != nil { - logger.InitLog.Fatalf("HTTP server setup failed: %+v", err) - } + <-a.ctx.Done() + a.Terminate() } -func (a *AusfApp) Terminate() { - logger.InitLog.Infof("Terminating AUSF...") +func (c *AusfApp) Terminate() { + logger.MainLog.Infof("Terminating AUSF...") + c.cancel() + c.CallServerStop() + // deregister with NRF - problemDetails, err := consumer.SendDeregisterNFInstance() + problemDetails, err := c.Consumer().SendDeregisterNFInstance() if problemDetails != nil { - logger.InitLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails) + logger.MainLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails) } else if err != nil { - logger.InitLog.Errorf("Deregister NF instance Error[%+v]", err) + logger.MainLog.Errorf("Deregister NF instance Error[%+v]", err) } else { - logger.InitLog.Infof("Deregister from NRF successfully") + logger.MainLog.Infof("Deregister from NRF successfully") + } + logger.MainLog.Infof("AUSF SBI Server terminated") +} + +func (a *AusfApp) CallServerStop() { + if a.sbiServer != nil { + a.sbiServer.Stop() } +} - logger.InitLog.Infof("AUSF terminated") +func (a *AusfApp) WaitRoutineStopped() { + a.wg.Wait() + logger.MainLog.Infof("AUSF App is terminated") } From 35175b334e0a43d0fd84ad4347669b9fc2fa8578 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Fri, 10 May 2024 23:12:15 +0800 Subject: [PATCH 02/16] refactor: processor --- internal/sbi/api_ueauthentication.go | 152 ++++++ internal/sbi/processor/processor.go | 24 + .../ue_authentication.go | 454 ++++++++++++++++-- .../sbi/producer/eapAkaPrimeKeyGen_test.go | 156 ------ internal/sbi/producer/functions.go | 401 ---------------- internal/sbi/routes.go | 26 + internal/sbi/ueauthentication/api_default.go | 171 ------- internal/sbi/ueauthentication/routers.go | 106 ---- 8 files changed, 625 insertions(+), 865 deletions(-) create mode 100644 internal/sbi/api_ueauthentication.go create mode 100644 internal/sbi/processor/processor.go rename internal/sbi/{producer => processor}/ue_authentication.go (58%) delete mode 100644 internal/sbi/producer/eapAkaPrimeKeyGen_test.go delete mode 100644 internal/sbi/producer/functions.go create mode 100644 internal/sbi/routes.go delete mode 100644 internal/sbi/ueauthentication/api_default.go delete mode 100644 internal/sbi/ueauthentication/routers.go diff --git a/internal/sbi/api_ueauthentication.go b/internal/sbi/api_ueauthentication.go new file mode 100644 index 0000000..11a8f19 --- /dev/null +++ b/internal/sbi/api_ueauthentication.go @@ -0,0 +1,152 @@ +/* + * Nausf_UeAuthentication + * + * UeAuthentication Service © 2021, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + * + * API version: 3.0.3 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package sbi + +import ( + "net/http" + + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" + + "github.com/gin-gonic/gin" + + "github.com/free5gc/ausf/internal/logger" +) + +// Index is the index handler. +func Index(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") +} + +func (s *Server) getUeAuthenticationRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: Index, + }, + { + Method: http.MethodPost, + Pattern: "/ue-authentications/:authCtxId/eap-session", + APIFunc: s.EapAuthMethodPost, + }, + { + Method: http.MethodPost, + Pattern: "/ue-authentications", + APIFunc: s.UeAuthenticationsPost, + }, + { + Method: http.MethodPut, + Pattern: "/ue-authentications/:authCtxId/5g-aka-confirmation", + APIFunc: s.UeAuthenticationsAuthCtxID5gAkaConfirmationPut, + }, + } +} + +// EapAuthMethodPost - +func (s *Server) EapAuthMethodPost(c *gin.Context) { + var eapSessionReq models.EapSession + + requestBody, err := c.GetRawData() + if err != nil { + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + logger.Auth5gAkaLog.Errorf("Get Request Body error: %+v", err) + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&eapSessionReq, requestBody, "application/json") + if err != nil { + problemDetail := "[Request Body] " + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.Auth5gAkaLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + eapSessionId := c.Param("authCtxId") + + s.Processor().HandleEapAuthComfirmRequest(c, eapSessionReq, eapSessionId) +} + +// UeAuthenticationsPost +func (s *Server) UeAuthenticationsPost(c *gin.Context) { + var authInfo models.AuthenticationInfo + + requestBody, err := c.GetRawData() + if err != nil { + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + logger.UeAuthLog.Errorf("Get Request Body error: %+v", err) + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&authInfo, requestBody, "application/json") + if err != nil { + problemDetail := "[Request Body] " + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.UeAuthLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + + s.Processor().HandleUeAuthPostRequest(c, authInfo) +} + +// UeAuthenticationsAuthCtxID5gAkaConfirmationPut +func (s *Server) UeAuthenticationsAuthCtxID5gAkaConfirmationPut(c *gin.Context) { + var confirmationData models.ConfirmationData + + requestBody, err := c.GetRawData() + if err != nil { + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + logger.Auth5gAkaLog.Errorf("Get Request Body error: %+v", err) + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&confirmationData, requestBody, "application/json") + if err != nil { + problemDetail := "[Request Body] " + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.Auth5gAkaLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + confirmationDataResponseId := c.Param("authCtxId") + + s.Processor().HandleAuth5gAkaComfirmRequest(c, confirmationData, confirmationDataResponseId) +} diff --git a/internal/sbi/processor/processor.go b/internal/sbi/processor/processor.go new file mode 100644 index 0000000..3533a12 --- /dev/null +++ b/internal/sbi/processor/processor.go @@ -0,0 +1,24 @@ +package processor + +import "github.com/free5gc/ausf/pkg/app" + +type ProcessorAusf interface { + app.App +} + +type Processor struct { + ProcessorAusf +} + +type HandlerResponse struct { + Status int + Headers map[string][]string + Body interface{} +} + +func NewProcessor(ausf ProcessorAusf) (*Processor, error) { + p := &Processor{ + ProcessorAusf: ausf, + } + return p, nil +} diff --git a/internal/sbi/producer/ue_authentication.go b/internal/sbi/processor/ue_authentication.go similarity index 58% rename from internal/sbi/producer/ue_authentication.go rename to internal/sbi/processor/ue_authentication.go index 6e9384b..388267c 100644 --- a/internal/sbi/producer/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -1,16 +1,22 @@ -package producer +package processor import ( "bytes" + "crypto/hmac" "crypto/sha256" "encoding/base64" + "encoding/binary" "encoding/hex" + "fmt" + "hash" "math/rand" "net/http" + "strconv" "strings" "time" "github.com/bronze1man/radius" + "github.com/gin-gonic/gin" "github.com/google/gopacket" "github.com/google/gopacket/layers" @@ -18,71 +24,77 @@ import ( "github.com/free5gc/ausf/internal/logger" "github.com/free5gc/ausf/pkg/factory" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" "github.com/free5gc/util/ueauth" + + "github.com/antihax/optional" + + "github.com/free5gc/ausf/internal/sbi/consumer" + "github.com/free5gc/openapi/Nnrf_NFDiscovery" + Nudm_UEAU "github.com/free5gc/openapi/Nudm_UEAuthentication" ) -func HandleEapAuthComfirmRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleEapAuthComfirmRequest(c *gin.Context, eapSession models.EapSession, eapSessionId string) { logger.Auth5gAkaLog.Infof("EapAuthComfirmRequest") - updateEapSession := request.Body.(models.EapSession) - eapSessionID := request.Params["authCtxId"] - - response, problemDetails := EapAuthComfirmRequestProcedure(updateEapSession, eapSessionID) + response, problemDetails := p.EapAuthComfirmRequestProcedure(eapSession, eapSessionId) if response != nil { - return httpwrapper.NewResponse(http.StatusOK, nil, response) + c.JSON(http.StatusOK, response) + return } else if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) + return } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } - return httpwrapper.NewResponse(http.StatusForbidden, nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } -func HandleAuth5gAkaComfirmRequest(request *httpwrapper.Request) *httpwrapper.Response { - logger.Auth5gAkaLog.Infof("Auth5gAkaComfirmRequest") - updateConfirmationData := request.Body.(models.ConfirmationData) - ConfirmationDataResponseID := request.Params["authCtxId"] +func (p *Processor) HandleUeAuthPostRequest(c *gin.Context, authenticationInfo models.AuthenticationInfo) { + logger.UeAuthLog.Infof("HandleUeAuthPostRequest") + + response, locationURI, problemDetails := p.UeAuthPostRequestProcedure(authenticationInfo) + respHeader := make(http.Header) + respHeader.Set("Location", locationURI) - response, problemDetails := Auth5gAkaComfirmRequestProcedure(updateConfirmationData, ConfirmationDataResponseID) if response != nil { - return httpwrapper.NewResponse(http.StatusOK, nil, response) + c.JSON(http.StatusOK, response) + return } else if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) + return } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } - return httpwrapper.NewResponse(http.StatusForbidden, nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } -func HandleUeAuthPostRequest(request *httpwrapper.Request) *httpwrapper.Response { - logger.UeAuthLog.Infof("HandleUeAuthPostRequest") - updateAuthenticationInfo := request.Body.(models.AuthenticationInfo) +func (p *Processor) HandleAuth5gAkaComfirmRequest(c *gin.Context, confirmationData models.ConfirmationData, confirmationDataResponseId string) { + logger.Auth5gAkaLog.Infof("Auth5gAkaComfirmRequest") - response, locationURI, problemDetails := UeAuthPostRequestProcedure(updateAuthenticationInfo) - respHeader := make(http.Header) - respHeader.Set("Location", locationURI) + response, problemDetails := p.Auth5gAkaComfirmRequestProcedure(confirmationData, confirmationDataResponseId) if response != nil { - return httpwrapper.NewResponse(http.StatusCreated, respHeader, response) + c.JSON(http.StatusOK, response) + return } else if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) + return } problemDetails = &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UNSPECIFIED", } - return httpwrapper.NewResponse(http.StatusForbidden, nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } // func UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo, // ) (response *models.UeAuthenticationCtx, locationURI string, problemDetails *models.ProblemDetails) { -func UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo) (*models.UeAuthenticationCtx, +func (p *Processor) UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo) (*models.UeAuthenticationCtx, string, *models.ProblemDetails, ) { var responseBody models.UeAuthenticationCtx @@ -329,7 +341,7 @@ func UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationIn // ConfirmationDataResponseID string) (response *models.ConfirmationDataResponse, // problemDetails *models.ProblemDetails) { -func Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.ConfirmationData, +func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.ConfirmationData, ConfirmationDataResponseID string, ) (*models.ConfirmationDataResponse, *models.ProblemDetails) { var responseBody models.ConfirmationDataResponse @@ -387,7 +399,7 @@ func Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.Confirmation } // return response, problemDetails -func EapAuthComfirmRequestProcedure(updateEapSession models.EapSession, eapSessionID string) (*models.EapSession, +func (p *Processor) EapAuthComfirmRequestProcedure(updateEapSession models.EapSession, eapSessionID string) (*models.EapSession, *models.ProblemDetails, ) { var responseBody models.EapSession @@ -498,7 +510,7 @@ func EapAuthComfirmRequestProcedure(updateEapSession models.EapSession, eapSessi authInfo.SupiOrSuci = eapSessionID authInfo.ServingNetworkName = servingNetworkName authInfo.ResynchronizationInfo = resynchronizationInfo - response, _, problemDetails := UeAuthPostRequestProcedure(authInfo) + response, _, problemDetails := p.UeAuthPostRequestProcedure(authInfo) if problemDetails != nil { return nil, problemDetails } @@ -557,3 +569,383 @@ func EapAuthComfirmRequestProcedure(updateEapSession models.EapSession, eapSessi return &responseBody, nil } + +/* function.go */ + +func KDF5gAka(param ...string) hash.Hash { + s := param[0] + s += param[1] + if p0len, err := strconv.Atoi(param[2]); err != nil { + logger.AuthELog.Warnf("atoi failed: %+v", err) + } else { + s += strconv.FormatInt(int64(p0len), 16) + } + h := hmac.New(sha256.New, []byte(s)) + + return h +} + +func intToByteArray(i int) []byte { + r := make([]byte, 2) + binary.BigEndian.PutUint16(r, uint16(i)) + return r +} + +func padZeros(byteArray []byte, size int) []byte { + l := len(byteArray) + if l == size { + return byteArray + } + r := make([]byte, size) + copy(r[size-l:], byteArray) + return r +} + +func CalculateAtMAC(key []byte, input []byte) []byte { + // keyed with K_aut + h := hmac.New(sha256.New, key) + if _, err := h.Write(input); err != nil { + logger.AuthELog.Errorln(err.Error()) + } + sum := h.Sum(nil) + return sum[:16] +} + +// func EapEncodeAttribute(attributeType string, data string) (returnStr string, err error) { +func EapEncodeAttribute(attributeType string, data string) (string, error) { + var attribute string + var length int + + switch attributeType { + case "AT_RAND": + length = len(data)/8 + 1 + if length != 5 { + return "", fmt.Errorf("[eapEncodeAttribute] AT_RAND Length Error") + } + attrNum := fmt.Sprintf("%02x", ausf_context.AT_RAND_ATTRIBUTE) + attribute = attrNum + "05" + "0000" + data + + case "AT_AUTN": + length = len(data)/8 + 1 + if length != 5 { + return "", fmt.Errorf("[eapEncodeAttribute] AT_AUTN Length Error") + } + attrNum := fmt.Sprintf("%02x", ausf_context.AT_AUTN_ATTRIBUTE) + attribute = attrNum + "05" + "0000" + data + + case "AT_KDF_INPUT": + var byteName []byte + nLength := len(data) + length := (nLength+3)/4 + 1 + b := make([]byte, length*4) + byteNameLength := intToByteArray(nLength) + byteName = []byte(data) + pad := padZeros(byteName, (length-1)*4) + b[0] = 23 + b[1] = byte(length) + copy(b[2:4], byteNameLength) + copy(b[4:], pad) + return string(b[:]), nil + + case "AT_KDF": + // Value 1 default key derivation function for EAP-AKA' + attrNum := fmt.Sprintf("%02x", ausf_context.AT_KDF_ATTRIBUTE) + attribute = attrNum + "01" + "0001" + + case "AT_MAC": + // Pad MAC value with 16 bytes of 0 since this is just for the calculation of MAC + attrNum := fmt.Sprintf("%02x", ausf_context.AT_MAC_ATTRIBUTE) + attribute = attrNum + "05" + "0000" + "00000000000000000000000000000000" + + case "AT_RES": + var byteName []byte + nLength := len(data) + length := (nLength+3)/4 + 1 + b := make([]byte, length*4) + byteNameLength := intToByteArray(nLength) + byteName = []byte(data) + pad := padZeros(byteName, (length-1)*4) + b[0] = 3 + b[1] = byte(length) + copy(b[2:4], byteNameLength) + copy(b[4:], pad) + return string(b[:]), nil + + default: + logger.AuthELog.Errorf("UNKNOWN attributeType %s\n", attributeType) + return "", nil + } + + if r, err := hex.DecodeString(attribute); err != nil { + return "", err + } else { + return string(r), nil + } +} + +// func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) (K_encr string, K_aut string, K_re string, +// MSK string, EMSK string) { +func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) ([]byte, []byte, []byte, []byte, []byte) { + keyAp := ikPrime + ckPrime + + var key []byte + if keyTmp, err := hex.DecodeString(keyAp); err != nil { + logger.AuthELog.Warnf("Decode key AP failed: %+v", err) + } else { + key = keyTmp + } + sBase := []byte("EAP-AKA'" + identity) + + MK := []byte("") + prev := []byte("") + //_ = prev + prfRounds := 208/32 + 1 + for i := 0; i < prfRounds; i++ { + // Create a new HMAC by defining the hash type and the key (as byte array) + h := hmac.New(sha256.New, key) + + hexNum := (byte)(i + 1) + ap := append(sBase, hexNum) + s := append(prev, ap...) + + // Write Data to it + if _, err := h.Write(s); err != nil { + logger.AuthELog.Errorln(err.Error()) + } + + // Get result + sha := h.Sum(nil) + MK = append(MK, sha...) + prev = sha + } + + K_encr := MK[0:16] // 0..127 + K_aut := MK[16:48] // 128..383 + K_re := MK[48:80] // 384..639 + MSK := MK[80:144] // 640..1151 + EMSK := MK[144:208] // 1152..1663 + return K_encr, K_aut, K_re, MSK, EMSK +} + +func decodeEapAkaPrime(eapPkt []byte) (*ausf_context.EapAkaPrimePkt, error) { + var decodePkt ausf_context.EapAkaPrimePkt + var attrLen int + var decodeAttr ausf_context.EapAkaPrimeAttribute + attributes := make(map[uint8]ausf_context.EapAkaPrimeAttribute) + data := eapPkt[5:] + decodePkt.Subtype = data[0] + dataLen := len(data) + + // decode attributes + for i := 3; i < dataLen; i += attrLen { + attrType := data[i] + attrLen = int(data[i+1]) * 4 + if attrLen == 0 { + return nil, fmt.Errorf("attribute length equal to zero") + } + if i+attrLen > dataLen { + return nil, fmt.Errorf("packet length out of range") + } + switch attrType { + case ausf_context.AT_RES_ATTRIBUTE: + logger.AuthELog.Tracef("Decoding AT_RES\n") + accLen := int(data[i+3] >> 3) + if accLen > 16 || accLen < 4 || accLen+4 > attrLen { + return nil, fmt.Errorf("attribute AT_RES decode err") + } + + decodeAttr.Type = attrType + decodeAttr.Length = data[i+1] + decodeAttr.Value = data[i+4 : i+4+accLen] + attributes[attrType] = decodeAttr + case ausf_context.AT_MAC_ATTRIBUTE: + logger.AuthELog.Tracef("Decoding AT_MAC\n") + if attrLen != 20 { + return nil, fmt.Errorf("attribute AT_MAC decode err") + } + decodeAttr.Type = attrType + decodeAttr.Length = data[i+1] + Mac := make([]byte, attrLen-4) + copy(Mac, data[i+4:i+attrLen]) + decodeAttr.Value = Mac + attributes[attrType] = decodeAttr + + // clean AT_MAC value for integrity check later + zeros := make([]byte, attrLen-4) + copy(data[i+4:i+attrLen], zeros) + decodePkt.MACInput = eapPkt + case ausf_context.AT_KDF_ATTRIBUTE: + logger.AuthELog.Tracef("Decoding AT_KDF\n") + if attrLen != 4 { + return nil, fmt.Errorf("attribute AT_KDF decode err") + } + decodeAttr.Type = attrType + decodeAttr.Length = data[i+1] + decodeAttr.Value = data[i+2 : i+attrLen] + attributes[attrType] = decodeAttr + case ausf_context.AT_AUTS_ATTRIBUTE: + logger.AuthELog.Tracef("Decoding AT_AUTS\n") + if attrLen != 16 { + return nil, fmt.Errorf("attribute AT_AUTS decode err") + } + decodeAttr.Type = attrType + decodeAttr.Length = data[i+1] + decodeAttr.Value = data[i+2 : i+attrLen] + attributes[attrType] = decodeAttr + case ausf_context.AT_CLIENT_ERROR_CODE_ATTRIBUTE: + logger.AuthELog.Tracef("Decoding AT_CLIENT_ERROR_CODE\n") + if attrLen != 4 { + return nil, fmt.Errorf("attribute AT_CLIENT_ERROR_CODE decode err") + } + decodeAttr.Type = attrType + decodeAttr.Length = data[i+1] + decodeAttr.Value = data[i+2 : i+attrLen] + attributes[attrType] = decodeAttr + default: + logger.AuthELog.Tracef("attribute type %x skipped\n", attrType) + } + } + + switch decodePkt.Subtype { + case ausf_context.AKA_CHALLENGE_SUBTYPE: + logger.AuthELog.Tracef("Subtype AKA-Challenge\n") + if _, ok := attributes[ausf_context.AT_RES_ATTRIBUTE]; !ok { + return nil, fmt.Errorf("AKA-Challenge attributes error") + } else if _, ok := attributes[ausf_context.AT_MAC_ATTRIBUTE]; !ok { + return nil, fmt.Errorf("AKA-Challenge attributes error") + } + case ausf_context.AKA_AUTHENTICATION_REJECT_SUBTYPE: + logger.AuthELog.Tracef("Subtype AKA-Authentication-Reject\n") + if len(attributes) != 0 { + return nil, fmt.Errorf("AKA-Authentication-Reject attributes error") + } + case ausf_context.AKA_SYNCHRONIZATION_FAILURE_SUBTYPE: + logger.AuthELog.Tracef("Subtype AKA-Synchronization-Failure\n") + if len(attributes) != 2 { + return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") + } else if _, ok := attributes[ausf_context.AT_AUTS_ATTRIBUTE]; !ok { + return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") + } else if _, ok := attributes[ausf_context.AT_KDF_ATTRIBUTE]; !ok { + return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") + } else if kdfVal := attributes[ausf_context.AT_KDF_ATTRIBUTE].Value; !(kdfVal[0] == 0 && kdfVal[1] == 1) { + return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") + } + case ausf_context.AKA_NOTIFICATION_SUBTYPE: + logger.AuthELog.Tracef("Subtype AKA-Notification\n") + case ausf_context.AKA_CLIENT_ERROR_SUBTYPE: + logger.AuthELog.Tracef("Subtype AKA-Client-Error\n") + if len(attributes) != 1 { + return nil, fmt.Errorf("AKA-Client-Error attributes error") + } else if _, ok := attributes[ausf_context.AT_CLIENT_ERROR_CODE_ATTRIBUTE]; !ok { + return nil, fmt.Errorf("AKA-Client-Error attributes error") + } + default: + logger.AuthELog.Tracef("subtype %x skipped\n", decodePkt.Subtype) + } + + decodePkt.Attributes = attributes + + return &decodePkt, nil +} + +func ConstructFailEapAkaNotification(oldPktId uint8) string { + var eapPkt radius.EapPacket + eapPkt.Code = radius.EapCodeRequest + eapPkt.Identifier = oldPktId + 1 + eapPkt.Type = ausf_context.EAP_AKA_PRIME_TYPENUM + + eapAkaHdrBytes := make([]byte, 3) + eapAkaHdrBytes[0] = ausf_context.AKA_NOTIFICATION_SUBTYPE + + attrNum := fmt.Sprintf("%02x", ausf_context.AT_NOTIFICATION_ATTRIBUTE) + attribute := attrNum + "01" + "4000" + var attrHex []byte + if attrHexTmp, err := hex.DecodeString(attribute); err != nil { + logger.AuthELog.Warnf("Decode attribute failed: %+v", err) + } else { + attrHex = attrHexTmp + } + + eapPkt.Data = append(eapAkaHdrBytes, attrHex...) + eapPktEncode := eapPkt.Encode() + return base64.StdEncoding.EncodeToString(eapPktEncode) +} + +func ConstructEapNoTypePkt(code radius.EapCode, pktID uint8) string { + b := make([]byte, 4) + b[0] = byte(code) + b[1] = pktID + binary.BigEndian.PutUint16(b[2:4], uint16(4)) + return base64.StdEncoding.EncodeToString(b) +} + +func getUdmUrl(nrfUri string) string { + udmUrl := "https://localhost:29503" // default + nfDiscoverParam := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ + ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NUDM_UEAU}), + } + res, err := consumer.SendSearchNFInstances(nrfUri, models.NfType_UDM, models.NfType_AUSF, nfDiscoverParam) + if err != nil { + logger.UeAuthLog.Errorln("[Search UDM UEAU] ", err.Error()) + } else if len(res.NfInstances) > 0 { + udmInstance := res.NfInstances[0] + if len(udmInstance.Ipv4Addresses) > 0 && udmInstance.NfServices != nil { + ueauService := (*udmInstance.NfServices)[0] + ueauEndPoint := (*ueauService.IpEndPoints)[0] + udmUrl = string(ueauService.Scheme) + "://" + ueauEndPoint.Ipv4Address + ":" + strconv.Itoa(int(ueauEndPoint.Port)) + } + } else { + logger.UeAuthLog.Errorln("[Search UDM UEAU] len(NfInstances) = 0") + } + return udmUrl +} + +func createClientToUdmUeau(udmUrl string) *Nudm_UEAU.APIClient { + cfg := Nudm_UEAU.NewConfiguration() + cfg.SetBasePath(udmUrl) + clientAPI := Nudm_UEAU.NewAPIClient(cfg) + return clientAPI +} + +func sendAuthResultToUDM(id string, authType models.AuthType, success bool, servingNetworkName, udmUrl string) error { + timeNow := time.Now() + timePtr := &timeNow + + self := ausf_context.GetSelf() + + var authEvent models.AuthEvent + authEvent.TimeStamp = timePtr + authEvent.AuthType = authType + authEvent.Success = success + authEvent.ServingNetworkName = servingNetworkName + authEvent.NfInstanceId = self.GetSelfID() + + client := createClientToUdmUeau(udmUrl) + + ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) + if err != nil { + return err + } + + _, rsp, confirmAuthErr := client.ConfirmAuthApi.ConfirmAuth(ctx, id, authEvent) + defer func() { + if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("ConfirmAuth Response cannot close: %v", rspCloseErr) + } + }() + return confirmAuthErr +} + +func logConfirmFailureAndInformUDM(id string, authType models.AuthType, servingNetworkName, errStr, udmUrl string) { + if authType == models.AuthType__5_G_AKA { + logger.Auth5gAkaLog.Infoln(errStr) + if sendErr := sendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { + logger.Auth5gAkaLog.Infoln(sendErr.Error()) + } + } else if authType == models.AuthType_EAP_AKA_PRIME { + logger.AuthELog.Infoln(errStr) + if sendErr := sendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { + logger.AuthELog.Infoln(sendErr.Error()) + } + } +} diff --git a/internal/sbi/producer/eapAkaPrimeKeyGen_test.go b/internal/sbi/producer/eapAkaPrimeKeyGen_test.go deleted file mode 100644 index 7434308..0000000 --- a/internal/sbi/producer/eapAkaPrimeKeyGen_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package producer - -import ( - "encoding/hex" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/free5gc/util/ueauth" -) - -type testEapAkaPrimeCase struct { - Identity string `json:"Identity"` - NetworkName string `json:"Networkname"` - RAND string `json:"RAND"` - AUTN string `json:"AUTN"` - IK string `json:"IK"` - CK string `json:"CK"` - RES string `json:"RES"` - CKPrime string `json:"CKPrime"` - IKPrime string `json:"IKPrime"` - K_encr string `json:"K_encr"` - K_aut string `json:"K_aut"` - K_re string `json:"K_re"` - MSK string `json:"MSK"` - EMSK string `json:"EMSK"` -} - -func EapAkaPrimeKeyGenAll(data testEapAkaPrimeCase) ([]byte, []byte, []byte, []byte, []byte, []byte, []byte) { - var CK, IK, AUTN []byte - if CKtmp, err := hex.DecodeString(data.CK); err != nil { - fmt.Println(err) - } else { - CK = CKtmp - } - if IKtmp, err := hex.DecodeString(data.IK); err != nil { - fmt.Println(err) - } else { - IK = IKtmp - } - if AUTNtmp, err := hex.DecodeString(data.AUTN); err != nil { - fmt.Println(err) - } else { - AUTN = AUTNtmp - } - SQNxorAK := AUTN[:6] - key := append(CK, IK...) - FC := ueauth.FC_FOR_CK_PRIME_IK_PRIME_DERIVATION - P0 := []byte(data.NetworkName) - P1 := SQNxorAK - - // Generate CK' IK' - kdfVal, err := ueauth.GetKDFValue(key, FC, P0, ueauth.KDFLen(P0), P1, ueauth.KDFLen(P1)) - if err != nil { - fmt.Println(err) - } - CKPrime := kdfVal[:len(kdfVal)/2] - IKPrime := kdfVal[len(kdfVal)/2:] - CKPrimeHex := hex.EncodeToString(CKPrime) - IKPrimeHex := hex.EncodeToString(IKPrime) - - // Generate K_encr K_aut K_re MSK EMSK - K_encr, K_aut, K_re, MSK, EMSK := eapAkaPrimePrf(IKPrimeHex, CKPrimeHex, data.Identity) - return CKPrime, IKPrime, K_encr, K_aut, K_re, MSK, EMSK -} - -func TestEapAkaPrimeKeyGen(t *testing.T) { - // From RFC 5448 Appendix C - testCases := []testEapAkaPrimeCase{ - { - "0555444333222111", - "WLAN", - "81e92b6c0ee0e12ebceba8d92a99dfa5", - "bb52e91c747ac3ab2a5c23d15ee351d5", - "9744871ad32bf9bbd1dd5ce54e3e2e5a", - "5349fbe098649f948f5d2e973a81c00f", - "28d7b0f2a2ec3de5", - "0093962d0dd84aa5684b045c9edffa04", - "ccfc230ca74fcc96c0a5d61164f5a76c", - "766fa0a6c317174b812d52fbcd11a179", - "0842ea722ff6835bfa2032499fc3ec23c2f0e388b4f07543ffc677f1696d71ea", - "cf83aa8bc7e0aced892acc98e76a9b2095b558c7795c7094715cb3393aa7d17a", - "67c42d9aa56c1b79e295e3459fc3d187d42be0bf818d3070e362c5e967a4d544" + - "e8ecfe19358ab3039aff03b7c930588c055babee58a02650b067ec4e9347c75a", - "f861703cd775590e16c7679ea3874ada866311de290764d760cf76df647ea01c" + - "313f69924bdd7650ca9bac141ea075c4ef9e8029c0e290cdbad5638b63bc23fb", - }, - { - "0555444333222111", - "HRPD", - "81e92b6c0ee0e12ebceba8d92a99dfa5", - "bb52e91c747ac3ab2a5c23d15ee351d5", - "9744871ad32bf9bbd1dd5ce54e3e2e5a", - "5349fbe098649f948f5d2e973a81c00f", - "28d7b0f2a2ec3de5", - "3820f0277fa5f77732b1fb1d90c1a0da", - "db94a0ab557ef6c9ab48619ca05b9a9f", - "05ad73ac915fce89ac77e1520d82187b", - "5b4acaef62c6ebb8882b2f3d534c4b35277337a00184f20ff25d224c04be2afd", - "3f90bf5c6e5ef325ff04eb5ef6539fa8cca8398194fbd00be425b3f40dba10ac", - "87b321570117cd6c95ab6c436fb5073ff15cf85505d2bc5bb7355fc21ea8a757" + - "57e8f86a2b138002e05752913bb43b82f868a96117e91a2d95f526677d572900", - "c891d5f20f148a1007553e2dea555c9cb672e9675f4a66b4bafa027379f93aee" + - "539a5979d0a0042b9d2ae28bed3b17a31dc8ab75072b80bd0c1da612466e402c", - }, - { - "0555444333222111", - "WLAN", - "e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0", - "a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0", - "b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0", - "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0", - "d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0", - "cd4c8e5c68f57dd1d7d7dfd0c538e577", - "3ece6b705dbbf7dfc459a11280c65524", - "897d302fa2847416488c28e20dcb7be4", - "c40700e7722483ae3dc7139eb0b88bb558cb3081eccd057f9207d1286ee7dd53", - "0a591a22dd8b5b1cf29e3d508c91dbbdb4aee23051892c42b6a2de66ea504473", - "9f7dca9e37bb22029ed986e7cd09d4a70d1ac76d95535c5cac40a7504699bb89" + - "61a29ef6f3e90f183de5861ad1bedc81ce9916391b401aa006c98785a5756df7", - "724de00bdb9e568187be3fe746114557d5018779537ee37f4d3c6c738cb97b9d" + - "c651bc19bfadc344ffe2b52ca78bd8316b51dacc5f2b1440cb9515521cc7ba23", - }, - { - "0555444333222111", - "WLAN", - "e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0", - "a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0", - "b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0", - "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0", - "d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0", - "cd4c8e5c68f57dd1d7d7dfd0c538e577", - "3ece6b705dbbf7dfc459a11280c65524", - "897d302fa2847416488c28e20dcb7be4", - "c40700e7722483ae3dc7139eb0b88bb558cb3081eccd057f9207d1286ee7dd53", - "0a591a22dd8b5b1cf29e3d508c91dbbdb4aee23051892c42b6a2de66ea504473", - "9f7dca9e37bb22029ed986e7cd09d4a70d1ac76d95535c5cac40a7504699bb89" + - "61a29ef6f3e90f183de5861ad1bedc81ce9916391b401aa006c98785a5756df7", - "724de00bdb9e568187be3fe746114557d5018779537ee37f4d3c6c738cb97b9d" + - "c651bc19bfadc344ffe2b52ca78bd8316b51dacc5f2b1440cb9515521cc7ba23", - }, - } - - for idx, testData := range testCases { - fmt.Printf("Case %d\n", idx+1) - CKPrime, IKPrime, K_encr, K_aut, K_re, MSK, EMSK := EapAkaPrimeKeyGenAll(testData) - assert.True(t, testData.IKPrime == hex.EncodeToString(IKPrime)) - assert.True(t, testData.CKPrime == hex.EncodeToString(CKPrime)) - assert.True(t, testData.K_encr == hex.EncodeToString(K_encr)) - assert.True(t, testData.K_aut == hex.EncodeToString(K_aut)) - assert.True(t, testData.K_re == hex.EncodeToString(K_re)) - assert.True(t, testData.MSK == hex.EncodeToString(MSK)) - assert.True(t, testData.EMSK == hex.EncodeToString(EMSK)) - } -} diff --git a/internal/sbi/producer/functions.go b/internal/sbi/producer/functions.go deleted file mode 100644 index 00aba64..0000000 --- a/internal/sbi/producer/functions.go +++ /dev/null @@ -1,401 +0,0 @@ -package producer - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "encoding/binary" - "encoding/hex" - "fmt" - "hash" - "strconv" - "time" - - "github.com/antihax/optional" - "github.com/bronze1man/radius" - - ausf_context "github.com/free5gc/ausf/internal/context" - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/internal/sbi/consumer" - "github.com/free5gc/openapi/Nnrf_NFDiscovery" - Nudm_UEAU "github.com/free5gc/openapi/Nudm_UEAuthentication" - "github.com/free5gc/openapi/models" -) - -func KDF5gAka(param ...string) hash.Hash { - s := param[0] - s += param[1] - if p0len, err := strconv.Atoi(param[2]); err != nil { - logger.AuthELog.Warnf("atoi failed: %+v", err) - } else { - s += strconv.FormatInt(int64(p0len), 16) - } - h := hmac.New(sha256.New, []byte(s)) - - return h -} - -func intToByteArray(i int) []byte { - r := make([]byte, 2) - binary.BigEndian.PutUint16(r, uint16(i)) - return r -} - -func padZeros(byteArray []byte, size int) []byte { - l := len(byteArray) - if l == size { - return byteArray - } - r := make([]byte, size) - copy(r[size-l:], byteArray) - return r -} - -func CalculateAtMAC(key []byte, input []byte) []byte { - // keyed with K_aut - h := hmac.New(sha256.New, key) - if _, err := h.Write(input); err != nil { - logger.AuthELog.Errorln(err.Error()) - } - sum := h.Sum(nil) - return sum[:16] -} - -// func EapEncodeAttribute(attributeType string, data string) (returnStr string, err error) { -func EapEncodeAttribute(attributeType string, data string) (string, error) { - var attribute string - var length int - - switch attributeType { - case "AT_RAND": - length = len(data)/8 + 1 - if length != 5 { - return "", fmt.Errorf("[eapEncodeAttribute] AT_RAND Length Error") - } - attrNum := fmt.Sprintf("%02x", ausf_context.AT_RAND_ATTRIBUTE) - attribute = attrNum + "05" + "0000" + data - - case "AT_AUTN": - length = len(data)/8 + 1 - if length != 5 { - return "", fmt.Errorf("[eapEncodeAttribute] AT_AUTN Length Error") - } - attrNum := fmt.Sprintf("%02x", ausf_context.AT_AUTN_ATTRIBUTE) - attribute = attrNum + "05" + "0000" + data - - case "AT_KDF_INPUT": - var byteName []byte - nLength := len(data) - length := (nLength+3)/4 + 1 - b := make([]byte, length*4) - byteNameLength := intToByteArray(nLength) - byteName = []byte(data) - pad := padZeros(byteName, (length-1)*4) - b[0] = 23 - b[1] = byte(length) - copy(b[2:4], byteNameLength) - copy(b[4:], pad) - return string(b[:]), nil - - case "AT_KDF": - // Value 1 default key derivation function for EAP-AKA' - attrNum := fmt.Sprintf("%02x", ausf_context.AT_KDF_ATTRIBUTE) - attribute = attrNum + "01" + "0001" - - case "AT_MAC": - // Pad MAC value with 16 bytes of 0 since this is just for the calculation of MAC - attrNum := fmt.Sprintf("%02x", ausf_context.AT_MAC_ATTRIBUTE) - attribute = attrNum + "05" + "0000" + "00000000000000000000000000000000" - - case "AT_RES": - var byteName []byte - nLength := len(data) - length := (nLength+3)/4 + 1 - b := make([]byte, length*4) - byteNameLength := intToByteArray(nLength) - byteName = []byte(data) - pad := padZeros(byteName, (length-1)*4) - b[0] = 3 - b[1] = byte(length) - copy(b[2:4], byteNameLength) - copy(b[4:], pad) - return string(b[:]), nil - - default: - logger.AuthELog.Errorf("UNKNOWN attributeType %s\n", attributeType) - return "", nil - } - - if r, err := hex.DecodeString(attribute); err != nil { - return "", err - } else { - return string(r), nil - } -} - -// func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) (K_encr string, K_aut string, K_re string, -// MSK string, EMSK string) { -func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) ([]byte, []byte, []byte, []byte, []byte) { - keyAp := ikPrime + ckPrime - - var key []byte - if keyTmp, err := hex.DecodeString(keyAp); err != nil { - logger.AuthELog.Warnf("Decode key AP failed: %+v", err) - } else { - key = keyTmp - } - sBase := []byte("EAP-AKA'" + identity) - - MK := []byte("") - prev := []byte("") - //_ = prev - prfRounds := 208/32 + 1 - for i := 0; i < prfRounds; i++ { - // Create a new HMAC by defining the hash type and the key (as byte array) - h := hmac.New(sha256.New, key) - - hexNum := (byte)(i + 1) - ap := append(sBase, hexNum) - s := append(prev, ap...) - - // Write Data to it - if _, err := h.Write(s); err != nil { - logger.AuthELog.Errorln(err.Error()) - } - - // Get result - sha := h.Sum(nil) - MK = append(MK, sha...) - prev = sha - } - - K_encr := MK[0:16] // 0..127 - K_aut := MK[16:48] // 128..383 - K_re := MK[48:80] // 384..639 - MSK := MK[80:144] // 640..1151 - EMSK := MK[144:208] // 1152..1663 - return K_encr, K_aut, K_re, MSK, EMSK -} - -func decodeEapAkaPrime(eapPkt []byte) (*ausf_context.EapAkaPrimePkt, error) { - var decodePkt ausf_context.EapAkaPrimePkt - var attrLen int - var decodeAttr ausf_context.EapAkaPrimeAttribute - attributes := make(map[uint8]ausf_context.EapAkaPrimeAttribute) - data := eapPkt[5:] - decodePkt.Subtype = data[0] - dataLen := len(data) - - // decode attributes - for i := 3; i < dataLen; i += attrLen { - attrType := data[i] - attrLen = int(data[i+1]) * 4 - if attrLen == 0 { - return nil, fmt.Errorf("attribute length equal to zero") - } - if i+attrLen > dataLen { - return nil, fmt.Errorf("packet length out of range") - } - switch attrType { - case ausf_context.AT_RES_ATTRIBUTE: - logger.AuthELog.Tracef("Decoding AT_RES\n") - accLen := int(data[i+3] >> 3) - if accLen > 16 || accLen < 4 || accLen+4 > attrLen { - return nil, fmt.Errorf("attribute AT_RES decode err") - } - - decodeAttr.Type = attrType - decodeAttr.Length = data[i+1] - decodeAttr.Value = data[i+4 : i+4+accLen] - attributes[attrType] = decodeAttr - case ausf_context.AT_MAC_ATTRIBUTE: - logger.AuthELog.Tracef("Decoding AT_MAC\n") - if attrLen != 20 { - return nil, fmt.Errorf("attribute AT_MAC decode err") - } - decodeAttr.Type = attrType - decodeAttr.Length = data[i+1] - Mac := make([]byte, attrLen-4) - copy(Mac, data[i+4:i+attrLen]) - decodeAttr.Value = Mac - attributes[attrType] = decodeAttr - - // clean AT_MAC value for integrity check later - zeros := make([]byte, attrLen-4) - copy(data[i+4:i+attrLen], zeros) - decodePkt.MACInput = eapPkt - case ausf_context.AT_KDF_ATTRIBUTE: - logger.AuthELog.Tracef("Decoding AT_KDF\n") - if attrLen != 4 { - return nil, fmt.Errorf("attribute AT_KDF decode err") - } - decodeAttr.Type = attrType - decodeAttr.Length = data[i+1] - decodeAttr.Value = data[i+2 : i+attrLen] - attributes[attrType] = decodeAttr - case ausf_context.AT_AUTS_ATTRIBUTE: - logger.AuthELog.Tracef("Decoding AT_AUTS\n") - if attrLen != 16 { - return nil, fmt.Errorf("attribute AT_AUTS decode err") - } - decodeAttr.Type = attrType - decodeAttr.Length = data[i+1] - decodeAttr.Value = data[i+2 : i+attrLen] - attributes[attrType] = decodeAttr - case ausf_context.AT_CLIENT_ERROR_CODE_ATTRIBUTE: - logger.AuthELog.Tracef("Decoding AT_CLIENT_ERROR_CODE\n") - if attrLen != 4 { - return nil, fmt.Errorf("attribute AT_CLIENT_ERROR_CODE decode err") - } - decodeAttr.Type = attrType - decodeAttr.Length = data[i+1] - decodeAttr.Value = data[i+2 : i+attrLen] - attributes[attrType] = decodeAttr - default: - logger.AuthELog.Tracef("attribute type %x skipped\n", attrType) - } - } - - switch decodePkt.Subtype { - case ausf_context.AKA_CHALLENGE_SUBTYPE: - logger.AuthELog.Tracef("Subtype AKA-Challenge\n") - if _, ok := attributes[ausf_context.AT_RES_ATTRIBUTE]; !ok { - return nil, fmt.Errorf("AKA-Challenge attributes error") - } else if _, ok := attributes[ausf_context.AT_MAC_ATTRIBUTE]; !ok { - return nil, fmt.Errorf("AKA-Challenge attributes error") - } - case ausf_context.AKA_AUTHENTICATION_REJECT_SUBTYPE: - logger.AuthELog.Tracef("Subtype AKA-Authentication-Reject\n") - if len(attributes) != 0 { - return nil, fmt.Errorf("AKA-Authentication-Reject attributes error") - } - case ausf_context.AKA_SYNCHRONIZATION_FAILURE_SUBTYPE: - logger.AuthELog.Tracef("Subtype AKA-Synchronization-Failure\n") - if len(attributes) != 2 { - return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") - } else if _, ok := attributes[ausf_context.AT_AUTS_ATTRIBUTE]; !ok { - return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") - } else if _, ok := attributes[ausf_context.AT_KDF_ATTRIBUTE]; !ok { - return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") - } else if kdfVal := attributes[ausf_context.AT_KDF_ATTRIBUTE].Value; !(kdfVal[0] == 0 && kdfVal[1] == 1) { - return nil, fmt.Errorf("AKA-Synchornization-Failure attributes error") - } - case ausf_context.AKA_NOTIFICATION_SUBTYPE: - logger.AuthELog.Tracef("Subtype AKA-Notification\n") - case ausf_context.AKA_CLIENT_ERROR_SUBTYPE: - logger.AuthELog.Tracef("Subtype AKA-Client-Error\n") - if len(attributes) != 1 { - return nil, fmt.Errorf("AKA-Client-Error attributes error") - } else if _, ok := attributes[ausf_context.AT_CLIENT_ERROR_CODE_ATTRIBUTE]; !ok { - return nil, fmt.Errorf("AKA-Client-Error attributes error") - } - default: - logger.AuthELog.Tracef("subtype %x skipped\n", decodePkt.Subtype) - } - - decodePkt.Attributes = attributes - - return &decodePkt, nil -} - -func ConstructFailEapAkaNotification(oldPktId uint8) string { - var eapPkt radius.EapPacket - eapPkt.Code = radius.EapCodeRequest - eapPkt.Identifier = oldPktId + 1 - eapPkt.Type = ausf_context.EAP_AKA_PRIME_TYPENUM - - eapAkaHdrBytes := make([]byte, 3) - eapAkaHdrBytes[0] = ausf_context.AKA_NOTIFICATION_SUBTYPE - - attrNum := fmt.Sprintf("%02x", ausf_context.AT_NOTIFICATION_ATTRIBUTE) - attribute := attrNum + "01" + "4000" - var attrHex []byte - if attrHexTmp, err := hex.DecodeString(attribute); err != nil { - logger.AuthELog.Warnf("Decode attribute failed: %+v", err) - } else { - attrHex = attrHexTmp - } - - eapPkt.Data = append(eapAkaHdrBytes, attrHex...) - eapPktEncode := eapPkt.Encode() - return base64.StdEncoding.EncodeToString(eapPktEncode) -} - -func ConstructEapNoTypePkt(code radius.EapCode, pktID uint8) string { - b := make([]byte, 4) - b[0] = byte(code) - b[1] = pktID - binary.BigEndian.PutUint16(b[2:4], uint16(4)) - return base64.StdEncoding.EncodeToString(b) -} - -func getUdmUrl(nrfUri string) string { - udmUrl := "https://localhost:29503" // default - nfDiscoverParam := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ - ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NUDM_UEAU}), - } - res, err := consumer.SendSearchNFInstances(nrfUri, models.NfType_UDM, models.NfType_AUSF, nfDiscoverParam) - if err != nil { - logger.UeAuthLog.Errorln("[Search UDM UEAU] ", err.Error()) - } else if len(res.NfInstances) > 0 { - udmInstance := res.NfInstances[0] - if len(udmInstance.Ipv4Addresses) > 0 && udmInstance.NfServices != nil { - ueauService := (*udmInstance.NfServices)[0] - ueauEndPoint := (*ueauService.IpEndPoints)[0] - udmUrl = string(ueauService.Scheme) + "://" + ueauEndPoint.Ipv4Address + ":" + strconv.Itoa(int(ueauEndPoint.Port)) - } - } else { - logger.UeAuthLog.Errorln("[Search UDM UEAU] len(NfInstances) = 0") - } - return udmUrl -} - -func createClientToUdmUeau(udmUrl string) *Nudm_UEAU.APIClient { - cfg := Nudm_UEAU.NewConfiguration() - cfg.SetBasePath(udmUrl) - clientAPI := Nudm_UEAU.NewAPIClient(cfg) - return clientAPI -} - -func sendAuthResultToUDM(id string, authType models.AuthType, success bool, servingNetworkName, udmUrl string) error { - timeNow := time.Now() - timePtr := &timeNow - - self := ausf_context.GetSelf() - - var authEvent models.AuthEvent - authEvent.TimeStamp = timePtr - authEvent.AuthType = authType - authEvent.Success = success - authEvent.ServingNetworkName = servingNetworkName - authEvent.NfInstanceId = self.GetSelfID() - - client := createClientToUdmUeau(udmUrl) - - ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) - if err != nil { - return err - } - - _, rsp, confirmAuthErr := client.ConfirmAuthApi.ConfirmAuth(ctx, id, authEvent) - defer func() { - if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("ConfirmAuth Response cannot close: %v", rspCloseErr) - } - }() - return confirmAuthErr -} - -func logConfirmFailureAndInformUDM(id string, authType models.AuthType, servingNetworkName, errStr, udmUrl string) { - if authType == models.AuthType__5_G_AKA { - logger.Auth5gAkaLog.Infoln(errStr) - if sendErr := sendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { - logger.Auth5gAkaLog.Infoln(sendErr.Error()) - } - } else if authType == models.AuthType_EAP_AKA_PRIME { - logger.AuthELog.Infoln(errStr) - if sendErr := sendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { - logger.AuthELog.Infoln(sendErr.Error()) - } - } -} diff --git a/internal/sbi/routes.go b/internal/sbi/routes.go new file mode 100644 index 0000000..124bbf8 --- /dev/null +++ b/internal/sbi/routes.go @@ -0,0 +1,26 @@ +package sbi + +import "github.com/gin-gonic/gin" + +type Route struct { + Method string + Pattern string + APIFunc gin.HandlerFunc +} + +func applyRoutes(group *gin.RouterGroup, routes []Route) { + for _, route := range routes { + switch route.Method { + case "GET": + group.GET(route.Pattern, route.APIFunc) + case "POST": + group.POST(route.Pattern, route.APIFunc) + case "PUT": + group.PUT(route.Pattern, route.APIFunc) + case "PATCH": + group.PATCH(route.Pattern, route.APIFunc) + case "DELETE": + group.DELETE(route.Pattern, route.APIFunc) + } + } +} diff --git a/internal/sbi/ueauthentication/api_default.go b/internal/sbi/ueauthentication/api_default.go deleted file mode 100644 index b2db8a0..0000000 --- a/internal/sbi/ueauthentication/api_default.go +++ /dev/null @@ -1,171 +0,0 @@ -/* - * AUSF API - * - * OpenAPI specification for AUSF - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package ueauthentication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// HTTPEapAuthMethod - -func HTTPEapAuthMethod(ctx *gin.Context) { - var eapSessionReq models.EapSession - - requestBody, err := ctx.GetRawData() - if err != nil { - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - logger.Auth5gAkaLog.Errorf("Get Request Body error: %+v", err) - ctx.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&eapSessionReq, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.Auth5gAkaLog.Errorln(problemDetail) - ctx.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(ctx.Request, eapSessionReq) - req.Params["authCtxId"] = ctx.Param("authCtxId") - - rsp := producer.HandleEapAuthComfirmRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.Auth5gAkaLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - ctx.JSON(http.StatusInternalServerError, problemDetails) - } else { - ctx.Data(rsp.Status, "application/json", responseBody) - } -} - -// HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut - -func HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut(ctx *gin.Context) { - var confirmationData models.ConfirmationData - - requestBody, err := ctx.GetRawData() - if err != nil { - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - logger.Auth5gAkaLog.Errorf("Get Request Body error: %+v", err) - ctx.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&confirmationData, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.Auth5gAkaLog.Errorln(problemDetail) - ctx.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(ctx.Request, confirmationData) - req.Params["authCtxId"] = ctx.Param("authCtxId") - - rsp := producer.HandleAuth5gAkaComfirmRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.Auth5gAkaLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - ctx.JSON(http.StatusInternalServerError, problemDetails) - } else { - ctx.Data(rsp.Status, "application/json", responseBody) - } -} - -// HTTPUeAuthenticationsPost - -func HTTPUeAuthenticationsPost(ctx *gin.Context) { - var authInfo models.AuthenticationInfo - - requestBody, err := ctx.GetRawData() - if err != nil { - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - logger.UeAuthLog.Errorf("Get Request Body error: %+v", err) - ctx.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&authInfo, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.UeAuthLog.Errorln(problemDetail) - ctx.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(ctx.Request, authInfo) - - rsp := producer.HandleUeAuthPostRequest(req) - - for key, value := range rsp.Header { - ctx.Header(key, value[0]) - } - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.UeAuthLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - ctx.JSON(http.StatusInternalServerError, problemDetails) - } else { - ctx.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/ueauthentication/routers.go b/internal/sbi/ueauthentication/routers.go deleted file mode 100644 index 948f8db..0000000 --- a/internal/sbi/ueauthentication/routers.go +++ /dev/null @@ -1,106 +0,0 @@ -/* - * AUSF API - * - * OpenAPI specification for AUSF - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package ueauthentication - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - ausf_context "github.com/free5gc/ausf/internal/context" - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/internal/util" - "github.com/free5gc/ausf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AusfAuthResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_AUTH) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "HTTPEapAuthMethod", - strings.ToUpper("Post"), - "/ue-authentications/:authCtxId/eap-session", - HTTPEapAuthMethod, - }, - - { - "HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut", - strings.ToUpper("Put"), - "/ue-authentications/:authCtxId/5g-aka-confirmation", - HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut, - }, - - { - "HTTPUeAuthenticationsPost", - strings.ToUpper("Post"), - "/ue-authentications", - HTTPUeAuthenticationsPost, - }, -} From 5920ef680257121eb10d25559a6d6a9ddecbb212 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Fri, 10 May 2024 23:13:13 +0800 Subject: [PATCH 03/16] refactor: consumer --- internal/sbi/consumer/consumer.go | 31 ++++ internal/sbi/consumer/nf_discovery.go | 40 ----- internal/sbi/consumer/nf_management.go | 125 -------------- internal/sbi/consumer/nrf_service.go | 218 +++++++++++++++++++++++++ 4 files changed, 249 insertions(+), 165 deletions(-) create mode 100644 internal/sbi/consumer/consumer.go delete mode 100644 internal/sbi/consumer/nf_discovery.go delete mode 100644 internal/sbi/consumer/nf_management.go create mode 100644 internal/sbi/consumer/nrf_service.go diff --git a/internal/sbi/consumer/consumer.go b/internal/sbi/consumer/consumer.go new file mode 100644 index 0000000..da52db1 --- /dev/null +++ b/internal/sbi/consumer/consumer.go @@ -0,0 +1,31 @@ +package consumer + +import ( + "github.com/free5gc/ausf/pkg/app" + + "github.com/free5gc/openapi/Nnrf_NFDiscovery" + "github.com/free5gc/openapi/Nnrf_NFManagement" +) + +type ConsumerAusf interface { + app.App +} + +type Consumer struct { + ConsumerAusf + + *nnrfService +} + +func NewConsumer(ausf ConsumerAusf) (*Consumer, error) { + c := &Consumer{ + ConsumerAusf: ausf, + } + + c.nnrfService = &nnrfService{ + consumer: c, + nfMngmntClients: make(map[string]*Nnrf_NFManagement.APIClient), + nfDiscClients: make(map[string]*Nnrf_NFDiscovery.APIClient), + } + return c, nil +} diff --git a/internal/sbi/consumer/nf_discovery.go b/internal/sbi/consumer/nf_discovery.go deleted file mode 100644 index 3c97013..0000000 --- a/internal/sbi/consumer/nf_discovery.go +++ /dev/null @@ -1,40 +0,0 @@ -package consumer - -import ( - "fmt" - "net/http" - - ausf_context "github.com/free5gc/ausf/internal/context" - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/openapi/Nnrf_NFDiscovery" - "github.com/free5gc/openapi/models" -) - -func SendSearchNFInstances(nrfUri string, targetNfType, requestNfType models.NfType, - param Nnrf_NFDiscovery.SearchNFInstancesParamOpts, -) (*models.SearchResult, error) { - ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF) - if err != nil { - return nil, err - } - - configuration := Nnrf_NFDiscovery.NewConfiguration() - configuration.SetBasePath(nrfUri) - client := Nnrf_NFDiscovery.NewAPIClient(configuration) - - result, rsp, rspErr := client.NFInstancesStoreApi.SearchNFInstances(ctx, - targetNfType, requestNfType, ¶m) - - if rspErr != nil { - return nil, fmt.Errorf("NFInstancesStoreApi Response error: %+w", rspErr) - } - defer func() { - if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("NFInstancesStoreApi Response cannot close: %v", rspCloseErr) - } - }() - if rsp != nil && rsp.StatusCode == http.StatusTemporaryRedirect { - return nil, fmt.Errorf("Temporary Redirect For Non NRF Consumer") - } - return &result, nil -} diff --git a/internal/sbi/consumer/nf_management.go b/internal/sbi/consumer/nf_management.go deleted file mode 100644 index 816ae73..0000000 --- a/internal/sbi/consumer/nf_management.go +++ /dev/null @@ -1,125 +0,0 @@ -package consumer - -import ( - "fmt" - "net/http" - "strings" - "time" - - ausf_context "github.com/free5gc/ausf/internal/context" - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/Nnrf_NFManagement" - "github.com/free5gc/openapi/models" -) - -func BuildNFInstance(ausfContext *ausf_context.AUSFContext) (profile models.NfProfile, err error) { - profile.NfInstanceId = ausfContext.NfId - profile.NfType = models.NfType_AUSF - profile.NfStatus = models.NfStatus_REGISTERED - profile.Ipv4Addresses = append(profile.Ipv4Addresses, ausfContext.RegisterIPv4) - services := []models.NfService{} - for _, nfService := range ausfContext.NfService { - services = append(services, nfService) - } - if len(services) > 0 { - profile.NfServices = &services - } - var ausfInfo models.AusfInfo - ausfInfo.GroupId = ausfContext.GroupID - profile.AusfInfo = &ausfInfo - profile.PlmnList = &ausfContext.PlmnList - return -} - -// func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfile, -// ) (resouceNrfUri string,retrieveNfInstanceID string, err error) { -func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfile) (string, string, error) { - configuration := Nnrf_NFManagement.NewConfiguration() - configuration.SetBasePath(nrfUri) - client := Nnrf_NFManagement.NewAPIClient(configuration) - - ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_NFM, models.NfType_NRF) - if err != nil { - return "", "", err - } - - var res *http.Response - for { - nf, resTmp, err := client.NFInstanceIDDocumentApi.RegisterNFInstance(ctx, nfInstanceId, profile) - if err != nil || resTmp == nil { - logger.ConsumerLog.Errorf("AUSF register to NRF Error[%v]", err) - time.Sleep(2 * time.Second) - continue - } else { - res = resTmp - } - defer func() { - if resCloseErr := res.Body.Close(); resCloseErr != nil { - logger.ConsumerLog.Errorf("AUSF NFInstanceIDDocumentApi response body cannot close: %+v", resCloseErr) - } - }() - status := res.StatusCode - if status == http.StatusOK { - // NFUpdate - break - } else if status == http.StatusCreated { - // NFRegister - resourceUri := res.Header.Get("Location") - resourceNrfUri := resourceUri[:strings.Index(resourceUri, "/nnrf-nfm/")] - retrieveNfInstanceID := resourceUri[strings.LastIndex(resourceUri, "/")+1:] - - oauth2 := false - if nf.CustomInfo != nil { - v, ok := nf.CustomInfo["oauth2"].(bool) - if ok { - oauth2 = v - logger.MainLog.Infoln("OAuth2 setting receive from NRF:", oauth2) - } - } - ausf_context.GetSelf().OAuth2Required = oauth2 - if oauth2 && ausf_context.GetSelf().NrfCertPem == "" { - logger.CfgLog.Error("OAuth2 enable but no nrfCertPem provided in config.") - } - - return resourceNrfUri, retrieveNfInstanceID, nil - } else { - fmt.Println(fmt.Errorf("handler returned wrong status code %d", status)) - fmt.Println(fmt.Errorf("NRF return wrong status code %d", status)) - } - } - return "", "", nil -} - -func SendDeregisterNFInstance() (*models.ProblemDetails, error) { - logger.ConsumerLog.Infof("Send Deregister NFInstance") - - ctx, pd, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_NFM, models.NfType_NRF) - if err != nil { - return pd, err - } - - ausfSelf := ausf_context.GetSelf() - // Set client and set url - configuration := Nnrf_NFManagement.NewConfiguration() - configuration.SetBasePath(ausfSelf.NrfUri) - client := Nnrf_NFManagement.NewAPIClient(configuration) - - res, err := client.NFInstanceIDDocumentApi.DeregisterNFInstance(ctx, ausfSelf.NfId) - if err == nil { - return nil, err - } else if res != nil { - defer func() { - if resCloseErr := res.Body.Close(); resCloseErr != nil { - logger.ConsumerLog.Errorf("NFInstanceIDDocumentApi response body cannot close: %+v", resCloseErr) - } - }() - if res.Status != err.Error() { - return nil, err - } - problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - return &problem, err - } else { - return nil, openapi.ReportError("server no response") - } -} diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go new file mode 100644 index 0000000..637b93f --- /dev/null +++ b/internal/sbi/consumer/nrf_service.go @@ -0,0 +1,218 @@ +package consumer + +import ( + "context" + "fmt" + "net/http" + "strings" + "sync" + "time" + + // "github.com/free5gc/openapi/nrf/NFManagement" // R17 + ausf_context "github.com/free5gc/ausf/internal/context" + "github.com/free5gc/ausf/internal/logger" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/Nnrf_NFDiscovery" + "github.com/free5gc/openapi/Nnrf_NFManagement" + "github.com/free5gc/openapi/models" + "github.com/pkg/errors" +) + +type nnrfService struct { + consumer *Consumer + + nfMngmntMu sync.RWMutex + nfDiscMu sync.RWMutex + + nfMngmntClients map[string]*Nnrf_NFManagement.APIClient + nfDiscClients map[string]*Nnrf_NFDiscovery.APIClient +} + +func (s *nnrfService) getNFManagementClient(uri string) *Nnrf_NFManagement.APIClient { + if uri == "" { + return nil + } + s.nfMngmntMu.RLock() + client, ok := s.nfMngmntClients[uri] + if ok { + defer s.nfMngmntMu.RUnlock() + return client + } + + configuration := Nnrf_NFManagement.NewConfiguration() + configuration.SetBasePath(uri) + client = Nnrf_NFManagement.NewAPIClient(configuration) + + s.nfMngmntMu.RUnlock() + s.nfMngmntMu.Lock() + defer s.nfMngmntMu.Unlock() + s.nfMngmntClients[uri] = client + return client +} + +func (s *nnrfService) getNFDiscClient(uri string) *Nnrf_NFDiscovery.APIClient { + if uri == "" { + return nil + } + s.nfDiscMu.RLock() + client, ok := s.nfDiscClients[uri] + if ok { + defer s.nfDiscMu.RUnlock() + return client + } + + configuration := Nnrf_NFDiscovery.NewConfiguration() + configuration.SetBasePath(uri) + client = Nnrf_NFDiscovery.NewAPIClient(configuration) + + s.nfDiscMu.RUnlock() + s.nfDiscMu.Lock() + defer s.nfDiscMu.Unlock() + s.nfDiscClients[uri] = client + return client +} + +func (s *nnrfService) SendSearchNFInstances( + nrfUri string, targetNfType, requestNfType models.NfType, param Nnrf_NFDiscovery.SearchNFInstancesParamOpts) ( + *models.SearchResult, error) { + // Set client and set url + ausfContext := s.consumer.Context() + + client := s.getNFDiscClient(ausfContext.NrfUri) + + ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF) + if err != nil { + return nil, err + } + + result, res, err := client.NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, requestNfType, ¶m) + if err != nil { + logger.ConsumerLog.Errorf("SearchNFInstances failed: %+v", err) + } + defer func() { + if resCloseErr := res.Body.Close(); resCloseErr != nil { + logger.ConsumerLog.Errorf("NFInstancesStoreApi response body cannot close: %+v", resCloseErr) + } + }() + if res != nil && res.StatusCode == http.StatusTemporaryRedirect { + return nil, fmt.Errorf("Temporary Redirect For Non NRF Consumer") + } + + return &result, nil +} + +func (s *nnrfService) SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err error) { + logger.ConsumerLog.Infof("Send Deregister NFInstance") + + ctx, pd, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_NFM, models.NfType_NRF) + if err != nil { + return pd, err + } + + ausfContext := s.consumer.Context() + client := s.getNFManagementClient(ausfContext.NrfUri) + + var res *http.Response + + res, err = client.NFInstanceIDDocumentApi.DeregisterNFInstance(ctx, ausfContext.NfId) + if err == nil { + return problemDetails, err + } else if res != nil { + defer func() { + if resCloseErr := res.Body.Close(); resCloseErr != nil { + logger.ConsumerLog.Errorf("DeregisterNFInstance response cannot close: %+v", resCloseErr) + } + }() + if res.Status != err.Error() { + return problemDetails, err + } + problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return problemDetails, err +} + +func (s *nnrfService) RegisterNFInstance(ctx context.Context) ( + resouceNrfUri string, retrieveNfInstanceID string, err error) { + ausfContext := s.consumer.Context() + + client := s.getNFManagementClient(ausfContext.NrfUri) + nfProfile, err := s.buildNfProfile(ausfContext) + if err != nil { + return "", "", errors.Wrap(err, "RegisterNFInstance buildNfProfile()") + } + + var nf models.NfProfile + var res *http.Response + for { + nf, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), ausfContext.NfId, nfProfile) + if err != nil || res == nil { + logger.ConsumerLog.Errorf("AUSF register to NRF Error[%v]", err) + time.Sleep(2 * time.Second) + continue + } + defer func() { + if resCloseErr := res.Body.Close(); resCloseErr != nil { + logger.ConsumerLog.Errorf("RegisterNFInstance response body cannot close: %+v", resCloseErr) + } + }() + status := res.StatusCode + if status == http.StatusOK { + // NFUpdate + break + } else if status == http.StatusCreated { + // NFRegister + resourceUri := res.Header.Get("Location") + resouceNrfUri = resourceUri[:strings.Index(resourceUri, "/nnrf-nfm/")] + retrieveNfInstanceID = resourceUri[strings.LastIndex(resourceUri, "/")+1:] + + oauth2 := false + if nf.CustomInfo != nil { + v, ok := nf.CustomInfo["oauth2"].(bool) + if ok { + oauth2 = v + logger.MainLog.Infoln("OAuth2 setting receive from NRF:", oauth2) + } + } + ausf_context.GetSelf().OAuth2Required = oauth2 + if oauth2 && ausf_context.GetSelf().NrfCertPem == "" { + logger.CfgLog.Error("OAuth2 enable but no nrfCertPem provided in config.") + } + + break + } else { + fmt.Println(fmt.Errorf("handler returned wrong status code %d", status)) + fmt.Println("NRF return wrong status code", status) + } + } + return resouceNrfUri, retrieveNfInstanceID, err +} + +func (s *nnrfService) buildNfProfile(ausfContext *ausf_context.AUSFContext) (profile models.NfProfile, err error) { + profile.NfInstanceId = ausfContext.NfId + profile.NfType = models.NfType_AUSF + profile.NfStatus = models.NfStatus_REGISTERED + profile.Ipv4Addresses = append(profile.Ipv4Addresses, ausfContext.RegisterIPv4) + services := []models.NfService{} + for _, nfService := range ausfContext.NfService { + services = append(services, nfService) + } + if len(services) > 0 { + profile.NfServices = &services + } + profile.AusfInfo = &models.AusfInfo{ + // Todo + // SupiRanges: &[]models.SupiRange{ + // { + // //from TS 29.510 6.1.6.2.9 example2 + // //no need to set supirange in this moment 2019/10/4 + // Start: "123456789040000", + // End: "123456789059999", + // Pattern: "^imsi-12345678904[0-9]{4}$", + // }, + // }, + } + return +} From 4e792d1df51fea4fcf45000a107a5ddadc3355b6 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Sat, 25 May 2024 18:49:29 +0800 Subject: [PATCH 04/16] fix: linter error --- internal/sbi/api_ueauthentication.go | 9 +++--- internal/sbi/consumer/consumer.go | 7 +++- internal/sbi/consumer/nrf_service.go | 9 ++++-- internal/sbi/processor/ue_authentication.go | 36 +++++++++++++-------- internal/sbi/server.go | 8 ++--- pkg/service/init.go | 1 - 6 files changed, 43 insertions(+), 27 deletions(-) diff --git a/internal/sbi/api_ueauthentication.go b/internal/sbi/api_ueauthentication.go index 11a8f19..073a6b1 100644 --- a/internal/sbi/api_ueauthentication.go +++ b/internal/sbi/api_ueauthentication.go @@ -1,7 +1,9 @@ /* * Nausf_UeAuthentication * - * UeAuthentication Service © 2021, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + * UeAuthentication Service + * © 2021, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). + * All rights reserved. * * API version: 3.0.3 * Generated by: OpenAPI Generator (https://openapi-generator.tech) @@ -12,12 +14,11 @@ package sbi import ( "net/http" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/gin-gonic/gin" "github.com/free5gc/ausf/internal/logger" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" ) // Index is the index handler. diff --git a/internal/sbi/consumer/consumer.go b/internal/sbi/consumer/consumer.go index da52db1..dea5304 100644 --- a/internal/sbi/consumer/consumer.go +++ b/internal/sbi/consumer/consumer.go @@ -2,11 +2,12 @@ package consumer import ( "github.com/free5gc/ausf/pkg/app" - "github.com/free5gc/openapi/Nnrf_NFDiscovery" "github.com/free5gc/openapi/Nnrf_NFManagement" ) +var consumer *Consumer + type ConsumerAusf interface { app.App } @@ -17,6 +18,10 @@ type Consumer struct { *nnrfService } +func GetConsumer() *Consumer { + return consumer +} + func NewConsumer(ausf ConsumerAusf) (*Consumer, error) { c := &Consumer{ ConsumerAusf: ausf, diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go index 637b93f..2040f84 100644 --- a/internal/sbi/consumer/nrf_service.go +++ b/internal/sbi/consumer/nrf_service.go @@ -8,6 +8,8 @@ import ( "sync" "time" + "github.com/pkg/errors" + // "github.com/free5gc/openapi/nrf/NFManagement" // R17 ausf_context "github.com/free5gc/ausf/internal/context" "github.com/free5gc/ausf/internal/logger" @@ -15,7 +17,6 @@ import ( "github.com/free5gc/openapi/Nnrf_NFDiscovery" "github.com/free5gc/openapi/Nnrf_NFManagement" "github.com/free5gc/openapi/models" - "github.com/pkg/errors" ) type nnrfService struct { @@ -74,7 +75,8 @@ func (s *nnrfService) getNFDiscClient(uri string) *Nnrf_NFDiscovery.APIClient { func (s *nnrfService) SendSearchNFInstances( nrfUri string, targetNfType, requestNfType models.NfType, param Nnrf_NFDiscovery.SearchNFInstancesParamOpts) ( - *models.SearchResult, error) { + *models.SearchResult, error, +) { // Set client and set url ausfContext := s.consumer.Context() @@ -135,7 +137,8 @@ func (s *nnrfService) SendDeregisterNFInstance() (problemDetails *models.Problem } func (s *nnrfService) RegisterNFInstance(ctx context.Context) ( - resouceNrfUri string, retrieveNfInstanceID string, err error) { + resouceNrfUri string, retrieveNfInstanceID string, err error, +) { ausfContext := s.consumer.Context() client := s.getNFManagementClient(ausfContext.NrfUri) diff --git a/internal/sbi/processor/ue_authentication.go b/internal/sbi/processor/ue_authentication.go index 388267c..c63f438 100644 --- a/internal/sbi/processor/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/antihax/optional" "github.com/bronze1man/radius" "github.com/gin-gonic/gin" "github.com/google/gopacket" @@ -22,15 +23,12 @@ import ( ausf_context "github.com/free5gc/ausf/internal/context" "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/pkg/factory" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/ueauth" - - "github.com/antihax/optional" - "github.com/free5gc/ausf/internal/sbi/consumer" + "github.com/free5gc/ausf/pkg/factory" "github.com/free5gc/openapi/Nnrf_NFDiscovery" Nudm_UEAU "github.com/free5gc/openapi/Nudm_UEAuthentication" + "github.com/free5gc/openapi/models" + "github.com/free5gc/util/ueauth" ) func (p *Processor) HandleEapAuthComfirmRequest(c *gin.Context, eapSession models.EapSession, eapSessionId string) { @@ -73,7 +71,11 @@ func (p *Processor) HandleUeAuthPostRequest(c *gin.Context, authenticationInfo m c.JSON(int(problemDetails.Status), problemDetails) } -func (p *Processor) HandleAuth5gAkaComfirmRequest(c *gin.Context, confirmationData models.ConfirmationData, confirmationDataResponseId string) { +func (p *Processor) HandleAuth5gAkaComfirmRequest( + c *gin.Context, + confirmationData models.ConfirmationData, + confirmationDataResponseId string, +) { logger.Auth5gAkaLog.Infof("Auth5gAkaComfirmRequest") response, problemDetails := p.Auth5gAkaComfirmRequestProcedure(confirmationData, confirmationDataResponseId) @@ -94,9 +96,9 @@ func (p *Processor) HandleAuth5gAkaComfirmRequest(c *gin.Context, confirmationDa // func UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo, // ) (response *models.UeAuthenticationCtx, locationURI string, problemDetails *models.ProblemDetails) { -func (p *Processor) UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo) (*models.UeAuthenticationCtx, - string, *models.ProblemDetails, -) { +func (p *Processor) UeAuthPostRequestProcedure( + updateAuthenticationInfo models.AuthenticationInfo, +) (*models.UeAuthenticationCtx, string, *models.ProblemDetails) { var responseBody models.UeAuthenticationCtx var authInfoReq models.AuthenticationInfoRequest @@ -399,9 +401,10 @@ func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData mode } // return response, problemDetails -func (p *Processor) EapAuthComfirmRequestProcedure(updateEapSession models.EapSession, eapSessionID string) (*models.EapSession, - *models.ProblemDetails, -) { +func (p *Processor) EapAuthComfirmRequestProcedure( + updateEapSession models.EapSession, + eapSessionID string, +) (*models.EapSession, *models.ProblemDetails) { var responseBody models.EapSession if !ausf_context.CheckIfSuciSupiPairExists(eapSessionID) { @@ -884,7 +887,12 @@ func getUdmUrl(nrfUri string) string { nfDiscoverParam := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NUDM_UEAU}), } - res, err := consumer.SendSearchNFInstances(nrfUri, models.NfType_UDM, models.NfType_AUSF, nfDiscoverParam) + res, err := consumer.GetConsumer().SendSearchNFInstances( + nrfUri, + models.NfType_UDM, + models.NfType_AUSF, + nfDiscoverParam, + ) if err != nil { logger.UeAuthLog.Errorln("[Search UDM UEAU] ", err.Error()) } else if len(res.NfInstances) > 0 { diff --git a/internal/sbi/server.go b/internal/sbi/server.go index 5498f43..a4db49f 100644 --- a/internal/sbi/server.go +++ b/internal/sbi/server.go @@ -9,19 +9,19 @@ import ( "sync" "time" - "github.com/free5gc/ausf/pkg/app" - "github.com/free5gc/ausf/pkg/factory" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" ausf_context "github.com/free5gc/ausf/internal/context" "github.com/free5gc/ausf/internal/logger" "github.com/free5gc/ausf/internal/sbi/consumer" "github.com/free5gc/ausf/internal/sbi/processor" "github.com/free5gc/ausf/internal/util" + "github.com/free5gc/ausf/pkg/app" + "github.com/free5gc/ausf/pkg/factory" "github.com/free5gc/openapi/models" "github.com/free5gc/util/httpwrapper" logger_util "github.com/free5gc/util/logger" - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" ) type ServerAusf interface { diff --git a/pkg/service/init.go b/pkg/service/init.go index 4e59f92..f4f8217 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -106,7 +106,6 @@ func (c *AusfApp) SetLogEnable(enable bool) { logger.Log.SetOutput(os.Stderr) } else { logger.Log.SetOutput(io.Discard) - } } From 13a472a9d4ffecc573205d1f84d56a568848fe1c Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Sat, 8 Jun 2024 21:56:12 +0800 Subject: [PATCH 05/16] refactor: refactor sorprotection and upuprotection --- internal/sbi/api_sorprotection.go | 11 +++ internal/sbi/api_upuprotection.go | 11 +++ internal/sbi/sorprotection/api_default.go | 21 ------ internal/sbi/sorprotection/routers.go | 92 ----------------------- internal/sbi/upuprotection/api_default.go | 21 ------ internal/sbi/upuprotection/routers.go | 92 ----------------------- 6 files changed, 22 insertions(+), 226 deletions(-) create mode 100644 internal/sbi/api_sorprotection.go create mode 100644 internal/sbi/api_upuprotection.go delete mode 100644 internal/sbi/sorprotection/api_default.go delete mode 100644 internal/sbi/sorprotection/routers.go delete mode 100644 internal/sbi/upuprotection/api_default.go delete mode 100644 internal/sbi/upuprotection/routers.go diff --git a/internal/sbi/api_sorprotection.go b/internal/sbi/api_sorprotection.go new file mode 100644 index 0000000..09799d1 --- /dev/null +++ b/internal/sbi/api_sorprotection.go @@ -0,0 +1,11 @@ +package sbi + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func (s *Server) SupiUeSorPost(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{}) +} diff --git a/internal/sbi/api_upuprotection.go b/internal/sbi/api_upuprotection.go new file mode 100644 index 0000000..473ef3d --- /dev/null +++ b/internal/sbi/api_upuprotection.go @@ -0,0 +1,11 @@ +package sbi + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func (s *Server) SupiUeUpuPost(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{}) +} diff --git a/internal/sbi/sorprotection/api_default.go b/internal/sbi/sorprotection/api_default.go deleted file mode 100644 index e0849b3..0000000 --- a/internal/sbi/sorprotection/api_default.go +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Nausf_SoRProtection Service - * - * AUSF SoR Protection Service - * - * API version: 1.0.1 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package sorprotection - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -// SupiUeSorPost - -func SupiUeSorPost(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{}) -} diff --git a/internal/sbi/sorprotection/routers.go b/internal/sbi/sorprotection/routers.go deleted file mode 100644 index 45264b2..0000000 --- a/internal/sbi/sorprotection/routers.go +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Nausf_SoRProtection Service - * - * AUSF SoR Protection Service - * - * API version: 1.0.1 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package sorprotection - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - ausf_context "github.com/free5gc/ausf/internal/context" - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/internal/util" - "github.com/free5gc/ausf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AusfSorprotectionResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_SORPROTECTION) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "SupiUeSorPost", - strings.ToUpper("Post"), - "/:supi/ue-sor", - SupiUeSorPost, - }, -} diff --git a/internal/sbi/upuprotection/api_default.go b/internal/sbi/upuprotection/api_default.go deleted file mode 100644 index 0b79c7f..0000000 --- a/internal/sbi/upuprotection/api_default.go +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Nausf_UPUProtection Service - * - * AUSF UPU Protection Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package upuprotection - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -// SupiUeUpuPost - -func SupiUeUpuPost(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{}) -} diff --git a/internal/sbi/upuprotection/routers.go b/internal/sbi/upuprotection/routers.go deleted file mode 100644 index f3affde..0000000 --- a/internal/sbi/upuprotection/routers.go +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Nausf_UPUProtection Service - * - * AUSF UPU Protection Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package upuprotection - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - ausf_context "github.com/free5gc/ausf/internal/context" - "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/internal/util" - "github.com/free5gc/ausf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AusfAuthResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_UPUPROTECTION) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "SupiUeUpuPost", - strings.ToUpper("Post"), - "/:supi/ue-upu", - SupiUeUpuPost, - }, -} From 15823891b3e7736a58b2ca405e8c29a177396d10 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Sun, 9 Jun 2024 13:25:03 +0800 Subject: [PATCH 06/16] fix: remove unused code --- internal/sbi/processor/processor.go | 6 ------ internal/sbi/processor/ue_authentication.go | 8 -------- 2 files changed, 14 deletions(-) diff --git a/internal/sbi/processor/processor.go b/internal/sbi/processor/processor.go index 3533a12..2ddabdb 100644 --- a/internal/sbi/processor/processor.go +++ b/internal/sbi/processor/processor.go @@ -10,12 +10,6 @@ type Processor struct { ProcessorAusf } -type HandlerResponse struct { - Status int - Headers map[string][]string - Body interface{} -} - func NewProcessor(ausf ProcessorAusf) (*Processor, error) { p := &Processor{ ProcessorAusf: ausf, diff --git a/internal/sbi/processor/ue_authentication.go b/internal/sbi/processor/ue_authentication.go index c63f438..7dce976 100644 --- a/internal/sbi/processor/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -94,8 +94,6 @@ func (p *Processor) HandleAuth5gAkaComfirmRequest( c.JSON(int(problemDetails.Status), problemDetails) } -// func UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo, -// ) (response *models.UeAuthenticationCtx, locationURI string, problemDetails *models.ProblemDetails) { func (p *Processor) UeAuthPostRequestProcedure( updateAuthenticationInfo models.AuthenticationInfo, ) (*models.UeAuthenticationCtx, string, *models.ProblemDetails) { @@ -339,10 +337,6 @@ func (p *Processor) UeAuthPostRequestProcedure( return &responseBody, locationURI, nil } -// func Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.ConfirmationData, -// ConfirmationDataResponseID string) (response *models.ConfirmationDataResponse, -// problemDetails *models.ProblemDetails) { - func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.ConfirmationData, ConfirmationDataResponseID string, ) (*models.ConfirmationDataResponse, *models.ProblemDetails) { @@ -686,8 +680,6 @@ func EapEncodeAttribute(attributeType string, data string) (string, error) { } } -// func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) (K_encr string, K_aut string, K_re string, -// MSK string, EMSK string) { func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) ([]byte, []byte, []byte, []byte, []byte) { keyAp := ikPrime + ckPrime From 44f7cfdd06e7ee81d3577d2704a9b16a96ccfd86 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Sun, 9 Jun 2024 13:32:43 +0800 Subject: [PATCH 07/16] fix: align naming convention --- go.mod | 3 --- internal/sbi/consumer/nrf_service.go | 2 +- internal/sbi/server.go | 6 +++++- pkg/service/init.go | 22 +++++++++++----------- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 95e5734..37e0437 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/google/uuid v1.3.0 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.8.1 - github.com/stretchr/testify v1.8.3 github.com/urfave/cli v1.22.5 gopkg.in/yaml.v2 v2.4.0 ) @@ -22,7 +21,6 @@ require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -40,7 +38,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go index 2040f84..73285c5 100644 --- a/internal/sbi/consumer/nrf_service.go +++ b/internal/sbi/consumer/nrf_service.go @@ -150,7 +150,7 @@ func (s *nnrfService) RegisterNFInstance(ctx context.Context) ( var nf models.NfProfile var res *http.Response for { - nf, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), ausfContext.NfId, nfProfile) + nf, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(ctx, ausfContext.NfId, nfProfile) if err != nil || res == nil { logger.ConsumerLog.Errorf("AUSF register to NRF Error[%v]", err) time.Sleep(2 * time.Second) diff --git a/internal/sbi/server.go b/internal/sbi/server.go index a4db49f..aaab0cc 100644 --- a/internal/sbi/server.go +++ b/internal/sbi/server.go @@ -78,7 +78,11 @@ func (s *Server) Run(traceCtx context.Context, wg *sync.WaitGroup) error { return nil } -func (s *Server) Stop() { +func (s *Server) Shutdown() { + s.shutdownHttpServer() +} + +func (s *Server) shutdownHttpServer() { const defaultShutdownTimeout time.Duration = 2 * time.Second if s.httpServer != nil { diff --git a/pkg/service/init.go b/pkg/service/init.go index f4f8217..b69683a 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -93,7 +93,7 @@ func (a *AusfApp) Config() *factory.Config { return a.cfg } -func (c *AusfApp) SetLogEnable(enable bool) { +func (a *AusfApp) SetLogEnable(enable bool) { logger.MainLog.Infof("Log enable is set to [%v]", enable) if enable && logger.Log.Out == os.Stderr { return @@ -101,7 +101,7 @@ func (c *AusfApp) SetLogEnable(enable bool) { return } - c.Config().SetLogEnable(enable) + a.Config().SetLogEnable(enable) if enable { logger.Log.SetOutput(os.Stderr) } else { @@ -109,7 +109,7 @@ func (c *AusfApp) SetLogEnable(enable bool) { } } -func (c *AusfApp) SetLogLevel(level string) { +func (a *AusfApp) SetLogLevel(level string) { lvl, err := logrus.ParseLevel(level) if err != nil { logger.MainLog.Warnf("Log level [%s] is invalid", level) @@ -121,17 +121,17 @@ func (c *AusfApp) SetLogLevel(level string) { return } - c.Config().SetLogLevel(level) + a.Config().SetLogLevel(level) logger.Log.SetLevel(lvl) } -func (c *AusfApp) SetReportCaller(reportCaller bool) { +func (a *AusfApp) SetReportCaller(reportCaller bool) { logger.MainLog.Infof("Report Caller is set to [%v]", reportCaller) if reportCaller == logger.Log.ReportCaller { return } - c.Config().SetLogReportCaller(reportCaller) + a.Config().SetLogReportCaller(reportCaller) logger.Log.SetReportCaller(reportCaller) } @@ -160,13 +160,13 @@ func (a *AusfApp) listenShutdownEvent() { a.Terminate() } -func (c *AusfApp) Terminate() { +func (a *AusfApp) Terminate() { logger.MainLog.Infof("Terminating AUSF...") - c.cancel() - c.CallServerStop() + a.cancel() + a.CallServerStop() // deregister with NRF - problemDetails, err := c.Consumer().SendDeregisterNFInstance() + problemDetails, err := a.Consumer().SendDeregisterNFInstance() if problemDetails != nil { logger.MainLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -179,7 +179,7 @@ func (c *AusfApp) Terminate() { func (a *AusfApp) CallServerStop() { if a.sbiServer != nil { - a.sbiServer.Stop() + a.sbiServer.Shutdown() } } From c6ace2befdd30b48855f6b02bc73ec077d22599e Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Mon, 17 Jun 2024 03:17:07 +0800 Subject: [PATCH 08/16] fix: add sorprotection and upuprotection routes --- internal/sbi/api_sorprotection.go | 15 +++++++++++++++ internal/sbi/api_upuprotection.go | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/internal/sbi/api_sorprotection.go b/internal/sbi/api_sorprotection.go index 09799d1..a24b8b0 100644 --- a/internal/sbi/api_sorprotection.go +++ b/internal/sbi/api_sorprotection.go @@ -6,6 +6,21 @@ import ( "github.com/gin-gonic/gin" ) +func (s *Server) getSorprotectionRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: Index, + }, + { + Method: http.MethodPost, + Pattern: "/:supi/ue-sor", + APIFunc: s.SupiUeSorPost, + }, + } +} + func (s *Server) SupiUeSorPost(c *gin.Context) { c.JSON(http.StatusOK, gin.H{}) } diff --git a/internal/sbi/api_upuprotection.go b/internal/sbi/api_upuprotection.go index 473ef3d..36a8d0f 100644 --- a/internal/sbi/api_upuprotection.go +++ b/internal/sbi/api_upuprotection.go @@ -6,6 +6,21 @@ import ( "github.com/gin-gonic/gin" ) +func (s *Server) getUpuprotectionRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: Index, + }, + { + Method: http.MethodPost, + Pattern: "/:supi/ue-upu", + APIFunc: s.SupiUeUpuPost, + }, + } +} + func (s *Server) SupiUeUpuPost(c *gin.Context) { c.JSON(http.StatusOK, gin.H{}) } From de42b01a4ddbcfbd48e2b080f2ef8c07c7ebdd89 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Mon, 17 Jun 2024 03:18:24 +0800 Subject: [PATCH 09/16] refactor: add routes to newRouter --- internal/sbi/server.go | 44 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/internal/sbi/server.go b/internal/sbi/server.go index aaab0cc..22e6fa7 100644 --- a/internal/sbi/server.go +++ b/internal/sbi/server.go @@ -41,16 +41,9 @@ type Server struct { func NewServer(ausf ServerAusf, tlsKeyLogPath string) (*Server, error) { s := &Server{ ServerAusf: ausf, - router: logger_util.NewGinWithLogrus(logger.GinLog), } - routes := s.getUeAuthenticationRoutes() - group := s.router.Group(factory.AusfAuthResUriPrefix) - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_AUTH) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) - }) - applyRoutes(group, routes) + s.router = newRouter(s) cfg := s.Config() bindAddr := cfg.GetSbiBindingAddr() @@ -65,6 +58,41 @@ func NewServer(ausf ServerAusf, tlsKeyLogPath string) (*Server, error) { return s, nil } +func newRouter(s *Server) *gin.Engine { + router := logger_util.NewGinWithLogrus(logger.GinLog) + + for _, serverName := range factory.AusfConfig.Configuration.ServiceNameList { + switch models.ServiceName(serverName) { + case models.ServiceName_NAUSF_AUTH: + ausfUeAuthenticationGroup := router.Group(factory.AusfAuthResUriPrefix) + ausfUeAuthenticationRoutes := s.getUeAuthenticationRoutes() + routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_AUTH) + ausfUeAuthenticationGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) + }) + applyRoutes(ausfUeAuthenticationGroup, ausfUeAuthenticationRoutes) + case models.ServiceName_NAUSF_SORPROTECTION: + ausfSorprotectionGroup := router.Group(factory.AusfSorprotectionResUriPrefix) + ausfSorprotectionRoutes := s.getSorprotectionRoutes() + routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_SORPROTECTION) + ausfSorprotectionGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) + }) + applyRoutes(ausfSorprotectionGroup, ausfSorprotectionRoutes) + case models.ServiceName_NAUSF_UPUPROTECTION: + ausfUpuprotectionGroup := router.Group(factory.AusfUpuprotectionResUriPrefix) + ausfUpuprotectionRoutes := s.getUpuprotectionRoutes() + routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAUSF_UPUPROTECTION) + ausfUpuprotectionGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, ausf_context.GetSelf()) + }) + applyRoutes(ausfUpuprotectionGroup, ausfUpuprotectionRoutes) + } + } + + return router +} + func (s *Server) Run(traceCtx context.Context, wg *sync.WaitGroup) error { var err error _, s.Context().NfId, err = s.Consumer().RegisterNFInstance(context.Background()) From 7f58f5f0e48a58d41b99bd4a73845da1ff8d4901 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Mon, 17 Jun 2024 23:26:14 +0800 Subject: [PATCH 10/16] fix: assign consumer --- internal/sbi/consumer/consumer.go | 1 + internal/sbi/consumer/nrf_service.go | 32 +++++++++++++++------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/internal/sbi/consumer/consumer.go b/internal/sbi/consumer/consumer.go index dea5304..6566109 100644 --- a/internal/sbi/consumer/consumer.go +++ b/internal/sbi/consumer/consumer.go @@ -32,5 +32,6 @@ func NewConsumer(ausf ConsumerAusf) (*Consumer, error) { nfMngmntClients: make(map[string]*Nnrf_NFManagement.APIClient), nfDiscClients: make(map[string]*Nnrf_NFDiscovery.APIClient), } + consumer = c return c, nil } diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go index 73285c5..a4b9cde 100644 --- a/internal/sbi/consumer/nrf_service.go +++ b/internal/sbi/consumer/nrf_service.go @@ -10,7 +10,6 @@ import ( "github.com/pkg/errors" - // "github.com/free5gc/openapi/nrf/NFManagement" // R17 ausf_context "github.com/free5gc/ausf/internal/context" "github.com/free5gc/ausf/internal/logger" "github.com/free5gc/openapi" @@ -74,33 +73,36 @@ func (s *nnrfService) getNFDiscClient(uri string) *Nnrf_NFDiscovery.APIClient { } func (s *nnrfService) SendSearchNFInstances( - nrfUri string, targetNfType, requestNfType models.NfType, param Nnrf_NFDiscovery.SearchNFInstancesParamOpts) ( + nrfUri string, targetNfType, requestNfType models.NfType, param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts) ( *models.SearchResult, error, ) { // Set client and set url - ausfContext := s.consumer.Context() - - client := s.getNFDiscClient(ausfContext.NrfUri) + client := s.getNFDiscClient(nrfUri) + if client == nil { + return nil, openapi.ReportError("nrf not found") + } ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF) if err != nil { return nil, err } - result, res, err := client.NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, requestNfType, ¶m) - if err != nil { - logger.ConsumerLog.Errorf("SearchNFInstances failed: %+v", err) + result, res, err := client.NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, requestNfType, param) + + if res != nil && res.StatusCode == http.StatusTemporaryRedirect { + return nil, fmt.Errorf("temporary Redirect For Non NRF Consumer") + } + if res == nil || res.Body == nil { + return &result, err } defer func() { - if resCloseErr := res.Body.Close(); resCloseErr != nil { - logger.ConsumerLog.Errorf("NFInstancesStoreApi response body cannot close: %+v", resCloseErr) + if res != nil { + if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { + err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) + } } }() - if res != nil && res.StatusCode == http.StatusTemporaryRedirect { - return nil, fmt.Errorf("Temporary Redirect For Non NRF Consumer") - } - - return &result, nil + return &result, err } func (s *nnrfService) SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err error) { From 7ec201b32f8fe794e7ca22f96f21206173e9a021 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Mon, 17 Jun 2024 23:28:10 +0800 Subject: [PATCH 11/16] fix: add header --- internal/sbi/processor/ue_authentication.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/sbi/processor/ue_authentication.go b/internal/sbi/processor/ue_authentication.go index 7dce976..3360c04 100644 --- a/internal/sbi/processor/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -54,11 +54,10 @@ func (p *Processor) HandleUeAuthPostRequest(c *gin.Context, authenticationInfo m logger.UeAuthLog.Infof("HandleUeAuthPostRequest") response, locationURI, problemDetails := p.UeAuthPostRequestProcedure(authenticationInfo) - respHeader := make(http.Header) - respHeader.Set("Location", locationURI) + c.Header("Location", locationURI) if response != nil { - c.JSON(http.StatusOK, response) + c.JSON(http.StatusCreated, response) return } else if problemDetails != nil { c.JSON(int(problemDetails.Status), problemDetails) @@ -883,7 +882,7 @@ func getUdmUrl(nrfUri string) string { nrfUri, models.NfType_UDM, models.NfType_AUSF, - nfDiscoverParam, + &nfDiscoverParam, ) if err != nil { logger.UeAuthLog.Errorln("[Search UDM UEAU] ", err.Error()) From ca00f22f54460da124bac6a2e506693e7db00578 Mon Sep 17 00:00:00 2001 From: "CTFang@WireLab" Date: Fri, 21 Jun 2024 05:08:35 +0000 Subject: [PATCH 12/16] fix: terminate procedure and unecessary defer --- cmd/main.go | 1 - internal/sbi/consumer/nrf_service.go | 4 ++-- pkg/service/init.go | 11 ++++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index acbfef8..2f30a2c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -87,7 +87,6 @@ func action(cliCtx *cli.Context) error { AUSF = ausf ausf.Start() - AUSF.WaitRoutineStopped() return nil } diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go index a4b9cde..f2fed16 100644 --- a/internal/sbi/consumer/nrf_service.go +++ b/internal/sbi/consumer/nrf_service.go @@ -35,7 +35,7 @@ func (s *nnrfService) getNFManagementClient(uri string) *Nnrf_NFManagement.APICl s.nfMngmntMu.RLock() client, ok := s.nfMngmntClients[uri] if ok { - defer s.nfMngmntMu.RUnlock() + s.nfMngmntMu.RUnlock() return client } @@ -57,7 +57,7 @@ func (s *nnrfService) getNFDiscClient(uri string) *Nnrf_NFDiscovery.APIClient { s.nfDiscMu.RLock() client, ok := s.nfDiscClients[uri] if ok { - defer s.nfDiscMu.RUnlock() + s.nfDiscMu.RUnlock() return client } diff --git a/pkg/service/init.go b/pkg/service/init.go index b69683a..b2052cc 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -145,6 +145,7 @@ func (a *AusfApp) Start() { if err := a.sbiServer.Run(context.Background(), &a.wg); err != nil { logger.MainLog.Fatalf("Run SBI server failed: %+v", err) } + a.WaitRoutineStopped() } func (a *AusfApp) listenShutdownEvent() { @@ -157,13 +158,15 @@ func (a *AusfApp) listenShutdownEvent() { }() <-a.ctx.Done() - a.Terminate() + a.terminateProcedure() } func (a *AusfApp) Terminate() { - logger.MainLog.Infof("Terminating AUSF...") a.cancel() - a.CallServerStop() +} + +func (a *AusfApp) terminateProcedure() { + logger.MainLog.Infof("Terminating AUSF...") // deregister with NRF problemDetails, err := a.Consumer().SendDeregisterNFInstance() @@ -175,6 +178,8 @@ func (a *AusfApp) Terminate() { logger.MainLog.Infof("Deregister from NRF successfully") } logger.MainLog.Infof("AUSF SBI Server terminated") + + a.CallServerStop() } func (a *AusfApp) CallServerStop() { From 60a2dde281492f2ea6a117a8e07de60c647c17ab Mon Sep 17 00:00:00 2001 From: "CTFang@WireLab" Date: Fri, 21 Jun 2024 06:09:16 +0000 Subject: [PATCH 13/16] refactor: add UDM service consumer --- internal/sbi/consumer/consumer.go | 8 ++ internal/sbi/consumer/nrf_service.go | 28 +++++ internal/sbi/consumer/udm_service.go | 107 +++++++++++++++++++ internal/sbi/processor/processor.go | 7 +- internal/sbi/processor/ue_authentication.go | 111 +++----------------- pkg/service/init.go | 5 - 6 files changed, 164 insertions(+), 102 deletions(-) create mode 100644 internal/sbi/consumer/udm_service.go diff --git a/internal/sbi/consumer/consumer.go b/internal/sbi/consumer/consumer.go index 6566109..ae286ba 100644 --- a/internal/sbi/consumer/consumer.go +++ b/internal/sbi/consumer/consumer.go @@ -4,6 +4,7 @@ import ( "github.com/free5gc/ausf/pkg/app" "github.com/free5gc/openapi/Nnrf_NFDiscovery" "github.com/free5gc/openapi/Nnrf_NFManagement" + "github.com/free5gc/openapi/Nudm_UEAuthentication" ) var consumer *Consumer @@ -16,6 +17,7 @@ type Consumer struct { ConsumerAusf *nnrfService + *nudmService } func GetConsumer() *Consumer { @@ -32,6 +34,12 @@ func NewConsumer(ausf ConsumerAusf) (*Consumer, error) { nfMngmntClients: make(map[string]*Nnrf_NFManagement.APIClient), nfDiscClients: make(map[string]*Nnrf_NFDiscovery.APIClient), } + + c.nudmService = &nudmService{ + consumer: c, + ueauClients: make(map[string]*Nudm_UEAuthentication.APIClient), + } + consumer = c return c, nil } diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go index f2fed16..e8b6757 100644 --- a/internal/sbi/consumer/nrf_service.go +++ b/internal/sbi/consumer/nrf_service.go @@ -4,10 +4,12 @@ import ( "context" "fmt" "net/http" + "strconv" "strings" "sync" "time" + "github.com/antihax/optional" "github.com/pkg/errors" ausf_context "github.com/free5gc/ausf/internal/context" @@ -221,3 +223,29 @@ func (s *nnrfService) buildNfProfile(ausfContext *ausf_context.AUSFContext) (pro } return } + +func (s *nnrfService) GetUdmUrl(nrfUri string) string { + udmUrl := "https://localhost:29503" // default + nfDiscoverParam := &Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ + ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NUDM_UEAU}), + } + res, err := s.SendSearchNFInstances( + nrfUri, + models.NfType_UDM, + models.NfType_AUSF, + nfDiscoverParam, + ) + if err != nil { + logger.ConsumerLog.Errorln("[Search UDM UEAU] ", err.Error(), "use defalt udmUrl", udmUrl) + } else if len(res.NfInstances) > 0 { + udmInstance := res.NfInstances[0] + if len(udmInstance.Ipv4Addresses) > 0 && udmInstance.NfServices != nil { + ueauService := (*udmInstance.NfServices)[0] + ueauEndPoint := (*ueauService.IpEndPoints)[0] + udmUrl = string(ueauService.Scheme) + "://" + ueauEndPoint.Ipv4Address + ":" + strconv.Itoa(int(ueauEndPoint.Port)) + } + } else { + logger.ConsumerLog.Errorln("[Search UDM UEAU] len(NfInstances) = 0") + } + return udmUrl +} diff --git a/internal/sbi/consumer/udm_service.go b/internal/sbi/consumer/udm_service.go new file mode 100644 index 0000000..69e2603 --- /dev/null +++ b/internal/sbi/consumer/udm_service.go @@ -0,0 +1,107 @@ +package consumer + +import ( + "sync" + "time" + + ausf_context "github.com/free5gc/ausf/internal/context" + "github.com/free5gc/ausf/internal/logger" + Nudm_UEAU "github.com/free5gc/openapi/Nudm_UEAuthentication" + "github.com/free5gc/openapi/models" +) + +type nudmService struct { + consumer *Consumer + + ueauMu sync.RWMutex + + ueauClients map[string]*Nudm_UEAU.APIClient +} + +func (s *nudmService) getUdmUeauClient(uri string) *Nudm_UEAU.APIClient { + if uri == "" { + return nil + } + s.ueauMu.RLock() + client, ok := s.ueauClients[uri] + if ok { + s.ueauMu.RUnlock() + return client + } + + configuration := Nudm_UEAU.NewConfiguration() + configuration.SetBasePath(uri) + client = Nudm_UEAU.NewAPIClient(configuration) + + s.ueauMu.RUnlock() + s.ueauMu.Lock() + defer s.ueauMu.Unlock() + s.ueauClients[uri] = client + return client +} + +func (s *nudmService) SendAuthResultToUDM( + id string, + authType models.AuthType, + success bool, + servingNetworkName, udmUrl string, +) error { + timeNow := time.Now() + timePtr := &timeNow + + self := s.consumer.Context() + + authEvent := models.AuthEvent{ + TimeStamp: timePtr, + AuthType: authType, + Success: success, + ServingNetworkName: servingNetworkName, + NfInstanceId: self.GetSelfID(), + } + + client := s.getUdmUeauClient(udmUrl) + + ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) + if err != nil { + return err + } + + _, rsp, confirmAuthErr := client.ConfirmAuthApi.ConfirmAuth(ctx, id, authEvent) + defer func() { + if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("ConfirmAuth Response cannot close: %v", rspCloseErr) + } + }() + return confirmAuthErr +} + +func (s *nudmService) GenerateAuthDataApi( + udmUrl string, + supiOrSuci string, + authInfoReq models.AuthenticationInfoRequest, +) (*models.AuthenticationInfoResult, error, *models.ProblemDetails) { + client := s.getUdmUeauClient(udmUrl) + + ctx, pd, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) + if err != nil { + return nil, err, pd + } + + authInfoResult, rsp, err := client.GenerateAuthDataApi.GenerateAuthData(ctx, supiOrSuci, authInfoReq) + if err != nil { + var problemDetails models.ProblemDetails + if authInfoResult.AuthenticationVector == nil { + problemDetails.Cause = "AV_GENERATION_PROBLEM" + } else { + problemDetails.Cause = "UPSTREAM_SERVER_ERROR" + } + problemDetails.Status = int32(rsp.StatusCode) + return nil, err, &problemDetails + } + defer func() { + if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { + logger.UeAuthLog.Errorf("GenerateAuthDataApi response body cannot close: %+v", rspCloseErr) + } + }() + return &authInfoResult, nil, nil +} diff --git a/internal/sbi/processor/processor.go b/internal/sbi/processor/processor.go index 2ddabdb..610fbc6 100644 --- a/internal/sbi/processor/processor.go +++ b/internal/sbi/processor/processor.go @@ -1,9 +1,14 @@ package processor -import "github.com/free5gc/ausf/pkg/app" +import ( + "github.com/free5gc/ausf/internal/sbi/consumer" + "github.com/free5gc/ausf/pkg/app" +) type ProcessorAusf interface { app.App + + Consumer() *consumer.Consumer } type Processor struct { diff --git a/internal/sbi/processor/ue_authentication.go b/internal/sbi/processor/ue_authentication.go index 3360c04..f2c0744 100644 --- a/internal/sbi/processor/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -15,7 +15,6 @@ import ( "strings" "time" - "github.com/antihax/optional" "github.com/bronze1man/radius" "github.com/gin-gonic/gin" "github.com/google/gopacket" @@ -23,10 +22,7 @@ import ( ausf_context "github.com/free5gc/ausf/internal/context" "github.com/free5gc/ausf/internal/logger" - "github.com/free5gc/ausf/internal/sbi/consumer" "github.com/free5gc/ausf/pkg/factory" - "github.com/free5gc/openapi/Nnrf_NFDiscovery" - Nudm_UEAU "github.com/free5gc/openapi/Nudm_UEAuthentication" "github.com/free5gc/openapi/models" "github.com/free5gc/util/ueauth" ) @@ -132,31 +128,14 @@ func (p *Processor) UeAuthPostRequestProcedure( lastEapID = ausfCurrentContext.EapID } - udmUrl := getUdmUrl(self.NrfUri) - client := createClientToUdmUeau(udmUrl) + udmUrl := p.Consumer().GetUdmUrl(self.NrfUri) - ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) + result, err, pd := p.Consumer().GenerateAuthDataApi(udmUrl, supiOrSuci, authInfoReq) if err != nil { - return nil, "", nil + logger.UeAuthLog.Infof("GenerateAuthDataApi error: %+v", err) + return nil, "", pd } - - authInfoResult, rsp, err := client.GenerateAuthDataApi.GenerateAuthData(ctx, supiOrSuci, authInfoReq) - if err != nil { - logger.UeAuthLog.Infoln(err.Error()) - var problemDetails models.ProblemDetails - if authInfoResult.AuthenticationVector == nil { - problemDetails.Cause = "AV_GENERATION_PROBLEM" - } else { - problemDetails.Cause = "UPSTREAM_SERVER_ERROR" - } - problemDetails.Status = int32(rsp.StatusCode) - return nil, "", &problemDetails - } - defer func() { - if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { - logger.UeAuthLog.Errorf("GenerateAuthDataApi response body cannot close: %+v", rspCloseErr) - } - }() + authInfoResult := *result ueid := authInfoResult.Supi ausfUeContext := ausf_context.NewAusfUeContext(ueid) @@ -376,11 +355,11 @@ func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData mode } else { ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE responseBody.AuthResult = models.AuthResult_FAILURE - logConfirmFailureAndInformUDM(ConfirmationDataResponseID, models.AuthType__5_G_AKA, servingNetworkName, + p.logConfirmFailureAndInformUDM(ConfirmationDataResponseID, models.AuthType__5_G_AKA, servingNetworkName, "5G AKA confirmation failed", ausfCurrentContext.UdmUeauUrl) } - if sendErr := sendAuthResultToUDM(currentSupi, models.AuthType__5_G_AKA, success, servingNetworkName, + if sendErr := p.Consumer().SendAuthResultToUDM(currentSupi, models.AuthType__5_G_AKA, success, servingNetworkName, ausfCurrentContext.UdmUeauUrl); sendErr != nil { logger.Auth5gAkaLog.Infoln(sendErr.Error()) var problemDetails models.ProblemDetails @@ -474,7 +453,7 @@ func (p *Processor) EapAuthComfirmRequestProcedure( eapSuccPkt := ConstructEapNoTypePkt(radius.EapCodeSuccess, eapContent.Id) responseBody.EapPayload = eapSuccPkt udmUrl := ausfCurrentContext.UdmUeauUrl - if sendErr := sendAuthResultToUDM( + if sendErr := p.Consumer().SendAuthResultToUDM( eapSessionID, models.AuthType_EAP_AKA_PRIME, true, @@ -528,7 +507,7 @@ func (p *Processor) EapAuthComfirmRequestProcedure( if !eapOK { logger.AuthELog.Warnf("EAP-AKA' failure: %s", eapErrStr) - if sendErr := sendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, + if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, ausfCurrentContext.UdmUeauUrl); sendErr != nil { logger.AuthELog.Infoln(sendErr.Error()) var problemDetails models.ProblemDetails @@ -548,7 +527,7 @@ func (p *Processor) EapAuthComfirmRequestProcedure( responseBody.Links = make(map[string]models.LinksValueSchema) responseBody.Links["eap-session"] = linksValue } else if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { - if sendErr := sendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, + if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, ausfCurrentContext.UdmUeauUrl); sendErr != nil { logger.AuthELog.Infoln(sendErr.Error()) var problemDetails models.ProblemDetails @@ -873,77 +852,17 @@ func ConstructEapNoTypePkt(code radius.EapCode, pktID uint8) string { return base64.StdEncoding.EncodeToString(b) } -func getUdmUrl(nrfUri string) string { - udmUrl := "https://localhost:29503" // default - nfDiscoverParam := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ - ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NUDM_UEAU}), - } - res, err := consumer.GetConsumer().SendSearchNFInstances( - nrfUri, - models.NfType_UDM, - models.NfType_AUSF, - &nfDiscoverParam, - ) - if err != nil { - logger.UeAuthLog.Errorln("[Search UDM UEAU] ", err.Error()) - } else if len(res.NfInstances) > 0 { - udmInstance := res.NfInstances[0] - if len(udmInstance.Ipv4Addresses) > 0 && udmInstance.NfServices != nil { - ueauService := (*udmInstance.NfServices)[0] - ueauEndPoint := (*ueauService.IpEndPoints)[0] - udmUrl = string(ueauService.Scheme) + "://" + ueauEndPoint.Ipv4Address + ":" + strconv.Itoa(int(ueauEndPoint.Port)) - } - } else { - logger.UeAuthLog.Errorln("[Search UDM UEAU] len(NfInstances) = 0") - } - return udmUrl -} - -func createClientToUdmUeau(udmUrl string) *Nudm_UEAU.APIClient { - cfg := Nudm_UEAU.NewConfiguration() - cfg.SetBasePath(udmUrl) - clientAPI := Nudm_UEAU.NewAPIClient(cfg) - return clientAPI -} - -func sendAuthResultToUDM(id string, authType models.AuthType, success bool, servingNetworkName, udmUrl string) error { - timeNow := time.Now() - timePtr := &timeNow - - self := ausf_context.GetSelf() - - var authEvent models.AuthEvent - authEvent.TimeStamp = timePtr - authEvent.AuthType = authType - authEvent.Success = success - authEvent.ServingNetworkName = servingNetworkName - authEvent.NfInstanceId = self.GetSelfID() - - client := createClientToUdmUeau(udmUrl) - - ctx, _, err := ausf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) - if err != nil { - return err - } - - _, rsp, confirmAuthErr := client.ConfirmAuthApi.ConfirmAuth(ctx, id, authEvent) - defer func() { - if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("ConfirmAuth Response cannot close: %v", rspCloseErr) - } - }() - return confirmAuthErr -} - -func logConfirmFailureAndInformUDM(id string, authType models.AuthType, servingNetworkName, errStr, udmUrl string) { +func (p *Processor) logConfirmFailureAndInformUDM( + id string, authType models.AuthType, servingNetworkName, errStr, udmUrl string, +) { if authType == models.AuthType__5_G_AKA { logger.Auth5gAkaLog.Infoln(errStr) - if sendErr := sendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { + if sendErr := p.Consumer().SendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { logger.Auth5gAkaLog.Infoln(sendErr.Error()) } } else if authType == models.AuthType_EAP_AKA_PRIME { logger.AuthELog.Infoln(errStr) - if sendErr := sendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { + if sendErr := p.Consumer().SendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { logger.AuthELog.Infoln(sendErr.Error()) } } diff --git a/pkg/service/init.go b/pkg/service/init.go index b2052cc..052a008 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -23,11 +23,6 @@ var AUSF *AusfApp var _ app.App = &AusfApp{} type AusfApp struct { - app.App - consumer.ConsumerAusf - processor.ProcessorAusf - sbi.ServerAusf - ausfCtx *ausf_context.AUSFContext cfg *factory.Config From 4fdd4bd6de40a33c2cb2b731fcf435e5ac974b5b Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Sat, 22 Jun 2024 17:21:01 +0800 Subject: [PATCH 14/16] fix: remove GetConsumer() and add http.NotImplement --- internal/sbi/api_sorprotection.go | 2 +- internal/sbi/api_upuprotection.go | 2 +- internal/sbi/consumer/consumer.go | 7 ------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/internal/sbi/api_sorprotection.go b/internal/sbi/api_sorprotection.go index a24b8b0..ff5ebf3 100644 --- a/internal/sbi/api_sorprotection.go +++ b/internal/sbi/api_sorprotection.go @@ -22,5 +22,5 @@ func (s *Server) getSorprotectionRoutes() []Route { } func (s *Server) SupiUeSorPost(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{}) + c.JSON(http.StatusNotImplemented, gin.H{}) } diff --git a/internal/sbi/api_upuprotection.go b/internal/sbi/api_upuprotection.go index 36a8d0f..856ebf1 100644 --- a/internal/sbi/api_upuprotection.go +++ b/internal/sbi/api_upuprotection.go @@ -22,5 +22,5 @@ func (s *Server) getUpuprotectionRoutes() []Route { } func (s *Server) SupiUeUpuPost(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{}) + c.JSON(http.StatusNotImplemented, gin.H{}) } diff --git a/internal/sbi/consumer/consumer.go b/internal/sbi/consumer/consumer.go index ae286ba..a0cd457 100644 --- a/internal/sbi/consumer/consumer.go +++ b/internal/sbi/consumer/consumer.go @@ -7,8 +7,6 @@ import ( "github.com/free5gc/openapi/Nudm_UEAuthentication" ) -var consumer *Consumer - type ConsumerAusf interface { app.App } @@ -20,10 +18,6 @@ type Consumer struct { *nudmService } -func GetConsumer() *Consumer { - return consumer -} - func NewConsumer(ausf ConsumerAusf) (*Consumer, error) { c := &Consumer{ ConsumerAusf: ausf, @@ -40,6 +34,5 @@ func NewConsumer(ausf ConsumerAusf) (*Consumer, error) { ueauClients: make(map[string]*Nudm_UEAuthentication.APIClient), } - consumer = c return c, nil } From ec36f63b1de488b9bd4f2099c9d43ba41c793791 Mon Sep 17 00:00:00 2001 From: TYuan0816 Date: Fri, 28 Jun 2024 01:24:11 +0800 Subject: [PATCH 15/16] fix: refactor processor --- internal/sbi/processor/ue_authentication.go | 493 +++++++++----------- 1 file changed, 228 insertions(+), 265 deletions(-) diff --git a/internal/sbi/processor/ue_authentication.go b/internal/sbi/processor/ue_authentication.go index f2c0744..d4894f2 100644 --- a/internal/sbi/processor/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -30,68 +30,187 @@ import ( func (p *Processor) HandleEapAuthComfirmRequest(c *gin.Context, eapSession models.EapSession, eapSessionId string) { logger.Auth5gAkaLog.Infof("EapAuthComfirmRequest") - response, problemDetails := p.EapAuthComfirmRequestProcedure(eapSession, eapSessionId) + p.EapAuthComfirmRequestProcedure(c, eapSession, eapSessionId) +} - if response != nil { - c.JSON(http.StatusOK, response) - return - } else if problemDetails != nil { - c.JSON(int(problemDetails.Status), problemDetails) +func (p *Processor) EapAuthComfirmRequestProcedure( + c *gin.Context, + updateEapSession models.EapSession, + eapSessionID string, +) { + var responseBody models.EapSession + + if !ausf_context.CheckIfSuciSupiPairExists(eapSessionID) { + logger.AuthELog.Infoln("supiSuciPair does not exist, confirmation failed") + problemDetails := models.ProblemDetails{ + Cause: "USER_NOT_FOUND", + } + c.JSON(http.StatusNotFound, problemDetails) return } - problemDetails = &models.ProblemDetails{ - Status: http.StatusForbidden, - Cause: "UNSPECIFIED", - } - c.JSON(int(problemDetails.Status), problemDetails) -} -func (p *Processor) HandleUeAuthPostRequest(c *gin.Context, authenticationInfo models.AuthenticationInfo) { - logger.UeAuthLog.Infof("HandleUeAuthPostRequest") + currentSupi := ausf_context.GetSupiFromSuciSupiMap(eapSessionID) + if !ausf_context.CheckIfAusfUeContextExists(currentSupi) { + logger.AuthELog.Infoln("SUPI does not exist, confirmation failed") + problemDetails := models.ProblemDetails{ + Cause: "USER_NOT_FOUND", + } + c.JSON(http.StatusNotFound, problemDetails) + return + } - response, locationURI, problemDetails := p.UeAuthPostRequestProcedure(authenticationInfo) - c.Header("Location", locationURI) + ausfCurrentContext := ausf_context.GetAusfUeContext(currentSupi) + servingNetworkName := ausfCurrentContext.ServingNetworkName - if response != nil { - c.JSON(http.StatusCreated, response) - return - } else if problemDetails != nil { - c.JSON(int(problemDetails.Status), problemDetails) + if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { + logger.AuthELog.Warnf("Authentication failed with status: %s", ausfCurrentContext.AuthStatus) + eapFailPkt := ConstructEapNoTypePkt(radius.EapCodeFailure, 0) + responseBody.EapPayload = eapFailPkt + responseBody.AuthResult = models.AuthResult_FAILURE + c.JSON(http.StatusUnauthorized, responseBody) return } - problemDetails = &models.ProblemDetails{ - Status: http.StatusForbidden, - Cause: "UNSPECIFIED", + + var eapPayload []byte + if eapPayloadTmp, err := base64.StdEncoding.DecodeString(updateEapSession.EapPayload); err != nil { + logger.AuthELog.Warnf("EAP Payload decode failed: %+v", err) + } else { + eapPayload = eapPayloadTmp } - c.JSON(int(problemDetails.Status), problemDetails) -} -func (p *Processor) HandleAuth5gAkaComfirmRequest( - c *gin.Context, - confirmationData models.ConfirmationData, - confirmationDataResponseId string, -) { - logger.Auth5gAkaLog.Infof("Auth5gAkaComfirmRequest") + eapGoPkt := gopacket.NewPacket(eapPayload, layers.LayerTypeEAP, gopacket.Default) + eapLayer := eapGoPkt.Layer(layers.LayerTypeEAP) + eapContent, _ := eapLayer.(*layers.EAP) + eapOK := true + var eapErrStr string - response, problemDetails := p.Auth5gAkaComfirmRequestProcedure(confirmationData, confirmationDataResponseId) + if eapContent.Code != layers.EAPCodeResponse { + eapOK = false + eapErrStr = "eap packet code error" + } else if eapContent.Type != ausf_context.EAP_AKA_PRIME_TYPENUM { + eapOK = false + eapErrStr = "eap packet type error" + } else if decodeEapAkaPrimePkt, err := decodeEapAkaPrime(eapContent.Contents); err != nil { + logger.AuthELog.Warnf("EAP-AKA' decode failed: %+v", err) + eapOK = false + eapErrStr = "eap packet error" + } else { + switch decodeEapAkaPrimePkt.Subtype { + case ausf_context.AKA_CHALLENGE_SUBTYPE: + K_autStr := ausfCurrentContext.K_aut + var K_aut []byte + if K_autTmp, err := hex.DecodeString(K_autStr); err != nil { + logger.AuthELog.Warnf("K_aut decode error: %+v", err) + } else { + K_aut = K_autTmp + } + XMAC := CalculateAtMAC(K_aut, decodeEapAkaPrimePkt.MACInput) + MAC := decodeEapAkaPrimePkt.Attributes[ausf_context.AT_MAC_ATTRIBUTE].Value + XRES := ausfCurrentContext.XRES + RES := hex.EncodeToString(decodeEapAkaPrimePkt.Attributes[ausf_context.AT_RES_ATTRIBUTE].Value) - if response != nil { - c.JSON(http.StatusOK, response) - return - } else if problemDetails != nil { - c.JSON(int(problemDetails.Status), problemDetails) - return + if !bytes.Equal(MAC, XMAC) { + eapOK = false + eapErrStr = "EAP-AKA' integrity check fail" + } else if XRES == RES { + logger.AuthELog.Infoln("Correct RES value, EAP-AKA' auth succeed") + responseBody.KSeaf = ausfCurrentContext.Kseaf + responseBody.Supi = currentSupi + responseBody.AuthResult = models.AuthResult_SUCCESS + eapSuccPkt := ConstructEapNoTypePkt(radius.EapCodeSuccess, eapContent.Id) + responseBody.EapPayload = eapSuccPkt + udmUrl := ausfCurrentContext.UdmUeauUrl + if sendErr := p.Consumer().SendAuthResultToUDM( + eapSessionID, + models.AuthType_EAP_AKA_PRIME, + true, + servingNetworkName, + udmUrl); sendErr != nil { + logger.AuthELog.Infoln(sendErr.Error()) + problemDetails := models.ProblemDetails{ + Cause: "UPSTREAM_SERVER_ERROR", + } + c.JSON(http.StatusInternalServerError, problemDetails) + } + ausfCurrentContext.AuthStatus = models.AuthResult_SUCCESS + } else { + eapOK = false + eapErrStr = "Wrong RES value, EAP-AKA' auth failed" + } + case ausf_context.AKA_AUTHENTICATION_REJECT_SUBTYPE: + ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE + case ausf_context.AKA_SYNCHRONIZATION_FAILURE_SUBTYPE: + logger.AuthELog.Warnf("EAP-AKA' synchronziation failure") + if ausfCurrentContext.Resynced { + eapOK = false + eapErrStr = "2 consecutive Synch Failure, terminate authentication procedure" + } else { + var authInfo models.AuthenticationInfo + AUTS := decodeEapAkaPrimePkt.Attributes[ausf_context.AT_AUTS_ATTRIBUTE].Value + resynchronizationInfo := &models.ResynchronizationInfo{ + Auts: hex.EncodeToString(AUTS[:]), + } + authInfo.SupiOrSuci = eapSessionID + authInfo.ServingNetworkName = servingNetworkName + authInfo.ResynchronizationInfo = resynchronizationInfo + p.UeAuthPostRequestProcedure(c, authInfo) + return + } + case ausf_context.AKA_NOTIFICATION_SUBTYPE: + ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE + case ausf_context.AKA_CLIENT_ERROR_SUBTYPE: + logger.AuthELog.Warnf("EAP-AKA' failure: receive client-error") + ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE + default: + ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE + } } - problemDetails = &models.ProblemDetails{ - Status: http.StatusForbidden, - Cause: "UNSPECIFIED", + + if !eapOK { + logger.AuthELog.Warnf("EAP-AKA' failure: %s", eapErrStr) + if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, + ausfCurrentContext.UdmUeauUrl); sendErr != nil { + logger.AuthELog.Infoln(sendErr.Error()) + problemDetails := models.ProblemDetails{ + Status: http.StatusInternalServerError, + Cause: "UPSTREAM_SERVER_ERROR", + } + c.JSON(http.StatusInternalServerError, problemDetails) + return + } + + ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE + responseBody.AuthResult = models.AuthResult_ONGOING + failEapAkaNoti := ConstructFailEapAkaNotification(eapContent.Id) + responseBody.EapPayload = failEapAkaNoti + self := ausf_context.GetSelf() + linkUrl := self.Url + factory.AusfAuthResUriPrefix + "/ue-authentications/" + eapSessionID + "/eap-session" + linksValue := models.LinksValueSchema{Href: linkUrl} + responseBody.Links = make(map[string]models.LinksValueSchema) + responseBody.Links["eap-session"] = linksValue + } else if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { + if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, + ausfCurrentContext.UdmUeauUrl); sendErr != nil { + logger.AuthELog.Infoln(sendErr.Error()) + var problemDetails models.ProblemDetails + problemDetails.Status = http.StatusInternalServerError + problemDetails.Cause = "UPSTREAM_SERVER_ERROR" + } + + eapFailPkt := ConstructEapNoTypePkt(radius.EapCodeFailure, eapPayload[1]) + responseBody.EapPayload = eapFailPkt + responseBody.AuthResult = models.AuthResult_FAILURE } - c.JSON(int(problemDetails.Status), problemDetails) + + c.JSON(http.StatusOK, responseBody) +} + +func (p *Processor) HandleUeAuthPostRequest(c *gin.Context, authenticationInfo models.AuthenticationInfo) { + logger.UeAuthLog.Infof("HandleUeAuthPostRequest") + p.UeAuthPostRequestProcedure(c, authenticationInfo) } -func (p *Processor) UeAuthPostRequestProcedure( - updateAuthenticationInfo models.AuthenticationInfo, -) (*models.UeAuthenticationCtx, string, *models.ProblemDetails) { +func (p *Processor) UeAuthPostRequestProcedure(c *gin.Context, updateAuthenticationInfo models.AuthenticationInfo) { var responseBody models.UeAuthenticationCtx var authInfoReq models.AuthenticationInfoRequest @@ -100,11 +219,13 @@ func (p *Processor) UeAuthPostRequestProcedure( snName := updateAuthenticationInfo.ServingNetworkName servingNetworkAuthorized := ausf_context.IsServingNetworkAuthorized(snName) if !servingNetworkAuthorized { - var problemDetails models.ProblemDetails - problemDetails.Cause = "SERVING_NETWORK_NOT_AUTHORIZED" - problemDetails.Status = http.StatusForbidden + problemDetails := models.ProblemDetails{ + Cause: "SERVING_NETWORK_NOT_AUTHORIZED", + Status: http.StatusForbidden, + } logger.UeAuthLog.Infoln("403 forbidden: serving network NOT AUTHORIZED") - return nil, "", &problemDetails + c.JSON(http.StatusForbidden, problemDetails) + return } logger.UeAuthLog.Infoln("Serving network authorized") @@ -133,7 +254,8 @@ func (p *Processor) UeAuthPostRequestProcedure( result, err, pd := p.Consumer().GenerateAuthDataApi(udmUrl, supiOrSuci, authInfoReq) if err != nil { logger.UeAuthLog.Infof("GenerateAuthDataApi error: %+v", err) - return nil, "", pd + c.JSON(http.StatusInternalServerError, pd) + return } authInfoResult := *result @@ -158,13 +280,14 @@ func (p *Processor) UeAuthPostRequestProcedure( var hxresStarBytes []byte if bytes, err := hex.DecodeString(concat); err != nil { logger.Auth5gAkaLog.Errorf("decode concat error: %+v", err) - return nil, "", - &models.ProblemDetails{ - Title: "Concat Decode Problem", - Cause: "CONCAT_DECODE_PROBLEM", - Detail: err.Error(), - Status: http.StatusInternalServerError, - } + problemDetails := models.ProblemDetails{ + Title: "Concat Decode Problem", + Cause: "CONCAT_DECODE_PROBLEM", + Detail: err.Error(), + Status: http.StatusInternalServerError, + } + c.JSON(http.StatusInternalServerError, problemDetails) + return } else { hxresStarBytes = bytes } @@ -177,13 +300,14 @@ func (p *Processor) UeAuthPostRequestProcedure( var KausfDecode []byte if ausfDecode, err := hex.DecodeString(Kausf); err != nil { logger.Auth5gAkaLog.Errorf("decode Kausf failed: %+v", err) - return nil, "", - &models.ProblemDetails{ - Title: "Kausf Decode Problem", - Cause: "KAUSF_DECODE_PROBLEM", - Detail: err.Error(), - Status: http.StatusInternalServerError, - } + problemDetails := models.ProblemDetails{ + Title: "Kausf Decode Problem", + Cause: "KAUSF_DECODE_PROBLEM", + Detail: err.Error(), + Status: http.StatusInternalServerError, + } + c.JSON(http.StatusInternalServerError, problemDetails) + return } else { KausfDecode = ausfDecode } @@ -191,13 +315,14 @@ func (p *Processor) UeAuthPostRequestProcedure( Kseaf, err := ueauth.GetKDFValue(KausfDecode, ueauth.FC_FOR_KSEAF_DERIVATION, P0, ueauth.KDFLen(P0)) if err != nil { logger.Auth5gAkaLog.Errorf("GetKDFValue failed: %+v", err) - return nil, "", - &models.ProblemDetails{ - Title: "Kseaf Derivation Problem", - Cause: "KSEAF_DERIVATION_PROBLEM", - Detail: err.Error(), - Status: http.StatusInternalServerError, - } + problemDetails := models.ProblemDetails{ + Title: "Kseaf Derivation Problem", + Cause: "KSEAF_DERIVATION_PROBLEM", + Detail: err.Error(), + Status: http.StatusInternalServerError, + } + c.JSON(http.StatusInternalServerError, problemDetails) + return } ausfUeContext.XresStar = authInfoResult.AuthenticationVector.XresStar ausfUeContext.Kausf = Kausf @@ -312,12 +437,22 @@ func (p *Processor) UeAuthPostRequestProcedure( responseBody.AuthType = authInfoResult.AuthType - return &responseBody, locationURI, nil + c.Header("Location", locationURI) + c.JSON(http.StatusCreated, responseBody) } -func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.ConfirmationData, +func (p *Processor) HandleAuth5gAkaComfirmRequest( + c *gin.Context, + confirmationData models.ConfirmationData, + confirmationDataResponseId string, +) { + logger.Auth5gAkaLog.Infof("Auth5gAkaComfirmRequest") + p.Auth5gAkaComfirmRequestProcedure(c, confirmationData, confirmationDataResponseId) +} + +func (p *Processor) Auth5gAkaComfirmRequestProcedure(c *gin.Context, updateConfirmationData models.ConfirmationData, ConfirmationDataResponseID string, -) (*models.ConfirmationDataResponse, *models.ProblemDetails) { +) { var responseBody models.ConfirmationDataResponse success := false responseBody.AuthResult = models.AuthResult_FAILURE @@ -325,19 +460,23 @@ func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData mode if !ausf_context.CheckIfSuciSupiPairExists(ConfirmationDataResponseID) { logger.Auth5gAkaLog.Infof("supiSuciPair does not exist, confirmation failed (queried by %s)\n", ConfirmationDataResponseID) - var problemDetails models.ProblemDetails - problemDetails.Cause = "USER_NOT_FOUND" - problemDetails.Status = http.StatusBadRequest - return nil, &problemDetails + problemDetails := models.ProblemDetails{ + Cause: "USER_NOT_FOUND", + Status: http.StatusBadRequest, + } + c.JSON(http.StatusBadRequest, problemDetails) + return } currentSupi := ausf_context.GetSupiFromSuciSupiMap(ConfirmationDataResponseID) if !ausf_context.CheckIfAusfUeContextExists(currentSupi) { logger.Auth5gAkaLog.Infof("SUPI does not exist, confirmation failed (queried by %s)\n", currentSupi) - var problemDetails models.ProblemDetails - problemDetails.Cause = "USER_NOT_FOUND" - problemDetails.Status = http.StatusBadRequest - return nil, &problemDetails + problemDetails := models.ProblemDetails{ + Cause: "USER_NOT_FOUND", + Status: http.StatusBadRequest, + } + c.JSON(http.StatusBadRequest, problemDetails) + return } ausfCurrentContext := ausf_context.GetAusfUeContext(currentSupi) @@ -362,191 +501,17 @@ func (p *Processor) Auth5gAkaComfirmRequestProcedure(updateConfirmationData mode if sendErr := p.Consumer().SendAuthResultToUDM(currentSupi, models.AuthType__5_G_AKA, success, servingNetworkName, ausfCurrentContext.UdmUeauUrl); sendErr != nil { logger.Auth5gAkaLog.Infoln(sendErr.Error()) - var problemDetails models.ProblemDetails - problemDetails.Status = http.StatusInternalServerError - problemDetails.Cause = "UPSTREAM_SERVER_ERROR" - - return nil, &problemDetails - } - - return &responseBody, nil -} - -// return response, problemDetails -func (p *Processor) EapAuthComfirmRequestProcedure( - updateEapSession models.EapSession, - eapSessionID string, -) (*models.EapSession, *models.ProblemDetails) { - var responseBody models.EapSession - - if !ausf_context.CheckIfSuciSupiPairExists(eapSessionID) { - logger.AuthELog.Infoln("supiSuciPair does not exist, confirmation failed") - var problemDetails models.ProblemDetails - problemDetails.Cause = "USER_NOT_FOUND" - return nil, &problemDetails - } - - currentSupi := ausf_context.GetSupiFromSuciSupiMap(eapSessionID) - if !ausf_context.CheckIfAusfUeContextExists(currentSupi) { - logger.AuthELog.Infoln("SUPI does not exist, confirmation failed") - var problemDetails models.ProblemDetails - problemDetails.Cause = "USER_NOT_FOUND" - return nil, &problemDetails - } - - ausfCurrentContext := ausf_context.GetAusfUeContext(currentSupi) - servingNetworkName := ausfCurrentContext.ServingNetworkName - - if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { - eapFailPkt := ConstructEapNoTypePkt(radius.EapCodeFailure, 0) - responseBody.EapPayload = eapFailPkt - responseBody.AuthResult = models.AuthResult_FAILURE - return &responseBody, nil - } - - var eapPayload []byte - if eapPayloadTmp, err := base64.StdEncoding.DecodeString(updateEapSession.EapPayload); err != nil { - logger.AuthELog.Warnf("EAP Payload decode failed: %+v", err) - } else { - eapPayload = eapPayloadTmp - } - - eapGoPkt := gopacket.NewPacket(eapPayload, layers.LayerTypeEAP, gopacket.Default) - eapLayer := eapGoPkt.Layer(layers.LayerTypeEAP) - eapContent, _ := eapLayer.(*layers.EAP) - eapOK := true - var eapErrStr string - - if eapContent.Code != layers.EAPCodeResponse { - eapOK = false - eapErrStr = "eap packet code error" - } else if eapContent.Type != ausf_context.EAP_AKA_PRIME_TYPENUM { - eapOK = false - eapErrStr = "eap packet type error" - } else if decodeEapAkaPrimePkt, err := decodeEapAkaPrime(eapContent.Contents); err != nil { - logger.AuthELog.Warnf("EAP-AKA' decode failed: %+v", err) - eapOK = false - eapErrStr = "eap packet error" - } else { - switch decodeEapAkaPrimePkt.Subtype { - case ausf_context.AKA_CHALLENGE_SUBTYPE: - K_autStr := ausfCurrentContext.K_aut - var K_aut []byte - if K_autTmp, err := hex.DecodeString(K_autStr); err != nil { - logger.AuthELog.Warnf("K_aut decode error: %+v", err) - } else { - K_aut = K_autTmp - } - XMAC := CalculateAtMAC(K_aut, decodeEapAkaPrimePkt.MACInput) - MAC := decodeEapAkaPrimePkt.Attributes[ausf_context.AT_MAC_ATTRIBUTE].Value - XRES := ausfCurrentContext.XRES - RES := hex.EncodeToString(decodeEapAkaPrimePkt.Attributes[ausf_context.AT_RES_ATTRIBUTE].Value) - - if !bytes.Equal(MAC, XMAC) { - eapOK = false - eapErrStr = "EAP-AKA' integrity check fail" - } else if XRES == RES { - logger.AuthELog.Infoln("Correct RES value, EAP-AKA' auth succeed") - responseBody.KSeaf = ausfCurrentContext.Kseaf - responseBody.Supi = currentSupi - responseBody.AuthResult = models.AuthResult_SUCCESS - eapSuccPkt := ConstructEapNoTypePkt(radius.EapCodeSuccess, eapContent.Id) - responseBody.EapPayload = eapSuccPkt - udmUrl := ausfCurrentContext.UdmUeauUrl - if sendErr := p.Consumer().SendAuthResultToUDM( - eapSessionID, - models.AuthType_EAP_AKA_PRIME, - true, - servingNetworkName, - udmUrl); sendErr != nil { - logger.AuthELog.Infoln(sendErr.Error()) - var problemDetails models.ProblemDetails - problemDetails.Cause = "UPSTREAM_SERVER_ERROR" - return nil, &problemDetails - } - ausfCurrentContext.AuthStatus = models.AuthResult_SUCCESS - } else { - eapOK = false - eapErrStr = "Wrong RES value, EAP-AKA' auth failed" - } - case ausf_context.AKA_AUTHENTICATION_REJECT_SUBTYPE: - ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE - case ausf_context.AKA_SYNCHRONIZATION_FAILURE_SUBTYPE: - logger.AuthELog.Warnf("EAP-AKA' synchronziation failure") - if ausfCurrentContext.Resynced { - eapOK = false - eapErrStr = "2 consecutive Synch Failure, terminate authentication procedure" - } else { - var authInfo models.AuthenticationInfo - AUTS := decodeEapAkaPrimePkt.Attributes[ausf_context.AT_AUTS_ATTRIBUTE].Value - resynchronizationInfo := &models.ResynchronizationInfo{ - Auts: hex.EncodeToString(AUTS[:]), - } - authInfo.SupiOrSuci = eapSessionID - authInfo.ServingNetworkName = servingNetworkName - authInfo.ResynchronizationInfo = resynchronizationInfo - response, _, problemDetails := p.UeAuthPostRequestProcedure(authInfo) - if problemDetails != nil { - return nil, problemDetails - } - ausfCurrentContext.Resynced = true - - responseBody.EapPayload = response.Var5gAuthData.(string) - responseBody.Links = response.Links - responseBody.AuthResult = models.AuthResult_ONGOING - } - case ausf_context.AKA_NOTIFICATION_SUBTYPE: - ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE - case ausf_context.AKA_CLIENT_ERROR_SUBTYPE: - logger.AuthELog.Warnf("EAP-AKA' failure: receive client-error") - ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE - default: - ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE + problemDetails := models.ProblemDetails{ + Status: http.StatusInternalServerError, + Cause: "UPSTREAM_SERVER_ERROR", } + c.JSON(http.StatusInternalServerError, problemDetails) + return } - if !eapOK { - logger.AuthELog.Warnf("EAP-AKA' failure: %s", eapErrStr) - if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, - ausfCurrentContext.UdmUeauUrl); sendErr != nil { - logger.AuthELog.Infoln(sendErr.Error()) - var problemDetails models.ProblemDetails - problemDetails.Status = http.StatusInternalServerError - problemDetails.Cause = "UPSTREAM_SERVER_ERROR" - - return nil, &problemDetails - } - - ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE - responseBody.AuthResult = models.AuthResult_ONGOING - failEapAkaNoti := ConstructFailEapAkaNotification(eapContent.Id) - responseBody.EapPayload = failEapAkaNoti - self := ausf_context.GetSelf() - linkUrl := self.Url + factory.AusfAuthResUriPrefix + "/ue-authentications/" + eapSessionID + "/eap-session" - linksValue := models.LinksValueSchema{Href: linkUrl} - responseBody.Links = make(map[string]models.LinksValueSchema) - responseBody.Links["eap-session"] = linksValue - } else if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { - if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, - ausfCurrentContext.UdmUeauUrl); sendErr != nil { - logger.AuthELog.Infoln(sendErr.Error()) - var problemDetails models.ProblemDetails - problemDetails.Status = http.StatusInternalServerError - problemDetails.Cause = "UPSTREAM_SERVER_ERROR" - - return nil, &problemDetails - } - - eapFailPkt := ConstructEapNoTypePkt(radius.EapCodeFailure, eapPayload[1]) - responseBody.EapPayload = eapFailPkt - responseBody.AuthResult = models.AuthResult_FAILURE - } - - return &responseBody, nil + c.JSON(http.StatusOK, responseBody) } -/* function.go */ - func KDF5gAka(param ...string) hash.Hash { s := param[0] s += param[1] @@ -586,7 +551,6 @@ func CalculateAtMAC(key []byte, input []byte) []byte { return sum[:16] } -// func EapEncodeAttribute(attributeType string, data string) (returnStr string, err error) { func EapEncodeAttribute(attributeType string, data string) (string, error) { var attribute string var length int @@ -671,7 +635,6 @@ func eapAkaPrimePrf(ikPrime string, ckPrime string, identity string) ([]byte, [] MK := []byte("") prev := []byte("") - //_ = prev prfRounds := 208/32 + 1 for i := 0; i < prfRounds; i++ { // Create a new HMAC by defining the hash type and the key (as byte array) From d333b082093661728f3f6a441d21e27b48edb961 Mon Sep 17 00:00:00 2001 From: "CTFang@WireLab" Date: Fri, 28 Jun 2024 04:56:26 +0000 Subject: [PATCH 16/16] fix: coding style and remove unused code --- internal/sbi/consumer/nrf_service.go | 3 +- internal/sbi/processor/ue_authentication.go | 57 +++++++++++---------- internal/sbi/server.go | 2 +- pkg/service/init.go | 1 - 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go index e8b6757..0a5a01b 100644 --- a/internal/sbi/consumer/nrf_service.go +++ b/internal/sbi/consumer/nrf_service.go @@ -190,8 +190,7 @@ func (s *nnrfService) RegisterNFInstance(ctx context.Context) ( break } else { - fmt.Println(fmt.Errorf("handler returned wrong status code %d", status)) - fmt.Println("NRF return wrong status code", status) + logger.ConsumerLog.Errorln("NRF return wrong status code", status) } } return resouceNrfUri, retrieveNfInstanceID, err diff --git a/internal/sbi/processor/ue_authentication.go b/internal/sbi/processor/ue_authentication.go index d4894f2..57dc802 100644 --- a/internal/sbi/processor/ue_authentication.go +++ b/internal/sbi/processor/ue_authentication.go @@ -38,14 +38,15 @@ func (p *Processor) EapAuthComfirmRequestProcedure( updateEapSession models.EapSession, eapSessionID string, ) { - var responseBody models.EapSession + var eapSession models.EapSession if !ausf_context.CheckIfSuciSupiPairExists(eapSessionID) { logger.AuthELog.Infoln("supiSuciPair does not exist, confirmation failed") problemDetails := models.ProblemDetails{ - Cause: "USER_NOT_FOUND", + Status: http.StatusNotFound, + Cause: "USER_NOT_FOUND", } - c.JSON(http.StatusNotFound, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) return } @@ -53,9 +54,10 @@ func (p *Processor) EapAuthComfirmRequestProcedure( if !ausf_context.CheckIfAusfUeContextExists(currentSupi) { logger.AuthELog.Infoln("SUPI does not exist, confirmation failed") problemDetails := models.ProblemDetails{ - Cause: "USER_NOT_FOUND", + Status: http.StatusNotFound, + Cause: "USER_NOT_FOUND", } - c.JSON(http.StatusNotFound, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) return } @@ -65,9 +67,9 @@ func (p *Processor) EapAuthComfirmRequestProcedure( if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { logger.AuthELog.Warnf("Authentication failed with status: %s", ausfCurrentContext.AuthStatus) eapFailPkt := ConstructEapNoTypePkt(radius.EapCodeFailure, 0) - responseBody.EapPayload = eapFailPkt - responseBody.AuthResult = models.AuthResult_FAILURE - c.JSON(http.StatusUnauthorized, responseBody) + eapSession.EapPayload = eapFailPkt + eapSession.AuthResult = models.AuthResult_FAILURE + c.JSON(http.StatusUnauthorized, eapSession) return } @@ -114,11 +116,11 @@ func (p *Processor) EapAuthComfirmRequestProcedure( eapErrStr = "EAP-AKA' integrity check fail" } else if XRES == RES { logger.AuthELog.Infoln("Correct RES value, EAP-AKA' auth succeed") - responseBody.KSeaf = ausfCurrentContext.Kseaf - responseBody.Supi = currentSupi - responseBody.AuthResult = models.AuthResult_SUCCESS + eapSession.KSeaf = ausfCurrentContext.Kseaf + eapSession.Supi = currentSupi + eapSession.AuthResult = models.AuthResult_SUCCESS eapSuccPkt := ConstructEapNoTypePkt(radius.EapCodeSuccess, eapContent.Id) - responseBody.EapPayload = eapSuccPkt + eapSession.EapPayload = eapSuccPkt udmUrl := ausfCurrentContext.UdmUeauUrl if sendErr := p.Consumer().SendAuthResultToUDM( eapSessionID, @@ -131,6 +133,7 @@ func (p *Processor) EapAuthComfirmRequestProcedure( Cause: "UPSTREAM_SERVER_ERROR", } c.JSON(http.StatusInternalServerError, problemDetails) + return } ausfCurrentContext.AuthStatus = models.AuthResult_SUCCESS } else { @@ -180,14 +183,14 @@ func (p *Processor) EapAuthComfirmRequestProcedure( } ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE - responseBody.AuthResult = models.AuthResult_ONGOING + eapSession.AuthResult = models.AuthResult_ONGOING failEapAkaNoti := ConstructFailEapAkaNotification(eapContent.Id) - responseBody.EapPayload = failEapAkaNoti + eapSession.EapPayload = failEapAkaNoti self := ausf_context.GetSelf() linkUrl := self.Url + factory.AusfAuthResUriPrefix + "/ue-authentications/" + eapSessionID + "/eap-session" linksValue := models.LinksValueSchema{Href: linkUrl} - responseBody.Links = make(map[string]models.LinksValueSchema) - responseBody.Links["eap-session"] = linksValue + eapSession.Links = make(map[string]models.LinksValueSchema) + eapSession.Links["eap-session"] = linksValue } else if ausfCurrentContext.AuthStatus == models.AuthResult_FAILURE { if sendErr := p.Consumer().SendAuthResultToUDM(eapSessionID, models.AuthType_EAP_AKA_PRIME, false, servingNetworkName, ausfCurrentContext.UdmUeauUrl); sendErr != nil { @@ -198,11 +201,11 @@ func (p *Processor) EapAuthComfirmRequestProcedure( } eapFailPkt := ConstructEapNoTypePkt(radius.EapCodeFailure, eapPayload[1]) - responseBody.EapPayload = eapFailPkt - responseBody.AuthResult = models.AuthResult_FAILURE + eapSession.EapPayload = eapFailPkt + eapSession.AuthResult = models.AuthResult_FAILURE } - c.JSON(http.StatusOK, responseBody) + c.JSON(http.StatusOK, eapSession) } func (p *Processor) HandleUeAuthPostRequest(c *gin.Context, authenticationInfo models.AuthenticationInfo) { @@ -453,9 +456,9 @@ func (p *Processor) HandleAuth5gAkaComfirmRequest( func (p *Processor) Auth5gAkaComfirmRequestProcedure(c *gin.Context, updateConfirmationData models.ConfirmationData, ConfirmationDataResponseID string, ) { - var responseBody models.ConfirmationDataResponse + var confirmDataRsp models.ConfirmationDataResponse success := false - responseBody.AuthResult = models.AuthResult_FAILURE + confirmDataRsp.AuthResult = models.AuthResult_FAILURE if !ausf_context.CheckIfSuciSupiPairExists(ConfirmationDataResponseID) { logger.Auth5gAkaLog.Infof("supiSuciPair does not exist, confirmation failed (queried by %s)\n", @@ -486,14 +489,14 @@ func (p *Processor) Auth5gAkaComfirmRequestProcedure(c *gin.Context, updateConfi logger.Auth5gAkaLog.Infof("res*: %x\nXres*: %x\n", updateConfirmationData.ResStar, ausfCurrentContext.XresStar) if strings.EqualFold(updateConfirmationData.ResStar, ausfCurrentContext.XresStar) { ausfCurrentContext.AuthStatus = models.AuthResult_SUCCESS - responseBody.AuthResult = models.AuthResult_SUCCESS + confirmDataRsp.AuthResult = models.AuthResult_SUCCESS success = true logger.Auth5gAkaLog.Infoln("5G AKA confirmation succeeded") - responseBody.Supi = currentSupi - responseBody.Kseaf = ausfCurrentContext.Kseaf + confirmDataRsp.Supi = currentSupi + confirmDataRsp.Kseaf = ausfCurrentContext.Kseaf } else { ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE - responseBody.AuthResult = models.AuthResult_FAILURE + confirmDataRsp.AuthResult = models.AuthResult_FAILURE p.logConfirmFailureAndInformUDM(ConfirmationDataResponseID, models.AuthType__5_G_AKA, servingNetworkName, "5G AKA confirmation failed", ausfCurrentContext.UdmUeauUrl) } @@ -509,7 +512,7 @@ func (p *Processor) Auth5gAkaComfirmRequestProcedure(c *gin.Context, updateConfi return } - c.JSON(http.StatusOK, responseBody) + c.JSON(http.StatusOK, confirmDataRsp) } func KDF5gAka(param ...string) hash.Hash { @@ -819,7 +822,7 @@ func (p *Processor) logConfirmFailureAndInformUDM( id string, authType models.AuthType, servingNetworkName, errStr, udmUrl string, ) { if authType == models.AuthType__5_G_AKA { - logger.Auth5gAkaLog.Infoln(errStr) + logger.Auth5gAkaLog.Infoln(servingNetworkName, errStr) if sendErr := p.Consumer().SendAuthResultToUDM(id, authType, false, "", udmUrl); sendErr != nil { logger.Auth5gAkaLog.Infoln(sendErr.Error()) } diff --git a/internal/sbi/server.go b/internal/sbi/server.go index 22e6fa7..90b3c09 100644 --- a/internal/sbi/server.go +++ b/internal/sbi/server.go @@ -151,5 +151,5 @@ func (s *Server) startServer(wg *sync.WaitGroup) { if err != nil && err != http.ErrServerClosed { logger.SBILog.Errorf("SBI server error: %v", err) } - logger.SBILog.Warnf("SBI server (listen on %s) stopped", s.httpServer.Addr) + logger.SBILog.Infof("SBI server (listen on %s) stopped", s.httpServer.Addr) } diff --git a/pkg/service/init.go b/pkg/service/init.go index 052a008..bb01b5d 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -130,7 +130,6 @@ func (a *AusfApp) SetReportCaller(reportCaller bool) { logger.Log.SetReportCaller(reportCaller) } -// tlsKeyLogPath have to remove after all NFs are refactor func (a *AusfApp) Start() { logger.InitLog.Infoln("Server started")