From 4d406288607a82fd63c2e655566922ed8869bffa Mon Sep 17 00:00:00 2001 From: CTFang Date: Mon, 18 Dec 2023 18:39:15 +0800 Subject: [PATCH] Feature: Add NRF Consumer support OAuth2 (#18) * Feature: NRF consumer support oauth2 * Add nrfCerPem config * Fix: add minor changes * Fix: prevent assertion and modify config setting * Fix: move GetTokenCtx() and remove unsed condition --------- Co-authored-by: CTFang@WireLab --- go.mod | 4 +-- go.sum | 7 ++--- internal/context/context.go | 16 ++++++++++ internal/sbi/consumer/communication.go | 2 +- .../sbi/consumer/influenceDataSubscription.go | 6 ++-- internal/sbi/consumer/nf_discovery.go | 9 ++++-- internal/sbi/consumer/nf_management.go | 30 +++++++++++++++---- internal/sbi/producer/policyauthorization.go | 2 +- internal/util/pcc_rule.go | 2 +- pkg/factory/config.go | 1 + 10 files changed, 60 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 4f4854e..f0dfbed 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/antihax/optional v1.0.0 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/cydev/zero v0.0.0-20160322155811-4a4535dd56e7 - github.com/free5gc/openapi v1.0.7-0.20230802173229-2b3ded4db293 + github.com/free5gc/openapi v1.0.7-0.20231216094313-e15a4ff046f6 github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.9.1 @@ -57,7 +57,7 @@ require ( golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/appengine v1.6.6 // indirect diff --git a/go.sum b/go.sum index 705b827..01a9781 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/free5gc/openapi v1.0.7-0.20230802173229-2b3ded4db293 h1:BSIvKCYu7646sE8J9R1L8v2R435otUik3wOFN33csfs= -github.com/free5gc/openapi v1.0.7-0.20230802173229-2b3ded4db293/go.mod h1:iw/N0E+FlX44EEx24IBi2EdZW8v+bkj3ETWPGnlK9DI= +github.com/free5gc/openapi v1.0.7-0.20231216094313-e15a4ff046f6 h1:8P/wOkTAQMgZJe9pUUNSTE5PWeAdlMrsU9kLsI+VAVE= +github.com/free5gc/openapi v1.0.7-0.20231216094313-e15a4ff046f6/go.mod h1:qv9KqEucoZSeENPRFGxfTe+33ZWYyiYFx1Rj+H0DoWA= github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94 h1:tNylIqH/m5Kq+3KuC+jjXGl06Y6EmM8yq61ZUgNrPBY= github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94/go.mod h1:aMszJZbCkcg5xaGgzya+55jz+OPMsJqPLq5Z3fWDFPE= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= @@ -330,7 +330,6 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= @@ -350,7 +349,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -552,6 +550,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/context/context.go b/internal/context/context.go index d8d266c..e34fcf5 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -1,6 +1,7 @@ package context import ( + "context" "fmt" "math" "os" @@ -12,6 +13,7 @@ import ( "github.com/free5gc/openapi" "github.com/free5gc/openapi/models" + "github.com/free5gc/openapi/oauth" "github.com/free5gc/pcf/internal/logger" "github.com/free5gc/pcf/pkg/factory" "github.com/free5gc/util/idgenerator" @@ -31,6 +33,7 @@ type PCFContext struct { PcfServiceUris map[models.ServiceName]string PcfSuppFeats map[models.ServiceName]openapi.SupportedFeature NrfUri string + NrfCertPem string DefaultUdrURI string Locality string // UePool map[string]*UeContext @@ -45,6 +48,8 @@ type PCFContext struct { // lock DefaultUdrURILock sync.RWMutex + + OAuth2Required bool } type AMFStatusSubscriptionData struct { @@ -86,6 +91,7 @@ func InitpcfContext(context *PCFContext) { sbi := configuration.Sbi context.NrfUri = configuration.NrfUri + context.NrfCertPem = configuration.NrfCertPem context.UriScheme = "" context.RegisterIPv4 = factory.PcfSbiDefaultIPv4 // default localhost context.SBIPort = factory.PcfSbiDefaultPort // default port @@ -426,3 +432,13 @@ func DeleteIpv6index(Ipv6index int32) { func (c *PCFContext) NewAmfStatusSubscription(subscriptionID string, subscriptionData AMFStatusSubscriptionData) { c.AMFStatusSubsData.Store(subscriptionID, subscriptionData) } + +func (c *PCFContext) GetTokenCtx(scope, targetNF string) ( + context.Context, *models.ProblemDetails, error, +) { + if !c.OAuth2Required { + return context.TODO(), nil, nil + } + return oauth.GetTokenCtx(models.NfType_PCF, + c.NfId, c.NrfUri, scope, targetNF) +} diff --git a/internal/sbi/consumer/communication.go b/internal/sbi/consumer/communication.go index 581d66c..292ed48 100644 --- a/internal/sbi/consumer/communication.go +++ b/internal/sbi/consumer/communication.go @@ -47,7 +47,7 @@ func AmfStatusChangeSubscribe(amfUri string, guamiList []models.Guami) ( } else if httpResp != nil { if httpResp.Status != localErr.Error() { err = localErr - return + return nil, err } problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) problemDetails = &problem diff --git a/internal/sbi/consumer/influenceDataSubscription.go b/internal/sbi/consumer/influenceDataSubscription.go index 0f35f84..c662e09 100644 --- a/internal/sbi/consumer/influenceDataSubscription.go +++ b/internal/sbi/consumer/influenceDataSubscription.go @@ -26,7 +26,7 @@ func CreateInfluenceDataSubscription(ue *pcf_context.UeContext, request models.S ApplicationDataInfluenceDataSubsToNotifyPost(context.Background(), trafficInfluSub) if localErr == nil { locationHeader := httpResp.Header.Get("Location") - subscriptionID := locationHeader[strings.LastIndex(locationHeader, "/")+1:] + subscriptionID = locationHeader[strings.LastIndex(locationHeader, "/")+1:] logger.ConsumerLog.Debugf("Influence Data Subscription ID: %s", subscriptionID) return subscriptionID, nil, nil } else if httpResp != nil { @@ -38,7 +38,7 @@ func CreateInfluenceDataSubscription(ue *pcf_context.UeContext, request models.S }() if httpResp.Status != localErr.Error() { err = localErr - return + return subscriptionID, problemDetails, err } problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) problemDetails = &problem @@ -85,7 +85,7 @@ func RemoveInfluenceDataSubscription(ue *pcf_context.UeContext, subscriptionID s }() if httpResp.Status != localErr.Error() { err = localErr - return + return nil, err } problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) problemDetails = &problem diff --git a/internal/sbi/consumer/nf_discovery.go b/internal/sbi/consumer/nf_discovery.go index 5ee3e0c..382c106 100644 --- a/internal/sbi/consumer/nf_discovery.go +++ b/internal/sbi/consumer/nf_discovery.go @@ -1,7 +1,6 @@ package consumer import ( - "context" "fmt" "net/http" @@ -9,6 +8,7 @@ import ( "github.com/free5gc/openapi/Nnrf_NFDiscovery" "github.com/free5gc/openapi/models" + pcf_context "github.com/free5gc/pcf/internal/context" "github.com/free5gc/pcf/internal/logger" "github.com/free5gc/pcf/internal/util" ) @@ -22,7 +22,12 @@ func SendSearchNFInstances( configuration.SetBasePath(nrfUri) client := Nnrf_NFDiscovery.NewAPIClient(configuration) - result, res, err := client.NFInstancesStoreApi.SearchNFInstances(context.TODO(), targetNfType, requestNfType, ¶m) + ctx, _, err := pcf_context.GetSelf().GetTokenCtx("nnrf-disc", "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) } diff --git a/internal/sbi/consumer/nf_management.go b/internal/sbi/consumer/nf_management.go index 26fc279..8489593 100644 --- a/internal/sbi/consumer/nf_management.go +++ b/internal/sbi/consumer/nf_management.go @@ -54,8 +54,9 @@ func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfil client := Nnrf_NFManagement.NewAPIClient(configuration) var res *http.Response + var nf models.NfProfile for { - _, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), nfInstanceId, profile) + nf, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), nfInstanceId, profile) if err != nil || res == nil { // TODO : add log fmt.Println(fmt.Errorf("PCF register to NRF Error[%v]", err.Error())) @@ -76,6 +77,20 @@ func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfil 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) + } + } + pcf_context.GetSelf().OAuth2Required = oauth2 + + if oauth2 && pcf_context.GetSelf().NrfCertPem == "" { + logger.CfgLog.Error("OAuth2 enable but no nrfCertPem provided in config.") + } break } else { fmt.Println("NRF return wrong status code", status) @@ -87,6 +102,11 @@ func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfil func SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err error) { logger.ConsumerLog.Infof("Send Deregister NFInstance") + ctx, pd, err := pcf_context.GetSelf().GetTokenCtx("nnrf-nfm", "NRF") + if err != nil { + return pd, err + } + pcfSelf := pcf_context.GetSelf() // Set client and set url configuration := Nnrf_NFManagement.NewConfiguration() @@ -95,9 +115,9 @@ func SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err erro var res *http.Response - res, err = client.NFInstanceIDDocumentApi.DeregisterNFInstance(context.Background(), pcfSelf.NfId) + res, err = client.NFInstanceIDDocumentApi.DeregisterNFInstance(ctx, pcfSelf.NfId) if err == nil { - return + return nil, nil } else if res != nil { defer func() { if resCloseErr := res.Body.Close(); resCloseErr != nil { @@ -105,12 +125,12 @@ func SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err erro } }() if res.Status != err.Error() { - return + return nil, err } problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) problemDetails = &problem } else { err = openapi.ReportError("server no response") } - return + return problemDetails, err } diff --git a/internal/sbi/producer/policyauthorization.go b/internal/sbi/producer/policyauthorization.go index 3f7b9a1..1ff332c 100644 --- a/internal/sbi/producer/policyauthorization.go +++ b/internal/sbi/producer/policyauthorization.go @@ -1480,7 +1480,7 @@ func updateQosInMedSubComp(qosData *models.QosData, comp *models.MediaComponent, if comp.FStatus == models.FlowStatus_REMOVED { updatedQosData.MaxbrDl = "" updatedQosData.MaxbrUl = "" - return + return updatedQosData, ulExist, dlExist } maxBwUl := 0.0 maxBwDl := 0.0 diff --git a/internal/util/pcc_rule.go b/internal/util/pcc_rule.go index f923137..9293112 100644 --- a/internal/util/pcc_rule.go +++ b/internal/util/pcc_rule.go @@ -274,7 +274,7 @@ func isUpPathChgEventExist(trafficInfluData *models.TrafficInfluData) bool { trafficInfluData.DnaiChgType != "" } -// subclause 4.2.6.2.6.2 in 3GPP TS 29.512. +// subclause 4.2.6.2.6.2 in 3GPP TS 29.512. func setUpPathChgEvent(trafficInfluData *models.TrafficInfluData) *models.UpPathChgEvent { return &models.UpPathChgEvent{ NotificationUri: trafficInfluData.UpPathChgNotifUri, diff --git a/pkg/factory/config.go b/pkg/factory/config.go index df914af..433e70c 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -62,6 +62,7 @@ type Configuration struct { TimeFormat string `yaml:"timeFormat,omitempty" valid:"required"` DefaultBdtRefId string `yaml:"defaultBdtRefId,omitempty" valid:"required, type(string)"` NrfUri string `yaml:"nrfUri,omitempty" valid:"required, url"` + NrfCertPem string `yaml:"nrfCertPem,omitempty" valid:"optional"` ServiceList []Service `yaml:"serviceList,omitempty" valid:"required"` Mongodb *Mongodb `yaml:"mongodb" valid:"required"` Locality string `yaml:"locality,omitempty" valid:"-"`