Merge "Changes in implementation of Security API - get Token"
[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         "fmt"
25         "net/http"
26         "net/url"
27         "os"
28         "testing"
29
30         "oransc.org/nonrtric/capifcore/internal/securityapi"
31
32         "oransc.org/nonrtric/capifcore/internal/invokermanagement"
33         "oransc.org/nonrtric/capifcore/internal/providermanagement"
34         "oransc.org/nonrtric/capifcore/internal/publishservice"
35
36         "github.com/labstack/echo/v4"
37
38         invokermocks "oransc.org/nonrtric/capifcore/internal/invokermanagement/mocks"
39         servicemocks "oransc.org/nonrtric/capifcore/internal/providermanagement/mocks"
40         publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
41
42         "github.com/deepmap/oapi-codegen/pkg/middleware"
43         "github.com/deepmap/oapi-codegen/pkg/testutil"
44         echomiddleware "github.com/labstack/echo/v4/middleware"
45         "github.com/stretchr/testify/assert"
46         "github.com/stretchr/testify/mock"
47 )
48
49 func TestPostSecurityIdTokenInvokerRegistered(t *testing.T) {
50         invokerRegisterMock := invokermocks.InvokerRegister{}
51         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
52         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
53         serviceRegisterMock := servicemocks.ServiceRegister{}
54         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(true)
55         publishRegisterMock := publishmocks.PublishRegister{}
56         publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
57
58         requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock)
59
60         data := url.Values{}
61         clientId := "id"
62         clientSecret := "secret"
63         aefId := "aefId"
64         path := "path"
65         data.Set("client_id", clientId)
66         data.Set("client_secret", clientSecret)
67         data.Set("grant_type", "client_credentials")
68         data.Set("scope", "3gpp#"+aefId+":"+path)
69
70         encodedData := data.Encode()
71
72         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
73
74         assert.Equal(t, http.StatusCreated, result.Code())
75         var resultResponse securityapi.AccessTokenRsp
76         err := result.UnmarshalBodyToObject(&resultResponse)
77         assert.NoError(t, err, "error unmarshaling response")
78         assert.NotEmpty(t, resultResponse.AccessToken)
79         assert.Equal(t, "3gpp#"+aefId+":"+path, *resultResponse.Scope)
80         assert.Equal(t, securityapi.AccessTokenRspTokenTypeBearer, resultResponse.TokenType)
81         invokerRegisterMock.AssertCalled(t, "IsInvokerRegistered", clientId)
82         invokerRegisterMock.AssertCalled(t, "VerifyInvokerSecret", clientId, clientSecret)
83         serviceRegisterMock.AssertCalled(t, "IsFunctionRegistered", aefId)
84         publishRegisterMock.AssertCalled(t, "IsAPIPublished", aefId, path)
85 }
86
87 func TestPostSecurityIdTokenInvokerNotRegistered(t *testing.T) {
88         invokerRegisterMock := invokermocks.InvokerRegister{}
89         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(false)
90
91         requestHandler := getEcho(nil, nil, &invokerRegisterMock)
92
93         data := url.Values{}
94         data.Set("client_id", "id")
95         data.Add("client_secret", "secret")
96         data.Add("grant_type", "client_credentials")
97         data.Add("scope", "3gpp#aefId:path")
98         encodedData := data.Encode()
99
100         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
101
102         assert.Equal(t, http.StatusBadRequest, result.Code())
103         var errDetails securityapi.AccessTokenErr
104         err := result.UnmarshalBodyToObject(&errDetails)
105         assert.NoError(t, err, "error unmarshaling response")
106         assert.Equal(t, securityapi.AccessTokenErrErrorInvalidClient, errDetails.Error)
107         errMsg := "Invoker not registered"
108         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
109 }
110
111 func TestPostSecurityIdTokenInvokerSecretNotValid(t *testing.T) {
112         invokerRegisterMock := invokermocks.InvokerRegister{}
113         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
114         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false)
115
116         requestHandler := getEcho(nil, nil, &invokerRegisterMock)
117
118         data := url.Values{}
119         data.Set("client_id", "id")
120         data.Add("client_secret", "secret")
121         data.Add("grant_type", "client_credentials")
122         data.Add("scope", "3gpp#aefId:path")
123         encodedData := data.Encode()
124
125         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
126
127         assert.Equal(t, http.StatusBadRequest, result.Code())
128         var errDetails securityapi.AccessTokenErr
129         err := result.UnmarshalBodyToObject(&errDetails)
130         assert.NoError(t, err, "error unmarshaling response")
131         assert.Equal(t, securityapi.AccessTokenErrErrorUnauthorizedClient, errDetails.Error)
132         errMsg := "Invoker secret not valid"
133         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
134 }
135
136 func TestPostSecurityIdTokenFunctionNotRegistered(t *testing.T) {
137         invokerRegisterMock := invokermocks.InvokerRegister{}
138         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
139         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
140         serviceRegisterMock := servicemocks.ServiceRegister{}
141         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(false)
142
143         requestHandler := getEcho(&serviceRegisterMock, nil, &invokerRegisterMock)
144
145         data := url.Values{}
146         data.Set("client_id", "id")
147         data.Add("client_secret", "secret")
148         data.Add("grant_type", "client_credentials")
149         data.Add("scope", "3gpp#aefId:path")
150         encodedData := data.Encode()
151
152         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
153
154         assert.Equal(t, http.StatusBadRequest, result.Code())
155         var errDetails securityapi.AccessTokenErr
156         err := result.UnmarshalBodyToObject(&errDetails)
157         assert.NoError(t, err, "error unmarshaling response")
158         assert.Equal(t, securityapi.AccessTokenErrErrorInvalidScope, errDetails.Error)
159         errMsg := "AEF Function not registered"
160         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
161 }
162
163 func TestPostSecurityIdTokenAPINotPublished(t *testing.T) {
164         invokerRegisterMock := invokermocks.InvokerRegister{}
165         invokerRegisterMock.On("IsInvokerRegistered", mock.AnythingOfType("string")).Return(true)
166         invokerRegisterMock.On("VerifyInvokerSecret", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(true)
167         serviceRegisterMock := servicemocks.ServiceRegister{}
168         serviceRegisterMock.On("IsFunctionRegistered", mock.AnythingOfType("string")).Return(true)
169         publishRegisterMock := publishmocks.PublishRegister{}
170         publishRegisterMock.On("IsAPIPublished", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(false)
171
172         requestHandler := getEcho(&serviceRegisterMock, &publishRegisterMock, &invokerRegisterMock)
173
174         data := url.Values{}
175         data.Set("client_id", "id")
176         data.Add("client_secret", "secret")
177         data.Add("grant_type", "client_credentials")
178         data.Add("scope", "3gpp#aefId:path")
179         encodedData := data.Encode()
180
181         result := testutil.NewRequest().Post("/securities/invokerId/token").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(encodedData)).Go(t, requestHandler)
182
183         assert.Equal(t, http.StatusBadRequest, result.Code())
184         var errDetails securityapi.AccessTokenErr
185         err := result.UnmarshalBodyToObject(&errDetails)
186         assert.NoError(t, err, "error unmarshaling response")
187         assert.Equal(t, securityapi.AccessTokenErrErrorInvalidScope, errDetails.Error)
188         errMsg := "API not published"
189         assert.Equal(t, &errMsg, errDetails.ErrorDescription)
190 }
191
192 func getEcho(serviceRegister providermanagement.ServiceRegister, publishRegister publishservice.PublishRegister, invokerRegister invokermanagement.InvokerRegister) *echo.Echo {
193         swagger, err := securityapi.GetSwagger()
194         if err != nil {
195                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
196                 os.Exit(1)
197         }
198
199         swagger.Servers = nil
200
201         s := NewSecurity(serviceRegister, publishRegister, invokerRegister)
202
203         e := echo.New()
204         e.Use(echomiddleware.Logger())
205         e.Use(middleware.OapiRequestValidator(swagger))
206
207         securityapi.RegisterHandlers(e, s)
208         return e
209 }