From 856821490df816d7343d90f76f729240bd4e00d6 Mon Sep 17 00:00:00 2001 From: ychacon Date: Tue, 7 Mar 2023 21:59:08 +0100 Subject: [PATCH] Implementation for GET/DELETE trustedInvokers endpoint Issue-ID: NONRTRIC-848 Signed-off-by: ychacon Change-Id: I7c3c8c484afa2b56cfabe7d82d47255f91fd726a --- capifcore/internal/securityservice/security.go | 58 ++++++++++++- .../internal/securityservice/security_test.go | 97 +++++++++++++++++++--- capifcore/main_test.go | 2 +- 3 files changed, 140 insertions(+), 17 deletions(-) diff --git a/capifcore/internal/securityservice/security.go b/capifcore/internal/securityservice/security.go index 52d28ce..d3d9026 100644 --- a/capifcore/internal/securityservice/security.go +++ b/capifcore/internal/securityservice/security.go @@ -28,7 +28,7 @@ import ( "sync" "github.com/labstack/echo/v4" - + copystructure "github.com/mitchellh/copystructure" "oransc.org/nonrtric/capifcore/internal/common29122" securityapi "oransc.org/nonrtric/capifcore/internal/securityapi" @@ -110,11 +110,63 @@ func (s *Security) PostSecuritiesSecurityIdToken(ctx echo.Context, securityId st } func (s *Security) DeleteTrustedInvokersApiInvokerId(ctx echo.Context, apiInvokerId string) error { - return ctx.NoContent(http.StatusNotImplemented) + if _, ok := s.trustedInvokers[apiInvokerId]; ok { + s.deleteTrustedInvoker(apiInvokerId) + } + + return ctx.NoContent(http.StatusNoContent) +} + +func (s *Security) deleteTrustedInvoker(apiInvokerId string) { + s.lock.Lock() + defer s.lock.Unlock() + delete(s.trustedInvokers, apiInvokerId) } func (s *Security) GetTrustedInvokersApiInvokerId(ctx echo.Context, apiInvokerId string, params securityapi.GetTrustedInvokersApiInvokerIdParams) error { - return ctx.NoContent(http.StatusNotImplemented) + + if trustedInvoker, ok := s.trustedInvokers[apiInvokerId]; ok { + updatedInvoker := s.checkParams(trustedInvoker, params) + if updatedInvoker != nil { + err := ctx.JSON(http.StatusOK, updatedInvoker) + if err != nil { + return err + } + } + } else { + return sendCoreError(ctx, http.StatusNotFound, fmt.Sprintf("invoker %s not registered as trusted invoker", apiInvokerId)) + } + + return nil +} + +func (s *Security) checkParams(trustedInvoker securityapi.ServiceSecurity, params securityapi.GetTrustedInvokersApiInvokerIdParams) *securityapi.ServiceSecurity { + emptyString := "" + + var sendAuthenticationInfo = (params.AuthenticationInfo != nil) && *params.AuthenticationInfo + var sendAuthorizationInfo = (params.AuthorizationInfo != nil) && *params.AuthorizationInfo + + if sendAuthenticationInfo && sendAuthorizationInfo { + return &trustedInvoker + } + + data, _ := copystructure.Copy(trustedInvoker) + updatedInvoker, ok := data.(securityapi.ServiceSecurity) + if !ok { + return nil + } + + if !sendAuthenticationInfo { + for i := range updatedInvoker.SecurityInfo { + updatedInvoker.SecurityInfo[i].AuthenticationInfo = &emptyString + } + } + if !sendAuthorizationInfo { + for i := range updatedInvoker.SecurityInfo { + updatedInvoker.SecurityInfo[i].AuthorizationInfo = &emptyString + } + } + return &updatedInvoker } func (s *Security) PutTrustedInvokersApiInvokerId(ctx echo.Context, apiInvokerId string) error { diff --git a/capifcore/internal/securityservice/security_test.go b/capifcore/internal/securityservice/security_test.go index d31ff6e..1abb8ae 100644 --- a/capifcore/internal/securityservice/security_test.go +++ b/capifcore/internal/securityservice/security_test.go @@ -68,7 +68,7 @@ func TestPostSecurityIdTokenInvokerRegistered(t *testing.T) { accessMgmMock := keycloackmocks.AccessManagement{} accessMgmMock.On("GetToken", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(jwt, nil) - requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) + requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) data := url.Values{} clientId := "id" @@ -101,7 +101,7 @@ func TestPostSecurityIdTokenInvokerNotRegistered(t *testing.T) { invokerRegisterMock := invokermocks.InvokerRegister{} invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(nil, nil, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") @@ -126,7 +126,7 @@ 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, nil) + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") @@ -153,7 +153,7 @@ func TestPostSecurityIdTokenFunctionNotRegistered(t *testing.T) { serviceRegisterMock := servicemocks.ServiceRegister{} serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(&serviceRegisterMock, nil, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(&serviceRegisterMock, nil, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") @@ -182,7 +182,7 @@ func TestPostSecurityIdTokenAPINotPublished(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, nil) data := url.Values{} data.Set("client_id", "id") @@ -215,7 +215,7 @@ func TestPostSecurityIdTokenInvokerInvalidCredentials(t *testing.T) { accessMgmMock := keycloackmocks.AccessManagement{} accessMgmMock.On("GetToken", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(jwt, errors.New("invalid_credentials")) - requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) + requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock) data := url.Values{} clientId := "id" @@ -263,7 +263,7 @@ func TestPutTrustedInvokerSuccessfully(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) - requestHandler := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) invokerId := "invokerId" serviceSecurityUnderTest := getServiceSecurity(aefId, apiId) @@ -289,7 +289,7 @@ func TestPutTrustedInkoverNotRegistered(t *testing.T) { invokerRegisterMock := invokermocks.InvokerRegister{} invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false) - requestHandler := getEcho(nil, nil, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) invokerId := "invokerId" serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId") @@ -310,7 +310,7 @@ func TestPutTrustedInkoverInvalidInputServiceSecurity(t *testing.T) { invokerRegisterMock := invokermocks.InvokerRegister{} invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true) - requestHandler := getEcho(nil, nil, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil) invokerId := "invokerId" notificationUrl := "url" @@ -350,7 +350,7 @@ func TestPutTrustedInvokerInterfaceDetailsNotNil(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) - requestHandler := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) invokerId := "invokerId" serviceSecurityUnderTest := getServiceSecurity(aefId, apiId) @@ -399,7 +399,7 @@ func TestPutTrustedInvokerNotFoundSecurityMethod(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) - requestHandler := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) + requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil) invokerId := "invokerId" serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId") @@ -417,7 +417,78 @@ func TestPutTrustedInvokerNotFoundSecurityMethod(t *testing.T) { invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId) } -func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister publishservice.PublishRegister, invokerRegister invokermanagement.InvokerRegister, keycloakMgm keycloak.AccessManagement) *echo.Echo { +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 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) @@ -433,7 +504,7 @@ func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister e.Use(middleware.OapiRequestValidator(swagger)) securityapi.RegisterHandlers(e, s) - return e + return e, s } func getServiceSecurity(aefId string, apiId string) securityapi.ServiceSecurity { diff --git a/capifcore/main_test.go b/capifcore/main_test.go index 7d77b92..571d475 100644 --- a/capifcore/main_test.go +++ b/capifcore/main_test.go @@ -101,7 +101,7 @@ func Test_routing(t *testing.T) { name: "Security path", args: args{ url: "/capif-security/v1/trustedInvokers/apiInvokerId", - returnStatus: http.StatusNotImplemented, + returnStatus: http.StatusNotFound, method: "GET", }, }, -- 2.16.6