1 package server
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "net/http"
8 "net/http/httptest"
9 "path"
10 "testing"
11
12 "edge-infra.dev/pkg/sds/emergencyaccess/eaconst"
13 "edge-infra.dev/pkg/sds/emergencyaccess/eagateway"
14 "edge-infra.dev/pkg/sds/emergencyaccess/msgdata"
15 "edge-infra.dev/pkg/sds/emergencyaccess/types"
16
17 "github.com/gin-gonic/gin"
18 "github.com/stretchr/testify/assert"
19 )
20
21 const (
22 badCommand = "false"
23 )
24
25 var (
26 defaultBytes = []byte(`
27 {
28 "type": "Output",
29 "exitCode": 0,
30 "output": "hello\n",
31 "timestamp": "01-01-2023 00:00:00",
32 "duration": 0.1
33 }`)
34 defaultAttrMap = map[string]string{
35 "bannerId": "banner",
36 "storeId": "store",
37 "terminalId": "terminal",
38 "sessionId": "orderingKey",
39 "identity": "identity",
40 "version": "1.0",
41 "signature": "signature",
42 "request-message-uuid": "uuid",
43 }
44 defaultTarget = types.Target{
45 Projectid: "projectID",
46 Bannerid: "bannerID",
47 Storeid: "storeID",
48 Terminalid: "terminalID",
49 }
50
51 errTestRCLIStartSessionFail = fmt.Errorf("TestRCLIStartSessionFail")
52 )
53
54
55 func setAuthHeaders(req *http.Request) {
56 req.Header.Set(eaconst.HeaderAuthKeyUsername, "user")
57 req.Header.Set(eaconst.HeaderAuthKeyEmail, "email")
58 req.Header.Set(eaconst.HeaderAuthKeyRoles, "role")
59 req.Header.Set(eaconst.HeaderAuthKeyBanners, "banner")
60 }
61
62
65
66 type httpmiddleware func(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request)
67
68 type authserverOpts struct {
69 middleware []httpmiddleware
70
71 authorizeCommand func(w http.ResponseWriter, r *http.Request)
72 authorizeRequest func(w http.ResponseWriter, r *http.Request)
73 resolveTarget func(w http.ResponseWriter, r *http.Request)
74 authorizeTarget func(w http.ResponseWriter, r *http.Request)
75 authorizeUser func(w http.ResponseWriter, r *http.Request)
76 }
77
78 type Option func(opts *authserverOpts)
79
80
81
82
83 func verifyUserAuthHeaders(t *testing.T) httpmiddleware {
84 return func(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
85 return func(w http.ResponseWriter, r *http.Request) {
86 assert.Equal(t, []string{"user"}, r.Header.Values(eaconst.HeaderAuthKeyUsername))
87 assert.Equal(t, []string{"email"}, r.Header.Values(eaconst.HeaderAuthKeyEmail))
88 assert.Equal(t, []string{"role"}, r.Header.Values(eaconst.HeaderAuthKeyRoles))
89 assert.Equal(t, []string{"banner"}, r.Header.Values(eaconst.HeaderAuthKeyBanners))
90
91 next(w, r)
92 }
93 }
94 }
95
96
97
98 func WithMiddleware(middleware ...httpmiddleware) Option {
99 return func(opts *authserverOpts) {
100 opts.middleware = middleware
101 }
102 }
103
104 func defaultAuthorizeRequest(status int) func(w http.ResponseWriter, r *http.Request) {
105 return func(w http.ResponseWriter, r *http.Request) {
106 if status != http.StatusOK {
107
108
109 w.WriteHeader(status)
110 }
111
112
113 bytes, err := io.ReadAll(r.Body)
114 if err != nil {
115 w.WriteHeader(http.StatusInternalServerError)
116 return
117 }
118
119 var m map[string]map[string]json.RawMessage
120 err = json.Unmarshal(bytes, &m)
121 if err != nil {
122 w.WriteHeader(http.StatusInternalServerError)
123 return
124 }
125
126 var n map[string]string
127 err = json.Unmarshal(m["Request"]["Data"], &n)
128 if err != nil {
129 w.WriteHeader(http.StatusInternalServerError)
130 return
131 }
132
133
134 if n["command"] == "false" {
135
136
137
138 w.WriteHeader(http.StatusUnauthorized)
139 _, _ = w.Write([]byte(`{
140 "errorCode": 62001,
141 "ErrorMessage": "User Authorization Failure - User not permitted to perform this action"
142 }`))
143 return
144 }
145
146
147
148
149 req, err := msgdata.NewV1_0Request(defaultCommand)
150 if err != nil {
151 w.WriteHeader(http.StatusInternalServerError)
152 return
153 }
154 d, err := req.Data()
155 if err != nil {
156 w.WriteHeader(http.StatusInternalServerError)
157 return
158 }
159
160 data := authRequestResponse{
161 Request: struct {
162 Data json.RawMessage
163 Attributes map[string]string
164 }{
165 Data: json.RawMessage(d),
166 Attributes: req.Attributes(),
167 },
168 }
169 resp, err := json.Marshal(data)
170 if err != nil {
171 w.WriteHeader(http.StatusInternalServerError)
172 return
173 }
174
175 _, err = w.Write(resp)
176 if err != nil {
177 w.WriteHeader(http.StatusInternalServerError)
178 return
179 }
180 }
181 }
182
183 func WithAuthorizeCommand(authorizeCommand func(w http.ResponseWriter, r *http.Request)) Option {
184 return func(opts *authserverOpts) {
185 opts.authorizeCommand = authorizeCommand
186 }
187 }
188
189 func defaultAuthorizeCommand(status int) func(w http.ResponseWriter, r *http.Request) {
190 return func(w http.ResponseWriter, r *http.Request) {
191 w.WriteHeader(status)
192 bytes, err := io.ReadAll(r.Body)
193 if err != nil {
194 w.WriteHeader(http.StatusInternalServerError)
195 return
196 }
197 var m map[string]interface{}
198 err = json.Unmarshal(bytes, &m)
199 if err != nil {
200 w.WriteHeader(http.StatusInternalServerError)
201 return
202 }
203 command, ok := m["Command"].(string)
204 if !ok {
205 w.WriteHeader(http.StatusInternalServerError)
206 return
207 }
208 validation := eagateway.CommandValidation{Valid: true}
209 if command == badCommand {
210 validation.Valid = false
211 }
212 resp, err := json.Marshal(validation)
213 if err != nil {
214 w.WriteHeader(http.StatusInternalServerError)
215 return
216 }
217 _, err = w.Write(resp)
218 if err != nil {
219 w.WriteHeader(http.StatusInternalServerError)
220 return
221 }
222 }
223 }
224
225
226 func WithResolveTarget(resolveTarget func(w http.ResponseWriter, r *http.Request)) Option {
227 return func(opts *authserverOpts) {
228 opts.resolveTarget = resolveTarget
229 }
230 }
231
232 func defaultResolveTarget() func(w http.ResponseWriter, r *http.Request) {
233 return func(w http.ResponseWriter, _ *http.Request) {
234 data, _ := json.Marshal(map[string]types.Target{
235 "target": defaultTarget,
236 })
237 _, _ = w.Write(data)
238 }
239 }
240
241
242 func WithAuthorizeTarget(authorizeTarget func(w http.ResponseWriter, r *http.Request)) Option {
243 return func(opts *authserverOpts) {
244 opts.authorizeTarget = authorizeTarget
245 }
246 }
247
248 func defaultAuthorizeTarget(status int) func(w http.ResponseWriter, r *http.Request) {
249 return func(w http.ResponseWriter, _ *http.Request) {
250 w.WriteHeader(status)
251 }
252 }
253
254 func WithAuthorizeUser(authorizeUser func(w http.ResponseWriter, r *http.Request)) Option {
255 return func(opts *authserverOpts) {
256 opts.authorizeUser = authorizeUser
257 }
258 }
259
260 func defaultAuthorizeUser(status int) func(w http.ResponseWriter, r *http.Request) {
261 return func(w http.ResponseWriter, _ *http.Request) {
262 w.WriteHeader(status)
263 }
264 }
265
266 func authserviceServer(status int, opts ...Option) (server *httptest.Server, url string) {
267 opt := authserverOpts{
268 authorizeCommand: defaultAuthorizeCommand(status),
269 authorizeRequest: defaultAuthorizeRequest(status),
270 authorizeTarget: defaultAuthorizeTarget(status),
271 resolveTarget: defaultResolveTarget(),
272 authorizeUser: defaultAuthorizeUser(status),
273 }
274 for _, o := range opts {
275 o(&opt)
276 }
277
278 for _, mid := range opt.middleware {
279 opt.authorizeCommand = mid(opt.authorizeCommand)
280 opt.authorizeRequest = mid(opt.authorizeRequest)
281 opt.authorizeTarget = mid(opt.authorizeTarget)
282 opt.resolveTarget = mid(opt.resolveTarget)
283 }
284
285 mux := http.NewServeMux()
286 mux.HandleFunc("/authservice/authorizeCommand", opt.authorizeCommand)
287 mux.HandleFunc("/authservice/authorizeRequest", opt.authorizeRequest)
288 mux.HandleFunc("/authservice/authorizeTarget", opt.authorizeTarget)
289 mux.HandleFunc("/authservice/resolveTarget", opt.resolveTarget)
290 mux.HandleFunc("/authservice/authorizeUser", opt.authorizeUser)
291
292 server = httptest.NewServer(mux)
293 url = path.Join(server.URL[7:], "authservice")
294 return server, url
295 }
296
297
300
301 func TestServerStatusEndpoints(t *testing.T) {
302 tests := map[string]struct {
303 query string
304 expRes string
305 expCode int
306 }{
307 "Ready Returns Ok": {
308 "/ready",
309 `ok`,
310 200,
311 },
312 "Health Returns Ok": {
313 "/health",
314 `ok`,
315 200,
316 },
317 }
318
319 for name, tc := range tests {
320 t.Run(name, func(t *testing.T) {
321 r := httptest.NewRecorder()
322
323
324 gin.SetMode(gin.TestMode)
325 _, ginEngine := gin.CreateTestContext(r)
326
327
328
329
330
331
332 _, err := New(eagateway.Config{AuthServiceHost: "localhost"}, ginEngine, newLogger(), nil, nil)
333 assert.NoError(t, err)
334
335
336 req, err := http.NewRequest(http.MethodGet, tc.query, nil)
337 assert.NoError(t, err)
338 ginEngine.ServeHTTP(r, req)
339
340
341 res := r.Result()
342 assert.Equal(t, tc.expCode, res.StatusCode)
343 data, err := io.ReadAll(r.Body)
344 assert.NoError(t, err)
345
346 assert.Equal(t, tc.expRes, string(data))
347 })
348 }
349 }
350
View as plain text