NONRTRIC-946: Fix Capifcore intersection panic
[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("map[string][]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.AssertNumberOfCalls(t, "GetToken", 1)
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("map[string][]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.AssertNumberOfCalls(t, "GetToken", 1)
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 func TestPutTrustedInkoverNotRegistered(t *testing.T) {
288         invokerRegisterMock := invokermocks.InvokerRegister{}
289         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false)
290
291         requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil)
292
293         invokerId := "invokerId"
294         serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId")
295
296         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
297
298         badRequest := http.StatusBadRequest
299         assert.Equal(t, badRequest, result.Code())
300         var problemDetails common29122.ProblemDetails
301         err := result.UnmarshalBodyToObject(&problemDetails)
302         assert.NoError(t, err, "error unmarshaling response")
303         assert.Equal(t, &badRequest, problemDetails.Status)
304         assert.Contains(t, *problemDetails.Cause, "Invoker not registered")
305         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
306 }
307
308 func TestPutTrustedInkoverInvalidInputServiceSecurity(t *testing.T) {
309         invokerRegisterMock := invokermocks.InvokerRegister{}
310         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
311
312         requestHandler, _ := getEcho(nil, nil, &invokerRegisterMock, nil)
313
314         invokerId := "invokerId"
315         notificationUrl := "url"
316         serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId")
317         serviceSecurityUnderTest.NotificationDestination = common29122.Uri(notificationUrl)
318
319         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
320
321         badRequest := http.StatusBadRequest
322         assert.Equal(t, badRequest, result.Code())
323         var problemDetails common29122.ProblemDetails
324         err := result.UnmarshalBodyToObject(&problemDetails)
325         assert.NoError(t, err, "error unmarshaling response")
326         assert.Equal(t, &badRequest, problemDetails.Status)
327         assert.Contains(t, *problemDetails.Cause, "ServiceSecurity has invalid notificationDestination")
328         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
329 }
330
331 func TestPutTrustedInvokerInterfaceDetailsNotNil(t *testing.T) {
332         invokerRegisterMock := invokermocks.InvokerRegister{}
333         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
334         aefId := "aefId"
335         aefProfile := getAefProfile(aefId)
336         aefProfile.SecurityMethods = &[]publishserviceapi.SecurityMethod{
337                 publishserviceapi.SecurityMethodPKI,
338         }
339         aefProfiles := []publishserviceapi.AefProfile{
340                 aefProfile,
341         }
342         apiId := "apiId"
343         publishedServices := []publishserviceapi.ServiceAPIDescription{
344                 {
345                         ApiId:       &apiId,
346                         AefProfiles: &aefProfiles,
347                 },
348         }
349         publishRegisterMock := publishmocks.PublishRegister{}
350         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
351
352         requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, nil)
353
354         invokerId := "invokerId"
355         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
356         serviceSecurityUnderTest.SecurityInfo[0] = securityapi.SecurityInformation{
357                 ApiId: &apiId,
358                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
359                         publishserviceapi.SecurityMethodOAUTH,
360                 },
361                 InterfaceDetails: &publishserviceapi.InterfaceDescription{
362                         SecurityMethods: &[]publishserviceapi.SecurityMethod{
363                                 publishserviceapi.SecurityMethodPSK,
364                         },
365                 },
366         }
367
368         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
369
370         assert.Equal(t, http.StatusCreated, result.Code())
371         var resultResponse securityapi.ServiceSecurity
372         err := result.UnmarshalBodyToObject(&resultResponse)
373         assert.NoError(t, err, "error unmarshaling response")
374         assert.NotEmpty(t, resultResponse.NotificationDestination)
375
376         for _, security := range resultResponse.SecurityInfo {
377                 assert.Equal(t, apiId, *security.ApiId)
378                 assert.Equal(t, publishserviceapi.SecurityMethodPSK, *security.SelSecurityMethod)
379         }
380         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
381 }
382
383 func TestPutTrustedInvokerNotFoundSecurityMethod(t *testing.T) {
384         invokerRegisterMock := invokermocks.InvokerRegister{}
385         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
386
387         aefProfiles := []publishserviceapi.AefProfile{
388                 getAefProfile("aefId"),
389         }
390         apiId := "apiId"
391         publishedServices := []publishserviceapi.ServiceAPIDescription{
392                 {
393                         ApiId:       &apiId,
394                         AefProfiles: &aefProfiles,
395                 },
396         }
397         publishRegisterMock := publishmocks.PublishRegister{}
398         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
399
400         accessMgmMock := keycloackmocks.AccessManagement{}
401         accessMgmMock.On("AddClient", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(nil)
402
403         requestHandler, _ := getEcho(nil, &publishRegisterMock, &invokerRegisterMock, &accessMgmMock)
404
405         invokerId := "invokerId"
406         serviceSecurityUnderTest := getServiceSecurity("aefId", "apiId")
407
408         result := testutil.NewRequest().Put("/trustedInvokers/"+invokerId).WithJsonBody(serviceSecurityUnderTest).Go(t, requestHandler)
409
410         badRequest := http.StatusBadRequest
411         assert.Equal(t, badRequest, result.Code())
412         var problemDetails common29122.ProblemDetails
413         err := result.UnmarshalBodyToObject(&problemDetails)
414         assert.NoError(t, err, "error unmarshaling response")
415         assert.Equal(t, &badRequest, problemDetails.Status)
416         assert.Contains(t, *problemDetails.Cause, "not found")
417         assert.Contains(t, *problemDetails.Cause, "security method")
418         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", invokerId)
419 }
420
421 func TestDeleteSecurityContext(t *testing.T) {
422
423         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
424
425         aefId := "aefId"
426         apiId := "apiId"
427         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
428         serviceSecurityUnderTest.SecurityInfo[0].ApiId = &apiId
429
430         invokerId := "invokerId"
431         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityUnderTest
432
433         // Delete the security context
434         result := testutil.NewRequest().Delete("/trustedInvokers/"+invokerId).Go(t, requestHandler)
435
436         assert.Equal(t, http.StatusNoContent, result.Code())
437         _, ok := securityUnderTest.trustedInvokers[invokerId]
438         assert.False(t, ok)
439 }
440
441 func TestGetSecurityContextByInvokerId(t *testing.T) {
442
443         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
444
445         aefId := "aefId"
446         apiId := "apiId"
447         authenticationInfo := "authenticationInfo"
448         authorizationInfo := "authorizationInfo"
449         serviceSecurityUnderTest := getServiceSecurity(aefId, apiId)
450         serviceSecurityUnderTest.SecurityInfo[0].AuthenticationInfo = &authenticationInfo
451         serviceSecurityUnderTest.SecurityInfo[0].AuthorizationInfo = &authorizationInfo
452
453         invokerId := "invokerId"
454         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityUnderTest
455
456         // Get security context
457         result := testutil.NewRequest().Get("/trustedInvokers/"+invokerId).Go(t, requestHandler)
458
459         assert.Equal(t, http.StatusOK, result.Code())
460         var resultService securityapi.ServiceSecurity
461         err := result.UnmarshalBodyToObject(&resultService)
462         assert.NoError(t, err, "error unmarshaling response")
463
464         for _, secInfo := range resultService.SecurityInfo {
465                 assert.Equal(t, apiId, *secInfo.ApiId)
466                 assert.Equal(t, aefId, *secInfo.AefId)
467                 assert.Equal(t, "", *secInfo.AuthenticationInfo)
468                 assert.Equal(t, "", *secInfo.AuthorizationInfo)
469         }
470
471         result = testutil.NewRequest().Get("/trustedInvokers/"+invokerId+"?authenticationInfo=true&authorizationInfo=false").Go(t, requestHandler)
472         assert.Equal(t, http.StatusOK, result.Code())
473         err = result.UnmarshalBodyToObject(&resultService)
474         assert.NoError(t, err, "error unmarshaling response")
475
476         for _, secInfo := range resultService.SecurityInfo {
477                 assert.Equal(t, authenticationInfo, *secInfo.AuthenticationInfo)
478                 assert.Equal(t, "", *secInfo.AuthorizationInfo)
479         }
480
481         result = testutil.NewRequest().Get("/trustedInvokers/"+invokerId+"?authenticationInfo=true&authorizationInfo=true").Go(t, requestHandler)
482         assert.Equal(t, http.StatusOK, result.Code())
483         err = result.UnmarshalBodyToObject(&resultService)
484         assert.NoError(t, err, "error unmarshaling response")
485
486         for _, secInfo := range resultService.SecurityInfo {
487                 assert.Equal(t, authenticationInfo, *secInfo.AuthenticationInfo)
488                 assert.Equal(t, authorizationInfo, *secInfo.AuthorizationInfo)
489         }
490 }
491
492 func TestUpdateTrustedInvoker(t *testing.T) {
493
494         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
495
496         aefId := "aefId"
497         apiId := "apiId"
498         invokerId := "invokerId"
499         serviceSecurityTest := getServiceSecurity(aefId, apiId)
500         serviceSecurityTest.SecurityInfo[0].ApiId = &apiId
501         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityTest
502
503         // Update the service security with valid invoker, should return 200 with updated service security
504         newNotifURL := "http://golang.org/"
505         serviceSecurityTest.NotificationDestination = common29122.Uri(newNotifURL)
506         result := testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/update").WithJsonBody(serviceSecurityTest).Go(t, requestHandler)
507
508         var resultResponse securityapi.ServiceSecurity
509         assert.Equal(t, http.StatusOK, result.Code())
510         err := result.UnmarshalBodyToObject(&resultResponse)
511         assert.NoError(t, err, "error unmarshaling response")
512         assert.Equal(t, newNotifURL, string(resultResponse.NotificationDestination))
513
514         // Update with a service security missing required NotificationDestination, should get 400 with problem details
515         invalidServiceSecurity := securityapi.ServiceSecurity{
516                 SecurityInfo: []securityapi.SecurityInformation{
517                         {
518                                 AefId: &aefId,
519                                 ApiId: &apiId,
520                                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
521                                         publishserviceapi.SecurityMethodOAUTH,
522                                 },
523                         },
524                 },
525         }
526
527         result = testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/update").WithJsonBody(invalidServiceSecurity).Go(t, requestHandler)
528
529         assert.Equal(t, http.StatusBadRequest, result.Code())
530         var problemDetails common29122.ProblemDetails
531         err = result.UnmarshalBodyToObject(&problemDetails)
532         assert.NoError(t, err, "error unmarshaling response")
533         assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
534         assert.Contains(t, *problemDetails.Cause, "missing")
535         assert.Contains(t, *problemDetails.Cause, "notificationDestination")
536
537         // Update a service security that has not been registered, should get 404 with problem details
538         missingId := "1"
539         result = testutil.NewRequest().Post("/trustedInvokers/"+missingId+"/update").WithJsonBody(serviceSecurityTest).Go(t, requestHandler)
540
541         assert.Equal(t, http.StatusNotFound, result.Code())
542         err = result.UnmarshalBodyToObject(&problemDetails)
543         assert.NoError(t, err, "error unmarshaling response")
544         assert.Equal(t, http.StatusNotFound, *problemDetails.Status)
545         assert.Contains(t, *problemDetails.Cause, "not register")
546         assert.Contains(t, *problemDetails.Cause, "trusted invoker")
547 }
548
549 func TestRevokeAuthorizationToInvoker(t *testing.T) {
550         aefId := "aefId"
551         apiId := "apiId"
552         invokerId := "invokerId"
553
554         notification := securityapi.SecurityNotification{
555                 AefId:        &aefId,
556                 ApiInvokerId: invokerId,
557                 ApiIds:       []string{apiId},
558                 Cause:        securityapi.CauseUNEXPECTEDREASON,
559         }
560
561         requestHandler, securityUnderTest := getEcho(nil, nil, nil, nil)
562
563         serviceSecurityTest := getServiceSecurity(aefId, apiId)
564         serviceSecurityTest.SecurityInfo[0].ApiId = &apiId
565
566         apiIdTwo := "apiIdTwo"
567         secInfo := securityapi.SecurityInformation{
568                 AefId: &aefId,
569                 ApiId: &apiIdTwo,
570                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
571                         publishserviceapi.SecurityMethodPKI,
572                 },
573         }
574
575         serviceSecurityTest.SecurityInfo = append(serviceSecurityTest.SecurityInfo, secInfo)
576
577         securityUnderTest.trustedInvokers[invokerId] = serviceSecurityTest
578
579         // Revoke apiId
580         result := testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/delete").WithJsonBody(notification).Go(t, requestHandler)
581
582         assert.Equal(t, http.StatusNoContent, result.Code())
583         assert.Equal(t, 1, len(securityUnderTest.trustedInvokers[invokerId].SecurityInfo))
584
585         notification.ApiIds = []string{apiIdTwo}
586         // Revoke apiIdTwo
587         result = testutil.NewRequest().Post("/trustedInvokers/"+invokerId+"/delete").WithJsonBody(notification).Go(t, requestHandler)
588
589         assert.Equal(t, http.StatusNoContent, result.Code())
590         _, ok := securityUnderTest.trustedInvokers[invokerId]
591         assert.False(t, ok)
592 }
593
594 func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister publishservice.PublishRegister, invokerRegister invokermanagement.InvokerRegister, keycloakMgm keycloak.AccessManagement) (*echo.Echo, *Security) {
595         swagger, err := securityapi.GetSwagger()
596         if err != nil {
597                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
598                 os.Exit(1)
599         }
600
601         swagger.Servers = nil
602
603         s := NewSecurity(serviceRegister, publishRegister, invokerRegister, keycloakMgm)
604
605         e := echo.New()
606         e.Use(echomiddleware.Logger())
607         e.Use(middleware.OapiRequestValidator(swagger))
608
609         securityapi.RegisterHandlers(e, s)
610         return e, s
611 }
612
613 func getServiceSecurity(aefId string, apiId string) securityapi.ServiceSecurity {
614         return securityapi.ServiceSecurity{
615                 NotificationDestination: common29122.Uri("http://golang.cafe/"),
616                 SecurityInfo: []securityapi.SecurityInformation{
617                         {
618                                 AefId: &aefId,
619                                 ApiId: &apiId,
620                                 PrefSecurityMethods: []publishserviceapi.SecurityMethod{
621                                         publishserviceapi.SecurityMethodOAUTH,
622                                 },
623                         },
624                 },
625         }
626 }
627
628 func getAefProfile(aefId string) publishserviceapi.AefProfile {
629         return publishserviceapi.AefProfile{
630                 AefId: aefId,
631                 Versions: []publishserviceapi.Version{
632                         {
633                                 Resources: &[]publishserviceapi.Resource{
634                                         {
635                                                 CommType: "REQUEST_RESPONSE",
636                                         },
637                                 },
638                         },
639                 },
640         }
641 }