X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=capifcore%2Finternal%2Fsecurityservice%2Fsecurity_test.go;h=ea0fbe6930f176de773fdcf542e56a63f70734a8;hb=5493b0faf67fc5b58b575880db528eb2b663d45a;hp=7043cca1fc0b406421746497168d3c6b21546818;hpb=de80bd1d75e2f9c410a0c626e4d03fa250fcb183;p=nonrtric%2Fplt%2Fsme.git diff --git a/capifcore/internal/securityservice/security_test.go b/capifcore/internal/securityservice/security_test.go index 7043cca..ea0fbe6 100644 --- a/capifcore/internal/securityservice/security_test.go +++ b/capifcore/internal/securityservice/security_test.go @@ -21,12 +21,16 @@ package security import ( + "errors" "fmt" "net/http" "net/url" "os" "testing" + "oransc.org/nonrtric/capifcore/internal/common29122" + "oransc.org/nonrtric/capifcore/internal/keycloak" + "oransc.org/nonrtric/capifcore/internal/publishserviceapi" "oransc.org/nonrtric/capifcore/internal/securityapi" "oransc.org/nonrtric/capifcore/internal/invokermanagement" @@ -35,9 +39,8 @@ import ( "github.com/labstack/echo/v4" - "oransc.org/nonrtric/capifcore/internal/common29122" - invokermocks "oransc.org/nonrtric/capifcore/internal/invokermanagement/mocks" + keycloackmocks "oransc.org/nonrtric/capifcore/internal/keycloak/mocks" servicemocks "oransc.org/nonrtric/capifcore/internal/providermanagement/mocks" publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks" @@ -57,7 +60,15 @@ func TestPostSecurityIdTokenInvokerRegistered(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true) - requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock) + jwt := keycloak.Jwttoken{ + AccessToken: "eyJhbGNIn0.e3YTQ0xLjEifQ.FcqCwCy7iJiOmw", + ExpiresIn: 300, + Scope: "3gpp#aefIdpath", + } + accessMgmMock := keycloackmocks.AccessManagement{} + accessMgmMock.On("GetToken", mock.AnythingOfType("string"), mock.AnythingOfType("map[string][]string")).Return(jwt, nil) + + requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) data := url.Values{} clientId := "id" @@ -65,9 +76,10 @@ func TestPostSecurityIdTokenInvokerRegistered(t *testing.T) { aefId := "aefId" path := "path" data.Set("client_id", clientId) - data.Add("client_secret", clientSecret) - data.Add("grant_type", "client_credentials") - data.Add("scope", "scope#"+aefId+":"+path) + data.Set("client_secret", clientSecret) + data.Set("grant_type", "client_credentials") + data.Set("scope", "3gpp#"+aefId+":"+path) + encodedData := data.Encode() result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler) @@ -77,38 +89,36 @@ func TestPostSecurityIdTokenInvokerRegistered(t *testing.T) { err := result.UnmarshalBodyToObject(&resultResponse) assert.NoError(t, err, "error unmarshaling response") assert.NotEmpty(t, resultResponse.AccessToken) - assert.Equal(t, "scope#"+aefId+":"+path, *resultResponse.Scope) assert.Equal(t, securityapi.AccessTokenRspTokenTypeBearer, resultResponse.TokenType) - assert.Equal(t, common29122.DurationSec(0), resultResponse.ExpiresIn) invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", clientId) invokerRegisterMock.AssertCalled(t, "VerifyInvokerSecret", clientId, clientSecret) serviceRegisterMock.AssertCalled(t, "IsFunctionRegistered", aefId) publishRegisterMock.AssertCalled(t, "IsAPIPublished", aefId, path) + accessMgmMock.AssertNumberOfCalls(t, "GetToken", 1) } func TestPostSecurityIdTokenInvokerNotRegistered(t *testing.T) { invokerRegisterMock := invokermocks.InvokerRegister{} invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(nil, nil, &invokerRegisterMock) + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") data.Add("client_secret", "secret") data.Add("grant_type", "client_credentials") - data.Add("scope", "scope#aefId:path") + data.Add("scope", "3gpp#aefId:path") encodedData := data.Encode() result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler) assert.Equal(t, http.StatusBadRequest, result.Code()) - var problemDetails common29122.ProblemDetails - err := result.UnmarshalBodyToObject(&problemDetails) + var errDetails securityapi.AccessTokenErr + err := result.UnmarshalBodyToObject(&errDetails) assert.NoError(t, err, "error unmarshaling response") - badRequest := http.StatusBadRequest - assert.Equal(t, &badRequest, problemDetails.Status) + assert.Equal(t, securityapi.AccessTokenErrErrorInvalidClient, errDetails.Error) errMsg := "Invoker not registered" - assert.Equal(t, &errMsg, problemDetails.Cause) + assert.Equal(t, &errMsg, errDetails.ErrorDescription) } func TestPostSecurityIdTokenInvokerSecretNotValid(t *testing.T) { @@ -116,25 +126,24 @@ func TestPostSecurityIdTokenInvokerSecretNotValid(t *testing.T) { invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(nil, nil, &invokerRegisterMock) + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") data.Add("client_secret", "secret") data.Add("grant_type", "client_credentials") - data.Add("scope", "scope#aefId:path") + data.Add("scope", "3gpp#aefId:path") encodedData := data.Encode() result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler) assert.Equal(t, http.StatusBadRequest, result.Code()) - var problemDetails common29122.ProblemDetails - err := result.UnmarshalBodyToObject(&problemDetails) + var errDetails securityapi.AccessTokenErr + err := result.UnmarshalBodyToObject(&errDetails) assert.NoError(t, err, "error unmarshaling response") - badRequest := http.StatusBadRequest - assert.Equal(t, &badRequest, problemDetails.Status) + assert.Equal(t, securityapi.AccessTokenErrErrorUnauthorizedClient, errDetails.Error) errMsg := "Invoker secret not valid" - assert.Equal(t, &errMsg, problemDetails.Cause) + assert.Equal(t, &errMsg, errDetails.ErrorDescription) } func TestPostSecurityIdTokenFunctionNotRegistered(t *testing.T) { @@ -144,25 +153,24 @@ func TestPostSecurityIdTokenFunctionNotRegistered(t *testing.T) { serviceRegisterMock := servicemocks.ServiceRegister{} serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(&serviceRegisterMock, nil, &invokerRegisterMock) + requestHandler, _ := getEcho(&serviceRegisterMock, nil, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") data.Add("client_secret", "secret") data.Add("grant_type", "client_credentials") - data.Add("scope", "scope#aefId:path") + data.Add("scope", "3gpp#aefId:path") encodedData := data.Encode() result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler) assert.Equal(t, http.StatusBadRequest, result.Code()) - var problemDetails common29122.ProblemDetails - err := result.UnmarshalBodyToObject(&problemDetails) + var errDetails securityapi.AccessTokenErr + err := result.UnmarshalBodyToObject(&errDetails) assert.NoError(t, err, "error unmarshaling response") - badRequest := http.StatusBadRequest - assert.Equal(t, &badRequest, problemDetails.Status) - errMsg := "Function not registered" - assert.Equal(t, &errMsg, problemDetails.Cause) + assert.Equal(t, securityapi.AccessTokenErrErrorInvalidScope, errDetails.Error) + errMsg := "AEF Function not registered" + assert.Equal(t, &errMsg, errDetails.ErrorDescription) } func TestPostSecurityIdTokenAPINotPublished(t *testing.T) { @@ -174,28 +182,416 @@ func TestPostSecurityIdTokenAPINotPublished(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock) + requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") data.Add("client_secret", "secret") data.Add("grant_type", "client_credentials") - data.Add("scope", "scope#aefId:path") + data.Add("scope", "3gpp#aefId:path") encodedData := data.Encode() result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler) assert.Equal(t, http.StatusBadRequest, result.Code()) + var errDetails securityapi.AccessTokenErr + err := result.UnmarshalBodyToObject(&errDetails) + assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, securityapi.AccessTokenErrErrorInvalidScope, errDetails.Error) + errMsg := "API not published" + assert.Equal(t, &errMsg, errDetails.ErrorDescription) +} + +func TestPostSecurityIdTokenInvokerInvalidCredentials(t *testing.T) { + invokerRegisterMock := invokermocks.InvokerRegister{} + invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) + invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true) + serviceRegisterMock := servicemocks.ServiceRegister{} + serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(true) + publishRegisterMock := publishmocks.PublishRegister{} + publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true) + + jwt := keycloak.Jwttoken{} + accessMgmMock := keycloackmocks.AccessManagement{} + accessMgmMock.On("GetToken", mock.AnythingOfType("string"), mock.AnythingOfType("map[string][]string")).Return(jwt, errors.New("invalid_credentials")) + + requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) + + data := url.Values{} + clientId := "id" + clientSecret := "secret" + aefId := "aefId" + path := "path" + data.Set("client_id", clientId) + data.Set("client_secret", clientSecret) + data.Set("grant_type", "client_credentials") + data.Set("scope", "3gpp#"+aefId+":"+path) + + encodedData := data.Encode() + + result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler) + + assert.Equal(t, http.StatusBadRequest, result.Code()) + var resultResponse securityapi.AccessTokenErr + err := result.UnmarshalBodyToObject(&resultResponse) + assert.NoError(t, err, "error unmarshaling response") + invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", clientId) + invokerRegisterMock.AssertCalled(t, "VerifyInvokerSecret", clientId, clientSecret) + serviceRegisterMock.AssertCalled(t, "IsFunctionRegistered", aefId) + publishRegisterMock.AssertCalled(t, "IsAPIPublished", aefId, path) + accessMgmMock.AssertNumberOfCalls(t, "GetToken", 1) +} + +func TestPutTrustedInvokerSuccessfully(t *testing.T) { + invokerRegisterMock := invokermocks.InvokerRegister{} + invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) + aefId := "aefId" + aefProfile := getAefProfile(aefId) + aefProfile.SecurityMethods = &[]publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodPKI, + } + aefProfiles := []publishserviceapi.AefProfile{ + aefProfile, + } + apiId := "apiId" + publishedServices := []publishserviceapi.ServiceAPIDescription{ + { + ApiId: &apiId, + AefProfiles: &aefProfiles, + }, + } + publishRegisterMock := publishmocks.PublishRegister{} + publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) + + requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) + + invokerId := "invokerId" + serviceSecurityUnderTest := getServiceSecurity(aefId, apiId) + serviceSecurityUnderTest.SecurityInfo[0].ApiId = &apiId + + result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler) + + assert.Equal(t, http.StatusCreated, result.Code()) + var resultResponse securityapi.ServiceSecurity + err := result.UnmarshalBodyToObject(&resultResponse) + assert.NoError(t, err, "error unmarshaling response") + assert.NotEmpty(t, resultResponse.NotificationDestination) + + for _, security := range resultResponse.SecurityInfo { + assert.Equal(t, *security.ApiId, apiId) + assert.Equal(t, *security.SelSecurityMethod, publishserviceapi.SecurityMethodPKI) + } + invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId) +} + +func TestPutTrustedInkoverNotRegistered(t *testing.T) { + invokerRegisterMock := invokermocks.InvokerRegister{} + invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false) + + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) + + invokerId := "invokerId" + serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId") + + result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler) + + badRequest := http.StatusBadRequest + assert.Equal(t, badRequest, result.Code()) var problemDetails common29122.ProblemDetails err := result.UnmarshalBodyToObject(&problemDetails) assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, &badRequest, problemDetails.Status) + assert.Contains(t, *problemDetails.Cause, "Invoker not registered") + invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId) +} + +func TestPutTrustedInkoverInvalidInputServiceSecurity(t *testing.T) { + invokerRegisterMock := invokermocks.InvokerRegister{} + invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) + + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) + + invokerId := "invokerId" + notificationUrl := "url" + serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId") + serviceSecurityUnderTest.NotificationDestination = common29122.Uri(notificationUrl) + + result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler) + badRequest := http.StatusBadRequest + assert.Equal(t, badRequest, result.Code()) + var problemDetails common29122.ProblemDetails + err := result.UnmarshalBodyToObject(&problemDetails) + assert.NoError(t, err, "error unmarshaling response") assert.Equal(t, &badRequest, problemDetails.Status) - errMsg := "API not published" - assert.Equal(t, &errMsg, problemDetails.Cause) + assert.Contains(t, *problemDetails.Cause, "ServiceSecurity has invalid notificationDestination") + invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId) +} + +func TestPutTrustedInvokerInterfaceDetailsNotNil(t *testing.T) { + invokerRegisterMock := invokermocks.InvokerRegister{} + invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) + aefId := "aefId" + aefProfile := getAefProfile(aefId) + aefProfile.SecurityMethods = &[]publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodPKI, + } + aefProfiles := []publishserviceapi.AefProfile{ + aefProfile, + } + apiId := "apiId" + publishedServices := []publishserviceapi.ServiceAPIDescription{ + { + ApiId: &apiId, + AefProfiles: &aefProfiles, + }, + } + publishRegisterMock := publishmocks.PublishRegister{} + publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) + + requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) + + invokerId := "invokerId" + serviceSecurityUnderTest := getServiceSecurity(aefId, apiId) + serviceSecurityUnderTest.SecurityInfo[0] = securityapi.SecurityInformation{ + ApiId: &apiId, + PrefSecurityMethods: []publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodOAUTH, + }, + InterfaceDetails: &publishserviceapi.InterfaceDescription{ + SecurityMethods: &[]publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodPSK, + }, + }, + } + + result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler) + + assert.Equal(t, http.StatusCreated, result.Code()) + var resultResponse securityapi.ServiceSecurity + err := result.UnmarshalBodyToObject(&resultResponse) + assert.NoError(t, err, "error unmarshaling response") + assert.NotEmpty(t, resultResponse.NotificationDestination) + + for _, security := range resultResponse.SecurityInfo { + assert.Equal(t, apiId, *security.ApiId) + assert.Equal(t, publishserviceapi.SecurityMethodPSK, *security.SelSecurityMethod) + } + invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId) } -func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister publishservice.PublishRegister, invokerRegister invokermanagement.InvokerRegister) *echo.Echo { +func TestPutTrustedInvokerNotFoundSecurityMethod(t *testing.T) { + invokerRegisterMock := invokermocks.InvokerRegister{} + invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) + + aefProfiles := []publishserviceapi.AefProfile{ + getAefProfile("aefId"), + } + apiId := "apiId" + publishedServices := []publishserviceapi.ServiceAPIDescription{ + { + ApiId: &apiId, + AefProfiles: &aefProfiles, + }, + } + publishRegisterMock := publishmocks.PublishRegister{} + publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) + + accessMgmMock := keycloackmocks.AccessManagement{} + accessMgmMock.On("AddClient", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(nil) + + requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) + + invokerId := "invokerId" + serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId") + + result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler) + + badRequest := http.StatusBadRequest + assert.Equal(t, badRequest, result.Code()) + var problemDetails common29122.ProblemDetails + err := result.UnmarshalBodyToObject(&problemDetails) + assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, &badRequest, problemDetails.Status) + assert.Contains(t, *problemDetails.Cause, "not found") + assert.Contains(t, *problemDetails.Cause, "security method") + invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId) +} + +func TestDeleteSecurityContext(t *testing.T) { + + requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil) + + aefId := "aefId" + apiId := "apiId" + serviceSecurityUnderTest := getServiceSecurity(aefId, apiId) + serviceSecurityUnderTest.SecurityInfo[0].ApiId = &apiId + + invokerId := "invokerId" + securityUnderTest.trustedInvokers[invokerId] = serviceSecurityUnderTest + + // Delete the security context + result := testutil.NewRequest().Delete("/trustedInvokers/"+invokerId).Go(t, requestHandler) + + assert.Equal(t, http.StatusNoContent, result.Code()) + _, ok := securityUnderTest.trustedInvokers[invokerId] + assert.False(t, ok) +} + +func TestGetSecurityContextByInvokerId(t *testing.T) { + + requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil) + + aefId := "aefId" + apiId := "apiId" + authenticationInfo := "authenticationInfo" + authorizationInfo := "authorizationInfo" + serviceSecurityUnderTest := getServiceSecurity(aefId, apiId) + serviceSecurityUnderTest.SecurityInfo[0].AuthenticationInfo = &authenticationInfo + serviceSecurityUnderTest.SecurityInfo[0].AuthorizationInfo = &authorizationInfo + + invokerId := "invokerId" + securityUnderTest.trustedInvokers[invokerId] = serviceSecurityUnderTest + + // Get security context + result := testutil.NewRequest().Get("/trustedInvokers/"+invokerId).Go(t, requestHandler) + + assert.Equal(t, http.StatusOK, result.Code()) + var resultService securityapi.ServiceSecurity + err := result.UnmarshalBodyToObject(&resultService) + assert.NoError(t, err, "error unmarshaling response") + + for _, secInfo := range resultService.SecurityInfo { + assert.Equal(t, apiId, *secInfo.ApiId) + assert.Equal(t, aefId, *secInfo.AefId) + assert.Equal(t, "", *secInfo.AuthenticationInfo) + assert.Equal(t, "", *secInfo.AuthorizationInfo) + } + + result = testutil.NewRequest().Get("/trustedInvokers/"+invokerId+"?authenticationInfo=true&authorizationInfo=false").Go(t, requestHandler) + assert.Equal(t, http.StatusOK, result.Code()) + err = result.UnmarshalBodyToObject(&resultService) + assert.NoError(t, err, "error unmarshaling response") + + for _, secInfo := range resultService.SecurityInfo { + assert.Equal(t, authenticationInfo, *secInfo.AuthenticationInfo) + assert.Equal(t, "", *secInfo.AuthorizationInfo) + } + + result = testutil.NewRequest().Get("/trustedInvokers/"+invokerId+"?authenticationInfo=true&authorizationInfo=true").Go(t, requestHandler) + assert.Equal(t, http.StatusOK, result.Code()) + err = result.UnmarshalBodyToObject(&resultService) + assert.NoError(t, err, "error unmarshaling response") + + for _, secInfo := range resultService.SecurityInfo { + assert.Equal(t, authenticationInfo, *secInfo.AuthenticationInfo) + assert.Equal(t, authorizationInfo, *secInfo.AuthorizationInfo) + } +} + +func TestUpdateTrustedInvoker(t *testing.T) { + + requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil) + + aefId := "aefId" + apiId := "apiId" + invokerId := "invokerId" + serviceSecurityTest := getServiceSecurity(aefId, apiId) + serviceSecurityTest.SecurityInfo[0].ApiId = &apiId + securityUnderTest.trustedInvokers[invokerId] = serviceSecurityTest + + // Update the service security with valid invoker, should return 200 with updated service security + newNotifURL := "http://golang.org/" + serviceSecurityTest.NotificationDestination = common29122.Uri(newNotifURL) + result := testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/update").WithJsonBody(serviceSecurityTest).Go(t, requestHandler) + + var resultResponse securityapi.ServiceSecurity + assert.Equal(t, http.StatusOK, result.Code()) + err := result.UnmarshalBodyToObject(&resultResponse) + assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, newNotifURL, string(resultResponse.NotificationDestination)) + + // Update with a service security missing required NotificationDestination, should get 400 with problem details + invalidServiceSecurity := securityapi.ServiceSecurity{ + SecurityInfo: []securityapi.SecurityInformation{ + { + AefId: &aefId, + ApiId: &apiId, + PrefSecurityMethods: []publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodOAUTH, + }, + }, + }, + } + + result = testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/update").WithJsonBody(invalidServiceSecurity).Go(t, requestHandler) + + assert.Equal(t, http.StatusBadRequest, result.Code()) + var problemDetails common29122.ProblemDetails + err = result.UnmarshalBodyToObject(&problemDetails) + assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, http.StatusBadRequest, *problemDetails.Status) + assert.Contains(t, *problemDetails.Cause, "missing") + assert.Contains(t, *problemDetails.Cause, "notificationDestination") + + // Update a service security that has not been registered, should get 404 with problem details + missingId := "1" + result = testutil.NewRequest().Post("/trustedInvokers/"+missingId+"/update").WithJsonBody(serviceSecurityTest).Go(t, requestHandler) + + assert.Equal(t, http.StatusNotFound, result.Code()) + err = result.UnmarshalBodyToObject(&problemDetails) + assert.NoError(t, err, "error unmarshaling response") + assert.Equal(t, http.StatusNotFound, *problemDetails.Status) + assert.Contains(t, *problemDetails.Cause, "not register") + assert.Contains(t, *problemDetails.Cause, "trusted invoker") +} + +func TestRevokeAuthorizationToInvoker(t *testing.T) { + aefId := "aefId" + apiId := "apiId" + invokerId := "invokerId" + + notification := securityapi.SecurityNotification{ + AefId: &aefId, + ApiInvokerId: invokerId, + ApiIds: []string{apiId}, + Cause: securityapi.CauseUNEXPECTEDREASON, + } + + requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil) + + serviceSecurityTest := getServiceSecurity(aefId, apiId) + serviceSecurityTest.SecurityInfo[0].ApiId = &apiId + + apiIdTwo := "apiIdTwo" + secInfo := securityapi.SecurityInformation{ + AefId: &aefId, + ApiId: &apiIdTwo, + PrefSecurityMethods: []publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodPKI, + }, + } + + serviceSecurityTest.SecurityInfo = append(serviceSecurityTest.SecurityInfo, secInfo) + + securityUnderTest.trustedInvokers[invokerId] = serviceSecurityTest + + // Revoke apiId + result := testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/delete").WithJsonBody(notification).Go(t, requestHandler) + + assert.Equal(t, http.StatusNoContent, result.Code()) + assert.Equal(t, 1, len(securityUnderTest.trustedInvokers[invokerId].SecurityInfo)) + + notification.ApiIds = []string{apiIdTwo} + // Revoke apiIdTwo + result = testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/delete").WithJsonBody(notification).Go(t, requestHandler) + + assert.Equal(t, http.StatusNoContent, result.Code()) + _, ok := securityUnderTest.trustedInvokers[invokerId] + assert.False(t, ok) +} + +func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister publishservice.PublishRegister, invokerRegister invokermanagement.InvokerRegister, keycloakMgm keycloak.AccessManagement) (*echo.Echo, *Security) { swagger, err := securityapi.GetSwagger() if err != nil { fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err) @@ -204,12 +600,42 @@ func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister swagger.Servers = nil - s := NewSecurity(serviceRegister, publishRegister, invokerRegister) + s := NewSecurity(serviceRegister, publishRegister, invokerRegister, keycloakMgm) e := echo.New() e.Use(echomiddleware.Logger()) e.Use(middleware.OapiRequestValidator(swagger)) securityapi.RegisterHandlers(e, s) - return e + return e, s +} + +func getServiceSecurity(aefId string, apiId string) securityapi.ServiceSecurity { + return securityapi.ServiceSecurity{ + NotificationDestination: common29122.Uri("http://golang.cafe/"), + SecurityInfo: []securityapi.SecurityInformation{ + { + AefId: &aefId, + ApiId: &apiId, + PrefSecurityMethods: []publishserviceapi.SecurityMethod{ + publishserviceapi.SecurityMethodOAUTH, + }, + }, + }, + } +} + +func getAefProfile(aefId string) publishserviceapi.AefProfile { + return publishserviceapi.AefProfile{ + AefId: aefId, + Versions: []publishserviceapi.Version{ + { + Resources: &[]publishserviceapi.Resource{ + { + CommType: "REQUEST_RESPONSE", + }, + }, + }, + }, + } }