Authentication Mechanism in NRF: What Is OAuth?
Note
Author: Wilson
Date: 2023/8/2
Abstract
Regarding the theme this time, I will briefly introduce OAuth. OAuth 2.0 defines four types of authorization flows. I choose the Client Credentials Flow to explain because the authentication mechanism in NRF is closely related to the Client Credentials Flow.
Next, I will explain how to apply the concept of the Client Credentials Flow to NRF and introduce Nnrf_AccessToken Service
, because Nnrf_AccessToken Service
is closely related to the Client Credentials Flow.
Finally, I will make a simple experiment of the authentication mechanism in NRF and share the environment settings and methods of operation.
OAuth
Before explaining the authentication mechanism in NRF, I will introduce OAuth. Regarding the OAuth flow, we can log in to the account through the platform before accessing an application. After logging in, we agree that an application can limitedly obtain the information of the user on the platform. The application can be LinkedIn, YouTube, etc. The platform can be Google, Facebook, etc.
The full English name of OAuth is Open standard Authorization. OAuth is an open standard, and it's used to deal with authorization-related behaviors. OAuth 2.0 defines four types of authorization flows. The four types of the authorization flows are:
- Authorization Code
- Implicit
- Resource Owner Password Credentials
- Client Credentials
This article explains the entire authorization of the Client Credentials Flow only, because the authentication mechanism in NRF adopts the Client Credentials.
If you're interested in how authorization mechanism works, please refer to this article for more details.
Client Credentials Flow
Figure 1. Client Credentials Flow
Referring to the Figure 1, the Client Credentials Flow is mainly composed of:
- Client
- Authorization Server
- Resource Server
The entire authorization of the Client Credentials Flow can be devided into 3 steps:
- First, the Client provdies Client ID, Client Secret Token, Scope, and Grant Type to the Authorization Server.
- Second, the Authorization Server verifies the information provided by the Client. After the Authorization Server verifies the information, it signs with the private key and sends the Access Token to the Client.
- Third, the Client obtains resources from the Resource Server with the Access Token.
In addition, the Client and the Authorization Server have their own Scope list. The Scope list records a series of the actions. The Client or the Authorization Server is permitted to do the actions for obtaining the user’s name, deleting posts, etc.
Below I will explain how to apply the Client Credentials Flow to NRF after talking about the Client Credentials Flow.
Client Credentials Flow in NRF
The Figure 2 and the Figure 3 originate from the Figure 13.4.1.1-1 and the Figure 13.4.1.1-2 of the TS 33.501.
Figure 2. NF Service Consumer Obtaining Access Token before NF Service Access
The entire flow in Figure 2 is the same as Step 1 and Step 2 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Authorization Server is played by the NRF.
First, the NF Service Consumer registers with NRF. Then the NF Service Consumer sends the Nnrf_AccessToken_Get Request
to NRF. The Nnrf_AccessToken_Get Request
includes:
- Consumer NF Type
- Expected NF Type
- Expected NF Service Name
- Client ID
The NF Type can be AMF, SMF, etc. , and the NF Service Name can be namf-comm
, nsmf-pdusession
, etc.
NRF verifies the information provided by the NF Service Consumer after it receives the Nnrf_AccessToken_Get Request
. NRF generates an Access Token and uses the NRF private key to sign on the Access Token after the verification is successful.
Finally, NRF returns the Nnrf_AccessToken_Get Response
to the NF Service Consumer. The NF Service Consumer stores the Access Token within the validity period after it gets the Access Token. The services provided by the NF Service Producer are in the Expected NF Service Name. The NF Service Consumer doesn’t need to verify again when it wants to use the services provided by the NF Service Producer.
Figure 3. NF Service Consumer Requesting Service Access with an Access Token
The entire flow in Figure 3 is the same as Step 3 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Resource Server is played by the NF Service Producer.
First, the NF Service Consumer sends the NF Service Request
to the NF Service Producer with the Access Token. Simply put, the NF Service Consumer wants to consume the service provided by the NF Service Producer.
The NF Service Producer uses the NRF public key to verify the signed Access Token after it receives the NF Service Request
. If the verification is successful, the NF Service Producer will send the NF Service Response
to the NF Service Consumer.
Now I will talk about the Nnrf_AccessToken Service
after explaining how to apply the Client Credentials Flow to NRF.
Nnrf_AccessToken Service
Figure 4. Access Token Request
The Figure 4 originates from the Figure 5.4.2.2.1-1 of the TS 29.510.
First, the NF Service Consumer sends the POST /oauth2/token
to NRF, and the data is stored in the AccessTokenReq
. The attribute name, the data type, and the formulation rule of the AccessTokenReq
are shown in the Table 1. The Table 1 originates from the Table 6.3.5.2.2-1 of the TS 29.510.
Table 1. Definition of Type AccessTokenReq
Definition of type AccessTokenReq
:
grant_type
: The value must be set to the client_credentials, and it is checked in the Snippet 1.nfInstanceId
: The value stores the ID of the NF Service Consumer.targetNfInstanceId
: The value stores the ID of the NF Service Producer.nfType
: The value stores the network function name of the NF Service Consumer. The network function name can be the AMF, SMF, etc.targetNfType
: The value stores the network function name of the NF Service Producer.scope
: It stores the services. The services can be thenamf-comm
,nsmf-pdusession
, etc. When the NF Service Consumer requests the services. The services will be provided by the NF Service Producer.requesterPlmn
: It is mainly used in the roaming.targetPlmn
: It is mainly used in the roaming.
if reqGrantType != "client_credentials" {
return &models.AccessTokenErr{
Error: "unsupported_grant_type",
}
}
Snippet 1. Grant Type Value Checking
NRF sends AccessTokenRsp
to the NF Service Consumer in the Step 2a of the Figure 4. The attribute name, the data type, and the formulation rule of the AccessTokenRsp
are shown in the Table 2. The Table 2 originates from the Table 6.3.5.2.3-1 of the TS 29.510.
Table 2. Definition of Type AccessTokenRsp
The AccessTokenRsp
contains four attribute names. The four attribute names are:
access_token
: It stores all the attribute names and values of the AccessTokenClaims in the Table 3. The Table 3 originates form the Table 6.3.5.2.4-1 of the TS 29.510.token_type
: It must be set to the Bearer and can be seen in the Snippet 2.expires_in
: It stores information related to the expiration date.scope
: The NF Service Consumer and the NF Service Producer have their own scope list. The scope in theAccessTokenRsp
has a series of these services, and the NF Service Producer is permitted to consume these services.
Table 3. Definition of Type AccessTokenClaims
Definition of Type AccessTokenClaims
:
iss
: It is called issuer, and the content usually stores the ID of NRF.sub
: It is called subject, and the content stores the ID of the NF Service Consumer.aud
: It is called audience, and the content stores the ID of the NF Service Producer.scope
: The scope in theAccessTokenClaims
has a series of these services, and the NF Service Consumer is authorized by the NF Service Producer and permitted to consume these services.exp
: It stores information related to the validity period.
func AccessTokenProcedure(request models.AccessTokenReq) (
*models.AccessTokenRsp, *models.AccessTokenErr,
) {
logger.AccTokenLog.Infoln("In AccessTokenProcedure")
var expiration int32 = 1000
scope := request.Scope
tokenType := "Bearer"
now := int32(time.Now().Unix())
errResponse := AccessTokenScopeCheck(request)
if errResponse != nil {
return nil, errResponse
}
// Create AccessToken
nrfCtx := nrf_context.GetSelf()
accessTokenClaims := models.AccessTokenClaims{
Iss: nrfCtx.Nrf_NfInstanceID, // NF instance id of the NRF
Sub: request.NfInstanceId, // nfInstanceId of service consumer
Aud: request.TargetNfInstanceId, // nfInstanceId of service producer
Scope: request.Scope, // TODO: the name of the NF services for which the
Exp: now + expiration, // access_token is authorized for use
StandardClaims: jwt.StandardClaims{},
}
accessTokenClaims.IssuedAt = int64(now)
// Use NRF private key to sign AccessToken
token := jwt.NewWithClaims(jwt.GetSigningMethod("RS512"), accessTokenClaims)
accessToken, err := token.SignedString(nrfCtx.NrfPrivKey)
if err != nil {
logger.AccTokenLog.Warnln("Signed string error: ", err)
return nil, &models.AccessTokenErr{
Error: "invalid_request",
}
}
response := &models.AccessTokenRsp{
AccessToken: accessToken,
TokenType: tokenType,
ExpiresIn: expiration,
Scope: scope,
}
return response, nil
}
Snippet 2. AccessTokenProcedure Function
The Snippet 2 is the AccessTokenProcedure()
function. The function is executed in NRF.
The function mainly processes:
- The NRF receives the
AccessTokenReq
sent by the NF Service Consumer. - The function calls the
AccessTokenScopeCheck()
function. TheAccessTokenScopeCheck()
function checks whether the content of the attribute name in theAccessTokenReq
complies with the requirements of the TS 29.510. If not, theAccessTokenProcedure()
function immediately returns theAccessTokenErr
to the NF Service Consumer. - The function starts to create the Access Token. The Access Token is stored in the
AccessTokenRsp
. TheAccessTokenRsp
is sent back to the NF Service Consumer. TheIss
in the AccessToken obtains its own ID in NRF. TheSub
andAud
are obtained from theNfInstancedId
and theTargetNfInstanceId
in theAccessTokenReq
respectively. TheScope
is obtained from thescope
in theAccessTokenReq
. The expiration is set to the 1000 in the Snippet 2. Therefore, the value of theexp
is the current time + 1000. - After the Access Token is created, the function uses the NRF private key to sign on the Access Token. After signing, the function checks whether there is an error. If so, the function immediately sends the
AccessTokenErr
to the NF Service Consumer. - The function puts the signed Access Token into the
AccessTokenRsp
. The value of theTokenType
is set to the Bearer by the function. The function sets theExprieIn
and theScope
in the Snippet 2.
Finally, I make a simple experiment about the Access Token and share the environment setting and method of operation with you.
Experiment
The Table 4 is my environment setting. I provide the Table 4 for you. You can refer it.
Table 4. Environment
Remove the part of the tls
and add the content of the cert
, rootcert
and oauth
under sbi
in the nrfcfg.yaml
before implementing about the Access Token.
info:
version: 1.0.2
description: NRF initial local configuration
configuration:
MongoDBName: free5gc # database name in MongoDB
MongoDBUrl: mongodb://127.0.0.1:27017 # a valid URL of the mongodb
sbi: # Service-based interface information
scheme: http # the protocol for sbi (http or https)
registerIPv4: 127.0.0.10 # IP used to serve NFs or register to another NRF
bindingIPv4: 127.0.0.10 # IP used to bind the service
port: 8000 # port used to bind the service
cert:
pem: cert/nrf.pem
key: cert/nrf.key
rootcert:
pem: cert/nrf.pem
key: cert/nrf.key
oauth: true
DefaultPlmnId:
mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
serviceNameList: # the SBI services provided by this NRF, refer to TS 29.510
- nnrf-nfm # Nnrf_NFManagement service
- nnrf-disc # Nnrf_NFDiscovery service
logger: # log output setting
enable: true # true or false
level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
reportCaller: false # enable the caller report or not, value: true or false
nrfcfg.yaml
Find the http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
in the NRF log, and you will get the 8f7891b4-b127-4f59-9ec2-b5e6aade5531
. The 8f7891b4-b127-4f59-9ec2-b5e6aade5531
is the nfInstanceID
.
2023-08-02T20:07:43.300826205Z [INFO][NRF][NFM] Handle NFRegisterRequest
2023-08-02T20:07:43.308259291Z [INFO][NRF][NFM] urilist create
2023-08-02T20:07:43.311674255Z [INFO][NRF][NFM] Create NF Profile
2023-08-02T20:07:43.318192771Z [INFO][NRF][NFM] Location header: http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
2023-08-02T20:07:43.325073275Z [INFO][NRF][GIN] | 201 | 127.0.0.1 | PUT | /nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 |
Execute $ curl -X GET {apiRoot}/nnrf-nfm/v1/nf-instances/{nfInstanceID}
, and you will obtain the detail information about the nfInstanceID
. You can see the nfType
of the nfInstanceID
is NSSF, and the information about the nfInstanceID
is used when you implement the Access Token.
ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X GET http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
{"ipv4Addresses":["127.0.0.31"],"nfInstanceId":"8f7891b4-b127-4f59-9ec2-b5e6aade5531","nfServices":[{"apiPrefix":"http://127.0.0.31:8000","ipEndPoints":[{"ipv4Address":"127.0.0.31","port":8000,"transport":"TCP"}],"nfServiceStatus":"REGISTERED","scheme":"http","serviceInstanceId":"0","serviceName":"nnssf-nsselection","versions":[{"apiFullVersion":"1.0.2","apiVersionInUri":"v1"}]},{"apiPrefix":"http://127.0.0.31:8000","ipEndPoints":[{"ipv4Address":"127.0.0.31","port":8000,"transport":"TCP"}],"nfServiceStatus":"REGISTERED","scheme":"http","serviceInstanceId":"1","serviceName":"nnssf-nssaiavailability","versions":[{"apiFullVersion":"1.0.2","apiVersionInUri":"v1"}]}],"nfStatus":"REGISTERED","nfType":"NSSF","plmnList":[{"mcc":"208","mnc":"93"}]}
Then you execute this command, see below.
$ curl -X POST -H "Content-Type: application/json" -d '{"nfInstanceId": {nfInstanceID}, "grant_type": "client_credentials", "nfType": {nfType}, "targetNfType": "UDR", "scope": "nudr-dr"}' {apiRoot}/oauth2/token
You will get the long symbols. The long symbols is that the Access Token is encrypted by the private key of NRF and stored in the
AccessTokenRsp
.
ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X POST -H "Content-Type: application/json" -d '{"nfInstanceId": "8f7891b4-b127-4f59-9ec2-b5e6aade5531", "grant_type": "client_credentials", "nfType": "NSSF", "targetNfType": "UDR", "scope": "nudr-dr"}' http://127.0.0.10:8000/oauth2/token
"eyJhY2Nlc3NfdG9rZW4iOiJleUpoYkdjaU9pSlNVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKcGMzTWlPaUlpTENKemRXSWlPaUk0WmpjNE9URmlOQzFpTVRJM0xUUm1OVGt0T1dWak1pMWlOV1UyWVdGa1pUVTFNekVpTENKaGRXUWlPaUlpTENKelkyOXdaU0k2SW01MVpISXRaSElpTENKbGVIQWlPakUyT1RFd01EZzBPRGdzSW1saGRDSTZNVFk1TVRBd056UTRPSDAuY3VHSkkwTndfV280S2lQbS1fZEZVdnVTQWM1WVEwMmRKYk5PTUhmMV9IOHdIZ2JKWFhUam9xU1Y2OTNYSmFKemkweGIxdC1DMW14TWhVZkZjbXpNMC1Nd2oxTXZYaWhyTTktdDFRUFItSFcxQlBlN0tHMUxBV3d5MEJfcXpIalltRlR6eGhONVlyNkpURDhBbkMxaFJFeEh4WHBjV1NqbV9vZnV0NVhfUFRFRkZtaHZrbmtVbU8waWFrTmdRWElRVTc1NnlvZ29ZTlFDRnJvSmRWamJMdnpFdkJLYTVFN0hQeXc3RkRDRHpTZU5WT2t2WTlobU11eldYZ3dOVmRIT3c1c2lNbmppbTlmTVZ0RTFxS1hjWDlScXlUdXlsWjM2ZlJ1QjdVZ2hkLU15Q19xd2VJRE41ZFdYOWZqdnA3VUNZZ01mVHhSLUI2M3d5OWFjQ183eThRIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImV4cGlyZXNfaW4iOjEwMDAsInNjb3BlIjoibnVkci1kciJ9"
NSSF sends the AccessTokenReq
to NRF after you execute the above command. In the AccessTokenReq
, the nfInstanceId
is set to 8f7891b4-b127-4f59-9ec2-b5e6aade5531
. The grant_type
is set to the client_credentials. The nfType
is set to NSSF. The targetNfType
is set to UDR. The scope
is set to nudr-dr
. The information is shown in the NRF log. The value of the targetNfInstanceId
, requesterPlmn
, and targetPlmn
is empty because they are not set.
2023-08-02T20:18:08.127557565Z [INFO][NRF][Token] In AccessTokenProcedure
2023-08-02T20:18:08.127586736Z [INFO][NRF][Token] Access Token Request
2023-08-02T20:18:08.127611885Z [INFO][NRF][Token] Grant Type: client_credentials
2023-08-02T20:18:08.127637480Z [INFO][NRF][Token] NF Instance ID: 8f7891b4-b127-4f59-9ec2-b5e6aade5531
2023-08-02T20:18:08.127664415Z [INFO][NRF][Token] Target NF Instance ID:
2023-08-02T20:18:08.127689792Z [INFO][NRF][Token] NF Type: NSSF
2023-08-02T20:18:08.127712916Z [INFO][NRF][Token] Target NF Type: UDR
2023-08-02T20:18:08.127734827Z [INFO][NRF][Token] Scope: nudr-dr
2023-08-02T20:18:08.127758317Z [INFO][NRF][Token] Requester PLMN: <nil>
2023-08-02T20:18:08.127781052Z [INFO][NRF][Token] Target PLMN: <nil>
Next, you can see the Access Token in the NRF log. The value of the Sub
is 8f7891b4-b127-4f59-9ec2-b5e6aade5531
. The Sub
represents NSSF, and NSSF belongs to the NF Service Consumer. The value of the Scope
is the nudr-dr
. The value of the Exp
is 1691008488.
2023-08-02T20:18:08.134096785Z [INFO][NRF][Token] Access Token Claims
2023-08-02T20:18:08.138100978Z [INFO][NRF][Token] Iss:
2023-08-02T20:18:08.138185972Z [INFO][NRF][Token] Sub: 8f7891b4-b127-4f59-9ec2-b5e6aade5531
2023-08-02T20:18:08.138228925Z [INFO][NRF][Token] Aud:
2023-08-02T20:18:08.138264519Z [INFO][NRF][Token] Scope: nudr-dr
2023-08-02T20:18:08.138298628Z [INFO][NRF][Token] Exp: 1691008488
Next, you can see the AccessTokenRsp
. You can see that the Access Token has become the long symbols. The value of the Token Type
is set to the Bearer. The value of the ExpiresIn
is set to 1000. The value of the Scope
is set to nudr-dr
.
2023-08-02T20:18:08.149587382Z [INFO][NRF][Token] Access Token Response
2023-08-02T20:18:08.150006665Z [INFO][NRF][Token] Access Token: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiI4Zjc4OTFiNC1iMTI3LTRmNTktOWVjMi1iNWU2YWFkZTU1MzEiLCJhdWQiOiIiLCJzY29wZSI6Im51ZHItZHIiLCJleHAiOjE2OTEwMDg0ODgsImlhdCI6MTY5MTAwNzQ4OH0.cuGJI0Nw_Wo4KiPm-_dFUvuSAc5YQ02dJbNOMHf1_H8wHgbJXXTjoqSV693XJaJzi0xb1t-C1mxMhUfFcmzM0-Mwj1MvXihrM9-t1QPR-HW1BPe7KG1LAWwy0B_qzHjYmFTzxhN5Yr6JTD8AnC1hRExHxXpcWSjm_ofut5X_PTEFFmhvknkUmO0iakNgQXIQU756yogoYNQCFroJdVjbLvzEvBKa5E7HPyw7FDCDzSeNVOkvY9hmMuzWXgwNVdHOw5siMnjim9fMVtE1qKXcX9RqyTuylZ36fRuB7Ughd-MyC_qweIDN5dWX9fjvp7UCYgMfTxR-B63wy9acC_7y8Q
2023-08-02T20:18:08.150094277Z [INFO][NRF][Token] Token Type: Bearer
2023-08-02T20:18:08.150133189Z [INFO][NRF][Token] Expires In: 1000
2023-08-02T20:18:08.150167371Z [INFO][NRF][Token] Scope: nudr-dr
Finally, you can see 200. 200 means that AUSF sends the AccessTokenReq
to NRF. NRF successfully sends to AUSF after verification.
2023-08-02T20:18:08.150302345Z [INFO][NRF][GIN] | 200 | 127.0.0.1 | POST | /oauth2/token |
Reference
- TS 29.510
- TS 33.501
- [Notes] Understanding OAuth 2.0: Understand the differences of each role and each type of process at one time
- https://blog.techbridge.cc/2019/02/01/linux-curl-command-tutorial/
- https://github.com/free5gc/free5gc/issues/434
About
Hi, my name is Wilson. I am a master’s student. My main area of research is network slicing. In the future, I will introduce more information about 5G. Hope you enjoy it.