diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6e79016e5..32abfc32d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,6 +17,15 @@ pr: - 202??? - 201??? +variables: + - name: BUILD_BRANCH + ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: + value: $(System.PullRequest.TargetBranch) + ${{ else }}: + value: $(Build.SourceBranchName) + - name: UNIT_TEST_FLAG + value: 'ENABLE_TRANSLIB_WRITE=y' + resources: repositories: - repository: sonic-mgmt-common @@ -28,6 +37,7 @@ resources: type: github name: sonic-net/sonic-swss-common endpoint: sonic-net + ref: refs/heads/$(BUILD_BRANCH) stages: - stage: Build @@ -37,7 +47,7 @@ stages: timeoutInMinutes: 60 pool: - vmImage: ubuntu-20.04 + vmImage: ubuntu-22.04 variables: DIFF_COVER_CHECK_THRESHOLD: 80 @@ -67,28 +77,20 @@ stages: inputs: source: specific project: build - pipeline: 1 + pipeline: 142 artifact: sonic-buildimage.vs runVersion: 'latestFromBranch' - runBranch: 'refs/heads/master' + runBranch: 'refs/heads/$(BUILD_BRANCH)' patterns: | target/debs/bullseye/libyang*.deb target/debs/bullseye/libnl*.deb + target/python-wheels/bullseye/sonic_yang_models*.whl displayName: "Download bullseye debs" - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: build - pipeline: 127 - artifact: sonic-mgmt-common - runVersion: 'latestFromBranch' - runBranch: 'refs/heads/master' - displayName: "Download sonic-mgmt-common" - - script: | # PYTEST sudo pip3 install -U pytest + sudo pip3 install -U jsonpatch # REDIS sudo apt-get update @@ -102,6 +104,12 @@ stages: sudo dpkg -i ../target/debs/bullseye/libyang*1.0.73*.deb displayName: "Install dependency" + - script: | + # SONIC YANGS + set -ex + sudo pip3 install ../target/python-wheels/bullseye/sonic_yang_models-1.0-py3-none-any.whl + displayName: "Install sonic yangs" + - script: | # LIBSWSSCOMMON sudo apt-get -y purge libnl-3-dev libnl-route-3-dev @@ -127,7 +135,7 @@ stages: pipeline: Azure.sonic-swss-common artifact: sonic-swss-common runVersion: 'latestFromBranch' - runBranch: 'refs/heads/master' + runBranch: 'refs/heads/$(BUILD_BRANCH)' displayName: "Download sonic-swss-common" - script: | diff --git a/gnmi_server/clientCertAuth.go b/gnmi_server/clientCertAuth.go index db6ebe129..28ef86c55 100644 --- a/gnmi_server/clientCertAuth.go +++ b/gnmi_server/clientCertAuth.go @@ -1,6 +1,8 @@ package gnmi import ( + "strings" + "github.com/sonic-net/sonic-gnmi/common_utils" "github.com/sonic-net/sonic-gnmi/swsscommon" "github.com/golang/glog" @@ -58,7 +60,11 @@ func PopulateAuthStructByCommonName(certCommonName string, auth *common_utils.Au var fieldValuePairs = configDbConnector.Get_entry(serviceConfigTableName, certCommonName) if fieldValuePairs.Size() > 0 { - if fieldValuePairs.Has_key("role") { + if fieldValuePairs.Has_key("role@") { + var role = fieldValuePairs.Get("role@") + auth.Roles = strings.Split(role, ",") + } else if fieldValuePairs.Has_key("role") { + // Backward compatibility for single role DB schema var role = fieldValuePairs.Get("role") auth.Roles = []string{role} } diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index 0eee36fde..7cf8e3175 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -4202,6 +4202,71 @@ func CreateAuthorizationCtx() (context.Context, context.CancelFunc) { swsscommon.DeleteDBConnector(configDb) } +func TestClientCertAuthenAndAuthorMultiRole(t *testing.T) { + if !swsscommon.SonicDBConfigIsInit() { + swsscommon.SonicDBConfigInitialize() + } + + var configDb = swsscommon.NewDBConnector("CONFIG_DB", uint(0), true) + var gnmiTable = swsscommon.NewTable(configDb, "GNMI_CLIENT_CERT") + configDb.Flushdb() + + // initialize err variable + err := status.Error(codes.Unauthenticated, "") + + // when config table is empty, will authorize with PopulateAuthStruct + mockpopulate := gomonkey.ApplyFunc(PopulateAuthStruct, func(username string, auth *common_utils.AuthInfo, r []string) error { + return nil + }) + defer mockpopulate.Reset() + + // check auth with nil cert name + ctx, cancel := CreateAuthorizationCtx() + ctx, err = ClientCertAuthenAndAuthor(ctx, "") + if err != nil { + t.Errorf("CommonNameMatch with empty config table should success: %v", err) + } + + cancel() + + // check get 1 cert name + ctx, cancel = CreateAuthorizationCtx() + configDb.Flushdb() + gnmiTable.Hset("certname1", "role@", "readwrite") + ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT") + if err != nil { + t.Errorf("CommonNameMatch with correct cert name should success: %v", err) + } + + cancel() + + // check get multiple cert names + ctx, cancel = CreateAuthorizationCtx() + configDb.Flushdb() + gnmiTable.Hset("certname1", "role@", "readwrite") + gnmiTable.Hset("certname2", "role@", "readonly") + ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT") + if err != nil { + t.Errorf("CommonNameMatch with correct cert name should success: %v", err) + } + + cancel() + + // check a invalid cert cname + ctx, cancel = CreateAuthorizationCtx() + configDb.Flushdb() + gnmiTable.Hset("certname2", "role@", "readonly") + ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT") + if err == nil { + t.Errorf("CommonNameMatch with invalid cert name should fail: %v", err) + } + + cancel() + + swsscommon.DeleteTable(gnmiTable) + swsscommon.DeleteDBConnector(configDb) +} + type MockServerStream struct { grpc.ServerStream }