Skip to content

Commit

Permalink
Feature: Add NRF Consumer support OAuth2 (#90)
Browse files Browse the repository at this point in the history
* Feature: NRF consumer support oauth2

* Feature: Consume NRF service via OAuth

* Fix: Minor change

* Fix: prevent assertion and modify config setting

* Fix: move GetTokenCtx() and fix logics

---------

Co-authored-by: CTFang@WireLab <ctfang.cs12@nycu.edu.tw>
  • Loading branch information
andy89923 and andy89923 authored Dec 18, 2023
1 parent d1e4a6d commit 71201ec
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 141 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/free5gc/aper v1.0.4
github.com/free5gc/nas v1.1.0
github.com/free5gc/ngap v1.0.6
github.com/free5gc/openapi v1.0.7-0.20230802173229-2b3ded4db293
github.com/free5gc/openapi v1.0.7-0.20231216094313-e15a4ff046f6
github.com/free5gc/pfcp v1.0.6
github.com/free5gc/util v1.0.5-0.20231001095115-433858e5be94
github.com/gin-gonic/gin v1.9.1
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ github.com/free5gc/ngap v1.0.6 h1:f9sKqHMNrFZVo9Kp8hAyrCXSoI8l746N5O+DFn7vKHA=
github.com/free5gc/ngap v1.0.6/go.mod h1:TG1kwwU/EyIlJ3bxY591rdxpD5ZeYnLZTzoWjcfvrBM=
github.com/free5gc/openapi v1.0.4/go.mod h1:KRCnnp0GeK0Bl4gnrX79cQAidKXNENf8VRdG0y9R0Fc=
github.com/free5gc/openapi v1.0.6/go.mod h1:iw/N0E+FlX44EEx24IBi2EdZW8v+bkj3ETWPGnlK9DI=
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/pfcp v1.0.6 h1:dKEVyZWozF1G+yk1JXw/1ggtIRI0v362say/Q6VDZTE=
github.com/free5gc/pfcp v1.0.6/go.mod h1:WzpW7Zxhx5WONMumNKRWbPn7pl/iTYp2FqRLNiOWUjs=
github.com/free5gc/tlv v1.0.2-0.20230131124215-8b6ebd69bf93 h1:QPSSI5zw4goiIfxem9doVyMqTO8iKLQ536pzpET5Y+Q=
Expand Down Expand Up @@ -546,6 +546,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=
Expand Down
14 changes: 14 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/free5gc/openapi/Nnrf_NFManagement"
"github.com/free5gc/openapi/Nudm_SubscriberDataManagement"
"github.com/free5gc/openapi/models"
"github.com/free5gc/openapi/oauth"
"github.com/free5gc/pfcp/pfcpType"
"github.com/free5gc/smf/internal/logger"
"github.com/free5gc/smf/pkg/factory"
Expand Down Expand Up @@ -48,12 +49,14 @@ type SMFContext struct {
SnssaiInfos []*SnssaiSmfInfo

NrfUri string
NrfCertPem string
NFManagementClient *Nnrf_NFManagement.APIClient
NFDiscoveryClient *Nnrf_NFDiscovery.APIClient
SubscriberDataManagementClient *Nudm_SubscriberDataManagement.APIClient
Locality string
AssocFailAlertInterval time.Duration
AssocFailRetryInterval time.Duration
OAuth2Required bool

UserPlaneInformation *UserPlaneInformation
Ctx context.Context
Expand Down Expand Up @@ -152,6 +155,7 @@ func InitSmfContext(config *factory.Config) {
logger.CtxLog.Warn("NRF Uri is empty! Using localhost as NRF IPv4 address.")
smfContext.NrfUri = fmt.Sprintf("%s://%s:%d", smfContext.URIScheme, "127.0.0.1", 29510)
}
smfContext.NrfCertPem = configuration.NrfCertPem

if pfcp := configuration.PFCP; pfcp != nil {
smfContext.ListenAddr = pfcp.ListenAddr
Expand Down Expand Up @@ -283,3 +287,13 @@ func GetUserPlaneInformation() *UserPlaneInformation {
func GetUEDefaultPathPool(groupName string) *UEDefaultPaths {
return smfContext.UEDefaultPathPool[groupName]
}

func (c *SMFContext) GetTokenCtx(scope, targetNF string) (
context.Context, *models.ProblemDetails, error,
) {
if !c.OAuth2Required {
return context.TODO(), nil, nil
}
return oauth.GetTokenCtx(models.NfType_SMF,
c.NfInstanceID, c.NrfUri, scope, targetNF)
}
7 changes: 5 additions & 2 deletions internal/context/sm_context.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package context

import (
"context"
"fmt"
"math"
"net"
Expand Down Expand Up @@ -410,6 +409,10 @@ func (smContext *SMContext) PDUAddressToNAS() ([12]byte, uint8) {

// PCFSelection will select PCF for this SM Context
func (smContext *SMContext) PCFSelection() error {
ctx, _, err := GetSelf().GetTokenCtx("nnrf-disc", "NRF")
if err != nil {
return err
}
// Send NFDiscovery for find PCF
localVarOptionals := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{}

Expand All @@ -420,7 +423,7 @@ func (smContext *SMContext) PCFSelection() error {
rep, res, err := GetSelf().
NFDiscoveryClient.
NFInstancesStoreApi.
SearchNFInstances(context.TODO(), models.NfType_PCF, models.NfType_SMF, &localVarOptionals)
SearchNFInstances(ctx, models.NfType_PCF, models.NfType_SMF, &localVarOptionals)
if err != nil {
return err
}
Expand Down
154 changes: 18 additions & 136 deletions internal/sbi/consumer/nnrf.go → internal/sbi/consumer/nf_discovery.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package consumer

import (
"context"
"fmt"
"net/http"
"strings"
"time"

"github.com/antihax/optional"
"github.com/mohae/deepcopy"
Expand All @@ -18,115 +14,19 @@ import (
"github.com/free5gc/smf/internal/logger"
)

func SendNFRegistration() error {
smfProfile := smf_context.NFProfile

sNssais := []models.Snssai{}
for _, snssaiSmfInfo := range *smfProfile.SMFInfo.SNssaiSmfInfoList {
sNssais = append(sNssais, *snssaiSmfInfo.SNssai)
}

// set nfProfile
profile := models.NfProfile{
NfInstanceId: smf_context.GetSelf().NfInstanceID,
NfType: models.NfType_SMF,
NfStatus: models.NfStatus_REGISTERED,
Ipv4Addresses: []string{smf_context.GetSelf().RegisterIPv4},
NfServices: smfProfile.NFServices,
SmfInfo: smfProfile.SMFInfo,
SNssais: &sNssais,
PlmnList: smfProfile.PLMNList,
}
if smf_context.GetSelf().Locality != "" {
profile.Locality = smf_context.GetSelf().Locality
}
var rep models.NfProfile
var res *http.Response
var err error

// Check data (Use RESTful PUT)
for {
rep, res, err = smf_context.GetSelf().
NFManagementClient.
NFInstanceIDDocumentApi.
RegisterNFInstance(context.TODO(), smf_context.GetSelf().NfInstanceID, profile)
if err != nil || res == nil {
logger.ConsumerLog.Infof("SMF register to NRF Error[%s]", err.Error())
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.LastIndex(resourceUri, "/"):]
smf_context.GetSelf().NfInstanceID = resourceUri[strings.LastIndex(resourceUri, "/")+1:]
break
} else {
logger.ConsumerLog.Infof("handler returned wrong status code %d", status)
// fmt.Errorf("NRF return wrong status code %d", status)
}
}

logger.InitLog.Infof("SMF Registration to NRF %v", rep)
return nil
}

func RetrySendNFRegistration(MaxRetry int) error {
retryCount := 0
for retryCount < MaxRetry {
err := SendNFRegistration()
if err == nil {
return nil
}
logger.ConsumerLog.Warnf("Send NFRegistration Failed by %v", err)
retryCount++
}

return fmt.Errorf("[SMF] Retry NF Registration has meet maximum")
}

func SendNFDeregistration() error {
// Check data (Use RESTful DELETE)
res, localErr := smf_context.GetSelf().
NFManagementClient.
NFInstanceIDDocumentApi.
DeregisterNFInstance(context.TODO(), smf_context.GetSelf().NfInstanceID)
if localErr != nil {
logger.ConsumerLog.Warnln(localErr)
return localErr
}
defer func() {
if resCloseErr := res.Body.Close(); resCloseErr != nil {
logger.ConsumerLog.Errorf("DeregisterNFInstance response body cannot close: %+v", resCloseErr)
}
}()
if res != nil {
if status := res.StatusCode; status != http.StatusNoContent {
logger.ConsumerLog.Warnln("handler returned wrong status code ", status)
return openapi.ReportError("handler returned wrong status code %d", status)
}
func SendNFDiscoveryUDM() (*models.ProblemDetails, error) {
ctx, pd, err := smf_context.GetSelf().GetTokenCtx("nnrf-disc", "NRF")
if err != nil {
return pd, err
}
return nil
}

func SendNFDiscoveryUDM() (*models.ProblemDetails, error) {
localVarOptionals := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{}

// Check data
result, httpResp, localErr := smf_context.GetSelf().
NFDiscoveryClient.
NFInstancesStoreApi.
SearchNFInstances(context.TODO(), models.NfType_UDM, models.NfType_SMF, &localVarOptionals)
SearchNFInstances(ctx, models.NfType_UDM, models.NfType_SMF, &localVarOptionals)

if localErr == nil {
smf_context.GetSelf().UDMProfile = result.NfInstances[0]
Expand Down Expand Up @@ -161,6 +61,11 @@ func SendNFDiscoveryUDM() (*models.ProblemDetails, error) {
}

func SendNFDiscoveryPCF() (problemDetails *models.ProblemDetails, err error) {
ctx, pd, err := smf_context.GetSelf().GetTokenCtx("nnrf-disc", "NRF")
if err != nil {
return pd, err
}

// Set targetNfType
targetNfType := models.NfType_PCF
// Set requestNfType
Expand All @@ -171,7 +76,7 @@ func SendNFDiscoveryPCF() (problemDetails *models.ProblemDetails, err error) {
result, httpResp, localErr := smf_context.GetSelf().
NFDiscoveryClient.
NFInstancesStoreApi.
SearchNFInstances(context.TODO(), targetNfType, requesterNfType, &localVarOptionals)
SearchNFInstances(ctx, targetNfType, requesterNfType, &localVarOptionals)

if localErr == nil {
logger.ConsumerLog.Traceln(result.NfInstances)
Expand All @@ -184,7 +89,7 @@ func SendNFDiscoveryPCF() (problemDetails *models.ProblemDetails, err error) {
logger.ConsumerLog.Warnln("handler returned wrong status code ", httpResp.Status)
if httpResp.Status != localErr.Error() {
err = localErr
return
return problemDetails, err
}
problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails)
problemDetails = &problem
Expand All @@ -196,6 +101,11 @@ func SendNFDiscoveryPCF() (problemDetails *models.ProblemDetails, err error) {
}

func SendNFDiscoveryServingAMF(smContext *smf_context.SMContext) (*models.ProblemDetails, error) {
ctx, pd, err := smf_context.GetSelf().GetTokenCtx("nnrf-disc", "NRF")
if err != nil {
return pd, err
}

targetNfType := models.NfType_AMF
requesterNfType := models.NfType_SMF

Expand All @@ -207,7 +117,7 @@ func SendNFDiscoveryServingAMF(smContext *smf_context.SMContext) (*models.Proble
result, httpResp, localErr := smf_context.GetSelf().
NFDiscoveryClient.
NFInstancesStoreApi.
SearchNFInstances(context.TODO(), targetNfType, requesterNfType, &localVarOptionals)
SearchNFInstances(ctx, targetNfType, requesterNfType, &localVarOptionals)

if localErr == nil {
if result.NfInstances == nil {
Expand Down Expand Up @@ -236,31 +146,3 @@ func SendNFDiscoveryServingAMF(smContext *smf_context.SMContext) (*models.Proble

return nil, nil
}

func SendDeregisterNFInstance() (*models.ProblemDetails, error) {
logger.ConsumerLog.Infof("Send Deregister NFInstance")

smfSelf := smf_context.GetSelf()
// Set client and set url

res, err := smfSelf.
NFManagementClient.
NFInstanceIDDocumentApi.
DeregisterNFInstance(context.Background(), smfSelf.NfInstanceID)
if err == nil {
return nil, err
} else if res != nil {
defer func() {
if resCloseErr := res.Body.Close(); resCloseErr != nil {
logger.ConsumerLog.Errorf("DeregisterNFInstance 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")
}
}
Loading

0 comments on commit 71201ec

Please sign in to comment.