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