@@ -2,6 +2,7 @@ package auth
22
33import (
44 "context"
5+ "errors"
56 "net/http"
67 "net/url"
78 "os"
@@ -15,6 +16,7 @@ import (
1516 "github.com/snapp-incubator/Cerberus/internal/tracing"
1617 "go.opentelemetry.io/otel/attribute"
1718 otelcodes "go.opentelemetry.io/otel/codes"
19+ "go.opentelemetry.io/otel/trace"
1820 "google.golang.org/grpc/codes"
1921 "google.golang.org/grpc/status"
2022)
@@ -159,27 +161,8 @@ func (a *Authenticator) Check(ctx context.Context, request *Request) (finalRespo
159161 wsvc , ns , reason := readRequestContext (request )
160162
161163 // generate opentelemetry span with given parameters
162- parentCtx := tracing .ReadParentSpanFromRequest (ctx , request .Request )
163- ctx , span := tracing .StartSpan (parentCtx , "CheckFunction" ,
164- attribute .String ("webservice" , wsvc ),
165- attribute .String ("namespace" , ns ),
166- )
167- defer func () {
168- extraAttrs := []attribute.KeyValue {
169- attribute .String ("cerberus-reason" , string (reason )),
170- }
171- if finalResponse != nil {
172- extraAttrs = append (extraAttrs ,
173- attribute .Bool ("final-response-ok" , finalResponse .Allow ),
174- )
175- for k , v := range finalResponse .Response .Header {
176- extraAttrs = append (extraAttrs ,
177- attribute .String ("final-extra-headers-" + k , strings .Join (v , "," )),
178- )
179- }
180- }
181- tracing .EndSpan (span , start_time , extraAttrs ... )
182- }()
164+ ctx , span := startSpan (ctx , request .Request , wsvc , ns )
165+ defer endSpan (span , start_time , finalResponse , reason )
183166
184167 if reason != "" {
185168 return generateResponse (reason , nil ), nil
@@ -193,6 +176,7 @@ func (a *Authenticator) Check(ctx context.Context, request *Request) (finalRespo
193176 var extraHeaders ExtraHeaders
194177
195178 reason , wsvcCacheEntry := a .readService (wsvc )
179+ addHeadersToSpan (request .Request , wsvcCacheEntry , span )
196180 if reason == "" {
197181 var cerberusExtraHeaders CerberusExtraHeaders
198182
@@ -214,6 +198,53 @@ func (a *Authenticator) Check(ctx context.Context, request *Request) (finalRespo
214198 return
215199}
216200
201+ // startSpan starts span for Check Function
202+ func startSpan (ctx context.Context , request http.Request , wsvc string , ns string ) (context.Context , trace.Span ) {
203+ parentCtx := tracing .ReadParentSpanFromRequest (ctx , request )
204+ return tracing .StartSpan (parentCtx , "CheckFunction" ,
205+ attribute .String ("webservice" , wsvc ),
206+ attribute .String ("namespace" , ns ),
207+ )
208+ }
209+
210+ // endSpan ends Check Function span and adds attributes.
211+ func endSpan (span trace.Span , start_time time.Time , finalResponse * Response , reason CerberusReason ) {
212+ extraAttrs := []attribute.KeyValue {
213+ attribute .String ("cerberus-reason" , string (reason )),
214+ }
215+ if finalResponse != nil {
216+ extraAttrs = append (extraAttrs ,
217+ attribute .Bool ("final-response-ok" , finalResponse .Allow ),
218+ )
219+ for k , v := range finalResponse .Response .Header {
220+ extraAttrs = append (extraAttrs ,
221+ attribute .String ("final-extra-headers-" + k , strings .Join (v , "," )),
222+ )
223+ }
224+ }
225+ tracing .EndSpan (span , start_time , extraAttrs ... )
226+ }
227+
228+ // addHeadersToSpan adds request headers to Span
229+ func addHeadersToSpan (request http.Request , service WebservicesCacheEntry , span trace.Span ) {
230+ // Add request headers to span
231+ for headerName , headerValues := range request .Header {
232+ headerValue := strings .Join (headerValues , "," )
233+
234+ // For Authorization header, only include first 20 chars
235+ if headerName == service .Spec .LookupHeader && len (headerValue ) > 20 {
236+ headerValue = headerValue [:20 ]
237+ }
238+ if hasUpstreamAuth (service ) && headerName == service .Spec .UpstreamHttpAuth .ReadTokenFrom && len (headerValue ) > 20 {
239+ headerValue = headerValue [:20 ]
240+ }
241+
242+ span .SetAttributes (
243+ attribute .String ("http.header." + headerName , headerValue ),
244+ )
245+ }
246+ }
247+
217248func readRequestContext (request * Request ) (wsvc string , ns string , reason CerberusReason ) {
218249 wsvc = request .Context ["webservice" ]
219250 if wsvc == "" {
@@ -253,14 +284,23 @@ func NewAuthenticator(logger logr.Logger) *Authenticator {
253284// validateUpstreamAuthRequest validates the service before calling the upstream.
254285// when calling the upstream authentication, one of read or write tokens must be
255286// empty and the upstream address must be a valid url.
256- func validateUpstreamAuthRequest (service WebservicesCacheEntry ) CerberusReason {
287+ func validateUpstreamAuthRequest (service WebservicesCacheEntry , request * Request ) CerberusReason {
257288 if service .Spec .UpstreamHttpAuth .ReadTokenFrom == "" ||
258289 service .Spec .UpstreamHttpAuth .WriteTokenTo == "" {
259290 return CerberusReasonTargetAuthTokenEmpty
260291 }
261292 if ! govalidator .IsRequestURL (service .Spec .UpstreamHttpAuth .Address ) {
262293 return CerberusReasonInvalidUpstreamAddress
263294 }
295+ if request != nil {
296+ token := request .Request .Header .Get (service .Spec .UpstreamHttpAuth .ReadTokenFrom )
297+ if token == "" {
298+ upstreamAuthEmptyTokens .Inc ()
299+
300+ // uncomment if you want to stop upstream auth call when token is empty
301+ // return CerberusReasonUpstreamAuthHeaderEmpty
302+ }
303+ }
264304 return ""
265305}
266306
@@ -332,12 +372,16 @@ func (a *Authenticator) checkServiceUpstreamAuth(service WebservicesCacheEntry,
332372 )
333373 }()
334374
335- if reason := validateUpstreamAuthRequest (service ); reason != "" {
375+ if reason := validateUpstreamAuthRequest (service , request ); reason != "" {
376+ span .RecordError (errors .New ("upstream auth request validation:" + string (reason )))
377+ span .SetStatus (otelcodes .Error , "upstream auth http request faild" )
336378 return reason
337379 }
338380 upstreamAuth := service .Spec .UpstreamHttpAuth
339381 req , err := setupUpstreamAuthRequest (& upstreamAuth , request )
340382 if err != nil {
383+ span .RecordError (err )
384+ span .SetStatus (otelcodes .Error , "failed to create upstream auth request" )
341385 return CerberusReasonUpstreamAuthNoReq
342386 }
343387 a .adjustTimeout (upstreamAuth .Timeout , downstreamDeadline , hasDownstreamDeadline )
@@ -368,6 +412,8 @@ func (a *Authenticator) checkServiceUpstreamAuth(service WebservicesCacheEntry,
368412 }
369413
370414 if resp .StatusCode != http .StatusOK {
415+ span .RecordError (err )
416+ span .SetStatus (otelcodes .Error , "upstream auth non 200 status code" )
371417 return CerberusReasonUnauthorized
372418 }
373419 // add requested careHeaders to extraHeaders for response
0 commit comments