Implementation for Update and revoke trustedInvokers endpoint
[nonrtric/plt/sme.git] / capifcore / internal / securityservice / security_test.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20
21 package security
22
23 import (
24         "errors"
25         "fmt"
26         "net/http"
27         "net/url"
28         "os"
29         "testing"
30
31         "oransc.org/nonrtric/capifcore/internal/common29122"
32         "oransc.org/nonrtric/capifcore/internal/keycloak"
33         "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
34         "oransc.org/nonrtric/capifcore/internal/securityapi"
35
36         "oransc.org/nonrtric/capifcore/internal/invokermanagement"
37         "oransc.org/nonrtric/capifcore/internal/providermanagement"
38         "oransc.org/nonrtric/capifcore/internal/publishservice"
39
40         "github.com/labstack/echo/v4"
41
42         invokermocks "oransc.org/nonrtric/capifcore/internal/invokermanagement/mocks"
43         keycloackmocks "oransc.org/nonrtric/capifcore/internal/keycloak/mocks"
44         servicemocks "oransc.org/nonrtric/capifcore/internal/providermanagement/mocks"
45         publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
46
47         "github.com/deepmap/oapi-codegen/pkg/middleware"
48         "github.com/deepmap/oapi-codegen/pkg/testutil"
49         echomiddleware "github.com/labstack/echo/v4/middleware"
50         "github.com/stretchr/testify/assert"
51         "github.com/stretchr/testify/mock"
52 )
53
54 func TestPostSecurityIdTokenInvokerRegistered(t *testing.T) {
55         invokerRegisterMock := invokermocks.InvokerRegister{}
56         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
57         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
58         serviceRegisterMock := servicemocks.ServiceRegister{}
59         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(true)
60         publishRegisterMock := publishmocks.PublishRegister{}
61         publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
62
63         jwt := keycloak.Jwttoken{
64                 AccessToken: "eyJhbGNIn0.e3YTQ0xLjEifQ.FcqCwCy7iJiOmw",
65                 ExpiresIn:   300,
66                 Scope:       "3gpp#aefIdpath",
67         }
68         accessMgmMock := keycloackmocks.AccessManagement{}
69         accessMgmMock.On("GetToken", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(jwt, nil)
70
71         requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock)
72
73         data := url.Values{}
74         clientId := "id"
75         clientSecret := "secret"
76         aefId := "aefId"
77         path := "path"
78         data.Set("client_id", clientId)
79         data.Set("client_secret", clientSecret)
80         data.Set("grant_type", "client_credentials")
81         data.Set("scope", "3gpp#"+aefId+":"+path)
82
83         encodedData := data.Encode()
84
85         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
86
87         assert.Equal(t, http.StatusCreated, result.Code())
88         var resultResponse securityapi.AccessTokenRsp
89         err := result.UnmarshalBodyToObject(&resultResponse)
90         assert.NoError(t, err, "error unmarshaling response")
91         assert.NotEmpty(t, resultResponse.AccessToken)
92         assert.Equal(t, securityapi.AccessTokenRspTokenTypeBearer, resultResponse.TokenType)
93         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", clientId)
94         invokerRegisterMock.AssertCalled(t, "VerifyInvokerSecret", clientId, clientSecret)
95         serviceRegisterMock.AssertCalled(t, "IsFunctionRegistered", aefId)
96         publishRegisterMock.AssertCalled(t, "IsAPIPublished", aefId, path)
97         accessMgmMock.AssertCalled(t, "GetToken", clientId, clientSecret, "3gpp#"+aefId+":"+path, "invokerrealm")
98 }
99
100 func TestPostSecurityIdTokenInvokerNotRegistered(t *testing.T) {
101         invokerRegisterMock := invokermocks.InvokerRegister{}
102         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false)
103
104         requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil)
105
106         data := url.Values{}
107         data.Set("client_id", "id")
108         data.Add("client_secret", "secret")
109         data.Add("grant_type", "client_credentials")
110         data.Add("scope", "3gpp#aefId:path")
111         encodedData := data.Encode()
112
113         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
114
115         assert.Equal(t, http.StatusBadRequest, result.Code())
116         var errDetails securityapi.AccessTokenErr
117         err := result.UnmarshalBodyToObject(&errDetails)
118         assert.NoError(t, err, "error unmarshaling response")
119         assert.Equal(t, securityapi.AccessTokenErrErrorInvalidClient, errDetails.Error)
120         errMsg := "Invoker not registered"
121         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
122 }
123
124 func TestPostSecurityIdTokenInvokerSecretNotValid(t *testing.T) {
125         invokerRegisterMock := invokermocks.InvokerRegister{}
126         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
127         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false)
128
129         requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil)
130
131         data := url.Values{}
132         data.Set("client_id", "id")
133         data.Add("client_secret", "secret")
134         data.Add("grant_type", "client_credentials")
135         data.Add("scope", "3gpp#aefId:path")
136         encodedData := data.Encode()
137
138         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
139
140         assert.Equal(t, http.StatusBadRequest, result.Code())
141         var errDetails securityapi.AccessTokenErr
142         err := result.UnmarshalBodyToObject(&errDetails)
143         assert.NoError(t, err, "error unmarshaling response")
144         assert.Equal(t, securityapi.AccessTokenErrErrorUnauthorizedClient, errDetails.Error)
145         errMsg := "Invoker secret not valid"
146         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
147 }
148
149 func TestPostSecurityIdTokenFunctionNotRegistered(t *testing.T) {
150         invokerRegisterMock := invokermocks.InvokerRegister{}
151         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
152         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
153         serviceRegisterMock := servicemocks.ServiceRegister{}
154         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(false)
155
156         requestHandler, _ := getEcho(&serviceRegisterMock, nil, &invokerRegisterMock, nil)
157
158         data := url.Values{}
159         data.Set("client_id", "id")
160         data.Add("client_secret", "secret")
161         data.Add("grant_type", "client_credentials")
162         data.Add("scope", "3gpp#aefId:path")
163         encodedData := data.Encode()
164
165         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
166
167         assert.Equal(t, http.StatusBadRequest, result.Code())
168         var errDetails securityapi.AccessTokenErr
169         err := result.UnmarshalBodyToObject(&errDetails)
170         assert.NoError(t, err, "error unmarshaling response")
171         assert.Equal(t, securityapi.AccessTokenErrErrorInvalidScope, errDetails.Error)
172         errMsg := "AEF Function not registered"
173         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
174 }
175
176 func TestPostSecurityIdTokenAPINotPublished(t *testing.T) {
177         invokerRegisterMock := invokermocks.InvokerRegister{}
178         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
179         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
180         serviceRegisterMock := servicemocks.ServiceRegister{}
181         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(true)
182         publishRegisterMock := publishmocks.PublishRegister{}
183         publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false)
184
185         requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, nil)
186
187         data := url.Values{}
188         data.Set("client_id", "id")
189         data.Add("client_secret", "secret")
190         data.Add("grant_type", "client_credentials")
191         data.Add("scope", "3gpp#aefId:path")
192         encodedData := data.Encode()
193
194         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
195
196         assert.Equal(t, http.StatusBadRequest, result.Code())
197         var errDetails securityapi.AccessTokenErr
198         err := result.UnmarshalBodyToObject(&errDetails)
199         assert.NoError(t, err, "error unmarshaling response")
200         assert.Equal(t, securityapi.AccessTokenErrErrorInvalidScope, errDetails.Error)
201         errMsg := "API not published"
202         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
203 }
204
205 func TestPostSecurityIdTokenInvokerInvalidCredentials(t *testing.T) {
206         invokerRegisterMock := invokermocks.InvokerRegister{}
207         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
208         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
209         serviceRegisterMock := servicemocks.ServiceRegister{}
210         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(true)
211         publishRegisterMock := publishmocks.PublishRegister{}
212         publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
213
214         jwt := keycloak.Jwttoken{}
215         accessMgmMock := keycloackmocks.AccessManagement{}
216         accessMgmMock.On("GetToken", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(jwt, errors.New("invalid_credentials"))
217
218         requestHandler, _ := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock)
219
220         data := url.Values{}
221         clientId := "id"
222         clientSecret := "secret"
223         aefId := "aefId"
224         path := "path"
225         data.Set("client_id", clientId)
226         data.Set("client_secret", clientSecret)
227         data.Set("grant_type", "client_credentials")
228         data.Set("scope", "3gpp#"+aefId+":"+path)
229
230         encodedData := data.Encode()
231
232         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
233
234         assert.Equal(t, http.StatusBadRequest, result.Code())
235         var resultResponse securityapi.AccessTokenErr
236         err := result.UnmarshalBodyToObject(&resultResponse)
237         assert.NoError(t, err, "error unmarshaling response")
238         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", clientId)
239         invokerRegisterMock.AssertCalled(t, "VerifyInvokerSecret", clientId, clientSecret)
240         serviceRegisterMock.AssertCalled(t, "IsFunctionRegistered", aefId)
241         publishRegisterMock.AssertCalled(t, "IsAPIPublished", aefId, path)
242         accessMgmMock.AssertCalled(t, "GetToken", clientId, clientSecret, "3gpp#"+aefId+":"+path, "invokerrealm")
243 }
244
245 func TestPutTrustedInvokerSuccessfully(t *testing.T) {
246         invokerRegisterMock := invokermocks.InvokerRegister{}
247         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
248         aefId := "aefId"
249         aefProfile := getAefProfile(aefId)
250         aefProfile.SecurityMethods = &[]publishserviceapi.SecurityMethod{
251                 publishserviceapi.SecurityMethodPKI,
252         }
253         aefProfiles := []publishserviceapi.AefProfile{
254                 aefProfile,
255         }
256         apiId := "apiId"
257         publishedServices := []publishserviceapi.ServiceAPIDescription{
258                 {
259                         ApiId:       &apiId,
260                         AefProfiles: &aefProfiles,
261                 },
262         }
263         publishRegisterMock := publishmocks.PublishRegister{}
264         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
265
266         requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil)
267
268         invokerId := "invokerId"
269         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
270         serviceSecurityUnderTest.SecurityInfo[0].ApiId = &apiId
271
272         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
273
274         assert.Equal(t, http.StatusCreated, result.Code())
275         var resultResponse securityapi.ServiceSecurity
276         err := result.UnmarshalBodyToObject(&resultResponse)
277         assert.NoError(t, err, "error unmarshaling response")
278         assert.NotEmpty(t, resultResponse.NotificationDestination)
279
280         for _, security := range resultResponse.SecurityInfo {
281                 assert.Equal(t, *security.ApiId, apiId)
282                 assert.Equal(t, *security.SelSecurityMethod, publishserviceapi.SecurityMethodPKI)
283         }
284         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
285
286 }
287
288 func TestPutTrustedInkoverNotRegistered(t *testing.T) {
289         invokerRegisterMock := invokermocks.InvokerRegister{}
290         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false)
291
292         requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil)
293
294         invokerId := "invokerId"
295         serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId")
296
297         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
298
299         badRequest := http.StatusBadRequest
300         assert.Equal(t, badRequest, result.Code())
301         var problemDetails common29122.ProblemDetails
302         err := result.UnmarshalBodyToObject(&problemDetails)
303         assert.NoError(t, err, "error unmarshaling response")
304         assert.Equal(t, &badRequest, problemDetails.Status)
305         assert.Contains(t, *problemDetails.Cause, "Invoker not registered")
306         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
307 }
308
309 func TestPutTrustedInkoverInvalidInputServiceSecurity(t *testing.T) {
310         invokerRegisterMock := invokermocks.InvokerRegister{}
311         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
312
313         requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil)
314
315         invokerId := "invokerId"
316         notificationUrl := "url"
317         serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId")
318         serviceSecurityUnderTest.NotificationDestination = common29122.Uri(notificationUrl)
319
320         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
321
322         badRequest := http.StatusBadRequest
323         assert.Equal(t, badRequest, result.Code())
324         var problemDetails common29122.ProblemDetails
325         err := result.UnmarshalBodyToObject(&problemDetails)
326         assert.NoError(t, err, "error unmarshaling response")
327         assert.Equal(t, &badRequest, problemDetails.Status)
328         assert.Contains(t, *problemDetails.Cause, "ServiceSecurity has invalid notificationDestination")
329         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
330 }
331
332 func TestPutTrustedInvokerInterfaceDetailsNotNil(t *testing.T) {
333         invokerRegisterMock := invokermocks.InvokerRegister{}
334         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
335         aefId := "aefId"
336         aefProfile := getAefProfile(aefId)
337         aefProfile.SecurityMethods = &[]publishserviceapi.SecurityMethod{
338                 publishserviceapi.SecurityMethodPKI,
339         }
340         aefProfiles := []publishserviceapi.AefProfile{
341                 aefProfile,
342         }
343         apiId := "apiId"
344         publishedServices := []publishserviceapi.ServiceAPIDescription{
345                 {
346                         ApiId:       &apiId,
347                         AefProfiles: &aefProfiles,
348                 },
349         }
350         publishRegisterMock := publishmocks.PublishRegister{}
351         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
352
353         requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil)
354
355         invokerId := "invokerId"
356         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
357         serviceSecurityUnderTest.SecurityInfo[0] = securityapi.SecurityInformation{
358                 ApiId: &apiId,
359                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
360                         publishserviceapi.SecurityMethodOAUTH,
361                 },
362                 InterfaceDetails: &publishserviceapi.InterfaceDescription{
363                         SecurityMethods: &[]publishserviceapi.SecurityMethod{
364                                 publishserviceapi.SecurityMethodPSK,
365                         },
366                 },
367         }
368
369         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
370
371         assert.Equal(t, http.StatusCreated, result.Code())
372         var resultResponse securityapi.ServiceSecurity
373         err := result.UnmarshalBodyToObject(&resultResponse)
374         assert.NoError(t, err, "error unmarshaling response")
375         assert.NotEmpty(t, resultResponse.NotificationDestination)
376
377         for _, security := range resultResponse.SecurityInfo {
378                 assert.Equal(t, apiId, *security.ApiId)
379                 assert.Equal(t, publishserviceapi.SecurityMethodPSK, *security.SelSecurityMethod)
380         }
381         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
382
383 }
384
385 func TestPutTrustedInvokerNotFoundSecurityMethod(t *testing.T) {
386         invokerRegisterMock := invokermocks.InvokerRegister{}
387         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
388
389         aefProfiles := []publishserviceapi.AefProfile{
390                 getAefProfile("aefId"),
391         }
392         apiId := "apiId"
393         publishedServices := []publishserviceapi.ServiceAPIDescription{
394                 {
395                         ApiId:       &apiId,
396                         AefProfiles: &aefProfiles,
397                 },
398         }
399         publishRegisterMock := publishmocks.PublishRegister{}
400         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
401
402         requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil)
403
404         invokerId := "invokerId"
405         serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId")
406
407         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
408
409         badRequest := http.StatusBadRequest
410         assert.Equal(t, badRequest, result.Code())
411         var problemDetails common29122.ProblemDetails
412         err := result.UnmarshalBodyToObject(&problemDetails)
413         assert.NoError(t, err, "error unmarshaling response")
414         assert.Equal(t, &badRequest, problemDetails.Status)
415         assert.Contains(t, *problemDetails.Cause, "not found")
416         assert.Contains(t, *problemDetails.Cause, "security method")
417         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
418 }
419
420 func TestDeleteSecurityContext(t *testing.T) {
421
422         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
423
424         aefId := "aefId"
425         apiId := "apiId"
426         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
427         serviceSecurityUnderTest.SecurityInfo[0].ApiId = &apiId
428
429         invokerId := "invokerId"
430         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityUnderTest
431
432         // Delete the security context
433         result := testutil.NewRequest().Delete("/trustedInvokers/"+invokerId).Go(t, requestHandler)
434
435         assert.Equal(t, http.StatusNoContent, result.Code())
436         _, ok := securityUnderTest.trustedInvokers[invokerId]
437         assert.False(t, ok)
438 }
439
440 func TestGetSecurityContextByInvokerId(t *testing.T) {
441
442         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
443
444         aefId := "aefId"
445         apiId := "apiId"
446         authenticationInfo := "authenticationInfo"
447         authorizationInfo := "authorizationInfo"
448         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
449         serviceSecurityUnderTest.SecurityInfo[0].AuthenticationInfo = &authenticationInfo
450         serviceSecurityUnderTest.SecurityInfo[0].AuthorizationInfo = &authorizationInfo
451
452         invokerId := "invokerId"
453         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityUnderTest
454
455         // Get security context
456         result := testutil.NewRequest().Get("/trustedInvokers/"+invokerId).Go(t, requestHandler)
457
458         assert.Equal(t, http.StatusOK, result.Code())
459         var resultService securityapi.ServiceSecurity
460         err := result.UnmarshalBodyToObject(&resultService)
461         assert.NoError(t, err, "error unmarshaling response")
462
463         for _, secInfo := range resultService.SecurityInfo {
464                 assert.Equal(t, apiId, *secInfo.ApiId)
465                 assert.Equal(t, aefId, *secInfo.AefId)
466                 assert.Equal(t, "", *secInfo.AuthenticationInfo)
467                 assert.Equal(t, "", *secInfo.AuthorizationInfo)
468         }
469
470         result = testutil.NewRequest().Get("/trustedInvokers/"+invokerId+"?authenticationInfo=true&authorizationInfo=false").Go(t, requestHandler)
471         assert.Equal(t, http.StatusOK, result.Code())
472         err = result.UnmarshalBodyToObject(&resultService)
473         assert.NoError(t, err, "error unmarshaling response")
474
475         for _, secInfo := range resultService.SecurityInfo {
476                 assert.Equal(t, authenticationInfo, *secInfo.AuthenticationInfo)
477                 assert.Equal(t, "", *secInfo.AuthorizationInfo)
478         }
479
480         result = testutil.NewRequest().Get("/trustedInvokers/"+invokerId+"?authenticationInfo=true&authorizationInfo=true").Go(t, requestHandler)
481         assert.Equal(t, http.StatusOK, result.Code())
482         err = result.UnmarshalBodyToObject(&resultService)
483         assert.NoError(t, err, "error unmarshaling response")
484
485         for _, secInfo := range resultService.SecurityInfo {
486                 assert.Equal(t, authenticationInfo, *secInfo.AuthenticationInfo)
487                 assert.Equal(t, authorizationInfo, *secInfo.AuthorizationInfo)
488         }
489 }
490
491 func TestUpdateTrustedInvoker(t *testing.T) {
492
493         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
494
495         aefId := "aefId"
496         apiId := "apiId"
497         invokerId := "invokerId"
498         serviceSecurityTest := getServiceSecurity(aefId, apiId)
499         serviceSecurityTest.SecurityInfo[0].ApiId = &apiId
500         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityTest
501
502         // Update the service security with valid invoker, should return 200 with updated service security
503         newNotifURL := "http://golang.org/"
504         serviceSecurityTest.NotificationDestination = common29122.Uri(newNotifURL)
505         result := testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/update").WithJsonBody(serviceSecurityTest).Go(t, requestHandler)
506
507         var resultResponse securityapi.ServiceSecurity
508         assert.Equal(t, http.StatusOK, result.Code())
509         err := result.UnmarshalBodyToObject(&resultResponse)
510         assert.NoError(t, err, "error unmarshaling response")
511         assert.Equal(t, newNotifURL, string(resultResponse.NotificationDestination))
512
513         // Update with an service security missing required NotificationDestination, should get 400 with problem details
514         invalidServiceSecurity := securityapi.ServiceSecurity{
515                 SecurityInfo: []securityapi.SecurityInformation{
516                         {
517                                 AefId: &aefId,
518                                 ApiId: &apiId,
519                                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
520                                         publishserviceapi.SecurityMethodOAUTH,
521                                 },
522                         },
523                 },
524         }
525
526         result = testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/update").WithJsonBody(invalidServiceSecurity).Go(t, requestHandler)
527
528         assert.Equal(t, http.StatusBadRequest, result.Code())
529         var problemDetails common29122.ProblemDetails
530         err = result.UnmarshalBodyToObject(&problemDetails)
531         assert.NoError(t, err, "error unmarshaling response")
532         assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
533         assert.Contains(t, *problemDetails.Cause, "missing")
534         assert.Contains(t, *problemDetails.Cause, "notificationDestination")
535
536         // Update a service security that has not been registered, should get 404 with problem details
537         missingId := "1"
538         result = testutil.NewRequest().Post("/trustedInvokers/"+missingId+"/update").WithJsonBody(serviceSecurityTest).Go(t, requestHandler)
539
540         assert.Equal(t, http.StatusNotFound, result.Code())
541         err = result.UnmarshalBodyToObject(&problemDetails)
542         assert.NoError(t, err, "error unmarshaling response")
543         assert.Equal(t, http.StatusNotFound, *problemDetails.Status)
544         assert.Contains(t, *problemDetails.Cause, "not register")
545         assert.Contains(t, *problemDetails.Cause, "trusted invoker")
546 }
547
548 func TestRevokeAuthorizationToInvoker(t *testing.T) {
549         aefId := "aefId"
550         apiId := "apiId"
551         invokerId := "invokerId"
552
553         notification := securityapi.SecurityNotification{
554                 AefId:        &aefId,
555                 ApiInvokerId: invokerId,
556                 ApiIds:       []string{apiId},
557                 Cause:        securityapi.CauseUNEXPECTEDREASON,
558         }
559
560         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
561
562         serviceSecurityTest := getServiceSecurity(aefId, apiId)
563         serviceSecurityTest.SecurityInfo[0].ApiId = &apiId
564
565         apiIdTwo := "apiIdTwo"
566         secInfo := securityapi.SecurityInformation{
567                 AefId: &aefId,
568                 ApiId: &apiIdTwo,
569                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
570                         publishserviceapi.SecurityMethodPKI,
571                 },
572         }
573
574         serviceSecurityTest.SecurityInfo = append(serviceSecurityTest.SecurityInfo, secInfo)
575
576         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityTest
577
578         // Revoke apiId
579         result := testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/delete").WithJsonBody(notification).Go(t, requestHandler)
580
581         assert.Equal(t, http.StatusNoContent, result.Code())
582         assert.Equal(t, 1, len(securityUnderTest.trustedInvokers[invokerId].SecurityInfo))
583
584         notification.ApiIds = []string{apiIdTwo}
585         // Revoke apiIdTwo
586         result = testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/delete").WithJsonBody(notification).Go(t, requestHandler)
587
588         assert.Equal(t, http.StatusNoContent, result.Code())
589         _, ok := securityUnderTest.trustedInvokers[invokerId]
590         assert.False(t, ok)
591 }
592
593 func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister publishservice.PublishRegister, invokerRegister invokermanagement.InvokerRegister, keycloakMgm keycloak.AccessManagement) (*echo.Echo, *Security) {
594         swagger, err := securityapi.GetSwagger()
595         if err != nil {
596                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
597                 os.Exit(1)
598         }
599
600         swagger.Servers = nil
601
602         s := NewSecurity(serviceRegister, publishRegister, invokerRegister, keycloakMgm)
603
604         e := echo.New()
605         e.Use(echomiddleware.Logger())
606         e.Use(middleware.OapiRequestValidator(swagger))
607
608         securityapi.RegisterHandlers(e, s)
609         return e, s
610 }
611
612 func getServiceSecurity(aefId string, apiId string) securityapi.ServiceSecurity {
613         return securityapi.ServiceSecurity{
614                 NotificationDestination: common29122.Uri("http://golang.cafe/"),
615                 SecurityInfo: []securityapi.SecurityInformation{
616                         {
617                                 AefId: &aefId,
618                                 ApiId: &apiId,
619                                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
620                                         publishserviceapi.SecurityMethodOAUTH,
621                                 },
622                         },
623                 },
624         }
625 }
626
627 func getAefProfile(aefId string) publishserviceapi.AefProfile {
628         return publishserviceapi.AefProfile{
629                 AefId: aefId,
630                 Versions: []publishserviceapi.Version{
631                         {
632                                 Resources: &[]publishserviceapi.Resource{
633                                         {
634                                                 CommType: "REQUEST_RESPONSE",
635                                         },
636                                 },
637                         },
638                 },
639         }
640 }