github.com/Axway/agent-sdk@v1.1.101/pkg/transaction/httpprotocolbuilder.go (about) 1 package transaction 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 8 "github.com/Axway/agent-sdk/pkg/traceability/redaction" 9 ) 10 11 // HTTPProtocolBuilder - Interface to build the HTTP protocol details for transaction log event 12 type HTTPProtocolBuilder interface { 13 SetURI(uri string) HTTPProtocolBuilder 14 SetVersion(version string) HTTPProtocolBuilder 15 SetArgs(args string) HTTPProtocolBuilder 16 SetArgsMap(args map[string][]string) HTTPProtocolBuilder 17 AddArg(key string, value []string) HTTPProtocolBuilder 18 SetMethod(method string) HTTPProtocolBuilder 19 SetStatus(status int, statusText string) HTTPProtocolBuilder 20 SetUserAgent(userAgent string) HTTPProtocolBuilder 21 SetHost(host string) HTTPProtocolBuilder 22 SetByteLength(byteReceived, byteSent int) HTTPProtocolBuilder 23 SetRemoteAddress(remoteName string, remoteAddr string, remotePort int) HTTPProtocolBuilder 24 SetLocalAddress(localAddr string, localPort int) HTTPProtocolBuilder 25 SetSSLProperties(sslProtocol, sslServerName, sslSubject string) HTTPProtocolBuilder 26 SetAuthSubjectID(authSubjectID string) HTTPProtocolBuilder 27 SetHeaders(requestHeaders, responseHeaders string) HTTPProtocolBuilder 28 SetRequestHeaders(requestHeaders map[string]string) HTTPProtocolBuilder 29 SetResponseHeaders(responseHeaders map[string]string) HTTPProtocolBuilder 30 AddRequestHeader(headerKey string, headerValue string) HTTPProtocolBuilder 31 AddResponseHeader(headerKey string, headerValue string) HTTPProtocolBuilder 32 SetIndexedHeaders(indexedRequestHeaders, indexedResponseHeaders string) HTTPProtocolBuilder 33 SetIndexedRequestHeaders(indexedRequestHeaders map[string]string) HTTPProtocolBuilder 34 SetIndexedResponseHeaders(indexedResponseHeaders map[string]string) HTTPProtocolBuilder 35 AddIndexedRequestHeader(headerKey string, headerValue string) HTTPProtocolBuilder 36 AddIndexedResponseHeader(headerKey string, headerValue string) HTTPProtocolBuilder 37 SetPayload(requestPayload, responsePayload string) HTTPProtocolBuilder 38 SetWAFStatus(wasStatus int) HTTPProtocolBuilder 39 SetRedactionConfig(config redaction.Redactions) HTTPProtocolBuilder 40 41 Build() (TransportProtocol, error) 42 } 43 44 type httpProtocolBuilder struct { 45 HTTPProtocolBuilder 46 err error 47 httpProtocol *Protocol 48 argsMap map[string][]string 49 requestHeaders map[string]string 50 responseHeaders map[string]string 51 indexedRequestHeaders map[string]string 52 indexedResponseHeaders map[string]string 53 redactionConfig redaction.Redactions 54 } 55 56 // NewHTTPProtocolBuilder - Creates a new http protocol builder 57 func NewHTTPProtocolBuilder() HTTPProtocolBuilder { 58 builder := &httpProtocolBuilder{ 59 httpProtocol: &Protocol{ 60 Type: "http", 61 Version: "1.1", 62 }, 63 argsMap: make(map[string][]string), 64 requestHeaders: make(map[string]string), 65 responseHeaders: make(map[string]string), 66 indexedRequestHeaders: make(map[string]string), 67 indexedResponseHeaders: make(map[string]string), 68 } 69 return builder 70 } 71 72 func (b *httpProtocolBuilder) SetURI(uri string) HTTPProtocolBuilder { 73 if b.err != nil { 74 return b 75 } 76 b.httpProtocol.uriRaw = uri 77 return b 78 } 79 80 func (b *httpProtocolBuilder) SetVersion(version string) HTTPProtocolBuilder { 81 if b.err != nil { 82 return b 83 } 84 b.httpProtocol.Version = version 85 return b 86 } 87 88 func (b *httpProtocolBuilder) SetArgs(args string) HTTPProtocolBuilder { 89 if b.err != nil || args == "" { 90 return b 91 } 92 var argMap map[string][]string 93 b.err = json.Unmarshal([]byte(args), &argMap) 94 if b.err == nil { 95 b.argsMap = argMap 96 } 97 return b 98 } 99 100 func (b *httpProtocolBuilder) AddArg(key string, value []string) HTTPProtocolBuilder { 101 if b.err != nil { 102 return b 103 } 104 if _, ok := b.argsMap[key]; ok { 105 b.err = fmt.Errorf("arg with key %s has already been added", key) 106 } else { 107 b.argsMap[key] = value 108 } 109 return b 110 } 111 112 func (b *httpProtocolBuilder) SetArgsMap(args map[string][]string) HTTPProtocolBuilder { 113 if b.err != nil { 114 return b 115 } 116 b.argsMap = args 117 return b 118 } 119 120 func (b *httpProtocolBuilder) SetMethod(method string) HTTPProtocolBuilder { 121 if b.err != nil { 122 return b 123 } 124 b.httpProtocol.Method = method 125 return b 126 } 127 128 func (b *httpProtocolBuilder) SetStatus(status int, statusText string) HTTPProtocolBuilder { 129 if b.err != nil { 130 return b 131 } 132 b.httpProtocol.Status = status 133 b.httpProtocol.StatusText = statusText 134 return b 135 } 136 137 func (b *httpProtocolBuilder) SetUserAgent(userAgent string) HTTPProtocolBuilder { 138 if b.err != nil { 139 return b 140 } 141 b.httpProtocol.UserAgent = userAgent 142 return b 143 } 144 145 func (b *httpProtocolBuilder) SetHost(host string) HTTPProtocolBuilder { 146 if b.err != nil { 147 return b 148 } 149 b.httpProtocol.Host = host 150 return b 151 } 152 153 func (b *httpProtocolBuilder) SetByteLength(byteReceived, byteSent int) HTTPProtocolBuilder { 154 if b.err != nil { 155 return b 156 } 157 b.httpProtocol.BytesReceived = byteReceived 158 b.httpProtocol.BytesSent = byteSent 159 return b 160 } 161 162 func (b *httpProtocolBuilder) SetRemoteAddress(remoteName string, remoteAddr string, remotePort int) HTTPProtocolBuilder { 163 if b.err != nil { 164 return b 165 } 166 b.httpProtocol.RemoteName = remoteName 167 b.httpProtocol.RemoteAddr = remoteAddr 168 b.httpProtocol.RemotePort = remotePort 169 return b 170 } 171 172 func (b *httpProtocolBuilder) SetLocalAddress(localAddr string, localPort int) HTTPProtocolBuilder { 173 if b.err != nil { 174 return b 175 } 176 b.httpProtocol.LocalAddr = localAddr 177 b.httpProtocol.LocalPort = localPort 178 return b 179 } 180 181 func (b *httpProtocolBuilder) SetSSLProperties(sslProtocol string, sslServerName string, sslSubject string) HTTPProtocolBuilder { 182 if b.err != nil { 183 return b 184 } 185 b.httpProtocol.SslProtocol = sslProtocol 186 b.httpProtocol.SslServerName = sslServerName 187 b.httpProtocol.SslSubject = sslSubject 188 return b 189 } 190 191 func (b *httpProtocolBuilder) SetAuthSubjectID(authSubjectID string) HTTPProtocolBuilder { 192 if b.err != nil { 193 return b 194 } 195 b.httpProtocol.AuthSubjectID = authSubjectID 196 return b 197 } 198 199 func (b *httpProtocolBuilder) SetHeaders(requestHeadersString, responseHeadersString string) HTTPProtocolBuilder { 200 if b.err != nil { 201 return b 202 } 203 204 if requestHeadersString != "" { 205 var requestHeaders map[string]string 206 b.err = json.Unmarshal([]byte(requestHeadersString), &requestHeaders) 207 if b.err != nil { 208 return b 209 } 210 b.requestHeaders = requestHeaders 211 } 212 213 if requestHeadersString != "" { 214 var responseHeaders map[string]string 215 b.err = json.Unmarshal([]byte(responseHeadersString), &responseHeaders) 216 if b.err != nil { 217 return b 218 } 219 b.responseHeaders = responseHeaders 220 } 221 return b 222 } 223 224 func (b *httpProtocolBuilder) SetRequestHeaders(requestHeaders map[string]string) HTTPProtocolBuilder { 225 if b.err != nil { 226 return b 227 } 228 b.requestHeaders = requestHeaders 229 return b 230 } 231 232 func (b *httpProtocolBuilder) AddRequestHeader(key string, value string) HTTPProtocolBuilder { 233 if b.err != nil { 234 return b 235 } 236 if _, ok := b.requestHeaders[key]; ok { 237 b.err = fmt.Errorf("response Header with key %s has already been added", key) 238 } else { 239 b.requestHeaders[key] = value 240 } 241 return b 242 } 243 244 func (b *httpProtocolBuilder) SetResponseHeaders(responseHeaders map[string]string) HTTPProtocolBuilder { 245 if b.err != nil { 246 return b 247 } 248 b.responseHeaders = responseHeaders 249 return b 250 } 251 252 func (b *httpProtocolBuilder) AddResponseHeader(key string, value string) HTTPProtocolBuilder { 253 if b.err != nil { 254 return b 255 } 256 if _, ok := b.responseHeaders[key]; ok { 257 b.err = fmt.Errorf("response Header with key %s has already been added", key) 258 } else { 259 b.responseHeaders[key] = value 260 } 261 return b 262 } 263 264 func (b *httpProtocolBuilder) SetIndexedHeaders(indexedRequestHeadersString, indexedResponseHeadersString string) HTTPProtocolBuilder { 265 if b.err != nil { 266 return b 267 } 268 269 var indexedRequestHeaders map[string]string 270 b.err = json.Unmarshal([]byte(indexedRequestHeadersString), &indexedRequestHeaders) 271 if b.err != nil { 272 return b 273 } 274 b.indexedRequestHeaders = indexedRequestHeaders 275 276 var indexedResponseHeaders map[string]string 277 b.err = json.Unmarshal([]byte(indexedResponseHeadersString), &indexedResponseHeaders) 278 if b.err != nil { 279 return b 280 } 281 b.indexedResponseHeaders = indexedResponseHeaders 282 return b 283 } 284 285 func (b *httpProtocolBuilder) SetIndexedRequestHeaders(indexedRequestHeaders map[string]string) HTTPProtocolBuilder { 286 if b.err != nil { 287 return b 288 } 289 b.indexedRequestHeaders = indexedRequestHeaders 290 return b 291 } 292 293 func (b *httpProtocolBuilder) AddIndexedRequestHeader(key string, value string) HTTPProtocolBuilder { 294 if b.err != nil { 295 return b 296 } 297 if _, ok := b.indexedRequestHeaders[key]; ok { 298 b.err = fmt.Errorf("indexed Response Header with key %s has already been added", key) 299 } else { 300 b.indexedRequestHeaders[key] = value 301 } 302 return b 303 } 304 305 func (b *httpProtocolBuilder) SetIndexedResponseHeaders(indexedResponseHeaders map[string]string) HTTPProtocolBuilder { 306 if b.err != nil { 307 return b 308 } 309 b.indexedResponseHeaders = indexedResponseHeaders 310 return b 311 } 312 313 func (b *httpProtocolBuilder) AddIndexedResponseHeader(key string, value string) HTTPProtocolBuilder { 314 if b.err != nil { 315 return b 316 } 317 if _, ok := b.indexedResponseHeaders[key]; ok { 318 b.err = fmt.Errorf("indexed Response Header with key %s has already been added", key) 319 } else { 320 b.indexedResponseHeaders[key] = value 321 } 322 return b 323 } 324 325 func (b *httpProtocolBuilder) SetPayload(requestPayload, responsePayload string) HTTPProtocolBuilder { 326 if b.err != nil { 327 return b 328 } 329 b.httpProtocol.RequestPayload = requestPayload 330 b.httpProtocol.ResponsePayload = responsePayload 331 return b 332 } 333 334 func (b *httpProtocolBuilder) SetWAFStatus(wasStatus int) HTTPProtocolBuilder { 335 if b.err != nil { 336 return b 337 } 338 b.httpProtocol.WafStatus = wasStatus 339 return b 340 } 341 342 func (b *httpProtocolBuilder) SetRedactionConfig(config redaction.Redactions) HTTPProtocolBuilder { 343 if b.err != nil { 344 return b 345 } 346 b.redactionConfig = config 347 return b 348 } 349 350 func (b *httpProtocolBuilder) Build() (TransportProtocol, error) { 351 if b.err != nil { 352 return nil, b.err 353 } 354 // Complete the redactions 355 b.queryArgsRedaction() 356 if b.err != nil { 357 return nil, b.err 358 } 359 b.headersRedaction() 360 if b.err != nil { 361 return nil, b.err 362 } 363 //set redacted URI 364 if b.httpProtocol.uriRaw == "" { 365 return nil, errors.New("Raw Uri property not set in HTTP protocol details") 366 } 367 if b.redactionConfig == nil { 368 b.httpProtocol.URI, _ = redaction.URIRedaction(b.httpProtocol.uriRaw) 369 } else { 370 b.httpProtocol.URI, _ = b.redactionConfig.URIRedaction(b.httpProtocol.uriRaw) 371 } 372 373 // b.indexedHeadersRedaction() // Indexed headers are not currently used in central 374 375 if b.httpProtocol.RequestHeaders == "" || b.httpProtocol.ResponseHeaders == "" { 376 return nil, errors.New("request or Response Headers not set in HTTP protocol details") 377 } 378 379 if b.httpProtocol.URI == "" { 380 return nil, errors.New("uri property not set in HTTP protocol details") 381 } 382 383 if b.httpProtocol.Method == "" { 384 return nil, errors.New("method property not set in HTTP protocol details") 385 } 386 387 if b.httpProtocol.Host == "" { 388 return nil, errors.New("host property not set in HTTP protocol details") 389 } 390 391 if b.httpProtocol.Status < 100 || b.httpProtocol.Status > 600 { 392 return nil, errors.New("invalid status code set in HTTP protocol details") 393 } 394 return b.httpProtocol, nil 395 } 396 397 func (b *httpProtocolBuilder) queryArgsRedaction() { 398 // skip if there is already an error 399 if b.err != nil { 400 return 401 } 402 var redactedArgs map[string][]string 403 var err error 404 if len(b.argsMap) > 0 { 405 if b.redactionConfig == nil { 406 redactedArgs, err = redaction.QueryArgsRedaction(b.argsMap) 407 } else { 408 redactedArgs, err = b.redactionConfig.QueryArgsRedaction(b.argsMap) 409 } 410 if err != nil { 411 b.err = ErrInRedactions.FormatError("QueryArgs", err) 412 return 413 } 414 argBytes, err := json.Marshal(redactedArgs) 415 if err != nil { 416 b.err = err 417 return 418 } 419 b.httpProtocol.Args = string(argBytes) 420 } 421 } 422 423 func (b *httpProtocolBuilder) headersRedaction() { 424 // skip if there is already an error 425 if b.err != nil { 426 return 427 } 428 429 b.httpProtocol.RequestHeaders, b.httpProtocol.ResponseHeaders, b.err = 430 headersRedaction(b.requestHeaders, b.responseHeaders, b.redactionConfig) 431 } 432 433 func (b *httpProtocolBuilder) indexedHeadersRedaction() { 434 // skip if there is already an error 435 if b.err != nil { 436 return 437 } 438 439 b.httpProtocol.IndexedRequestHeaders, b.httpProtocol.IndexedResponseHeaders, b.err = 440 headersRedaction(b.indexedRequestHeaders, b.indexedResponseHeaders, b.redactionConfig) 441 } 442 443 func headersRedaction(requestHeaders, responseHeaders map[string]string, redactionConfig redaction.Redactions) (string, string, error) { 444 const emptyHeaders = "{}" 445 reqHeadersBytes := []byte(emptyHeaders) 446 resHeadersBytes := []byte(emptyHeaders) 447 448 if len(requestHeaders) > 0 { 449 var redactedHeaders map[string]string 450 var err error 451 if redactionConfig == nil { 452 redactedHeaders, err = redaction.RequestHeadersRedaction(requestHeaders) 453 } else { 454 redactedHeaders, err = redactionConfig.RequestHeadersRedaction(requestHeaders) 455 } 456 if err != nil { 457 return emptyHeaders, emptyHeaders, ErrInRedactions.FormatError("RequestHeaders", err) 458 } 459 reqHeadersBytes, err = json.Marshal(redactedHeaders) 460 if err != nil { 461 return emptyHeaders, emptyHeaders, ErrInRedactions.FormatError("RequestHeaders", err) 462 } 463 } 464 465 if len(responseHeaders) > 0 { 466 var redactedHeaders map[string]string 467 var err error 468 if redactionConfig == nil { 469 redactedHeaders, err = redaction.ResponseHeadersRedaction(responseHeaders) 470 } else { 471 redactedHeaders, err = redactionConfig.ResponseHeadersRedaction(responseHeaders) 472 } 473 if err != nil { 474 return emptyHeaders, emptyHeaders, ErrInRedactions.FormatError("ResponseHeaders", err) 475 } 476 resHeadersBytes, err = json.Marshal(redactedHeaders) 477 if err != nil { 478 return emptyHeaders, emptyHeaders, ErrInRedactions.FormatError("ResponseHeaders", err) 479 } 480 } 481 482 return string(reqHeadersBytes), string(resHeadersBytes), nil 483 }