diff --git a/parameters/validate_security.go b/parameters/validate_security.go index e5ce0989..53492b45 100644 --- a/parameters/validate_security.go +++ b/parameters/validate_security.go @@ -124,24 +124,37 @@ func (v *paramValidator) validateHTTPSecurityScheme( request *http.Request, pathValue string, ) (bool, []*errors.ValidationError) { - switch strings.ToLower(secScheme.Scheme) { - case "basic", "bearer", "digest": - if request.Header.Get("Authorization") == "" { - validationErrors := []*errors.ValidationError{ - { - Message: fmt.Sprintf("Authorization header for '%s' scheme", secScheme.Scheme), - Reason: "Authorization header was not found", - ValidationType: helpers.SecurityValidation, - ValidationSubType: secScheme.Scheme, - SpecLine: sec.GoLow().Requirements.ValueNode.Line, - SpecCol: sec.GoLow().Requirements.ValueNode.Column, - HowToFix: "Add an 'Authorization' header to this request", - }, - } - errors.PopulateValidationErrors(validationErrors, request, pathValue) - return false, validationErrors + authorizationHeader := request.Header.Get("Authorization") + if authorizationHeader == "" { + validationErrors := []*errors.ValidationError{ + { + Message: fmt.Sprintf("Authorization header for '%s' scheme", secScheme.Scheme), + Reason: "Authorization header was not found", + ValidationType: helpers.SecurityValidation, + ValidationSubType: secScheme.Scheme, + SpecLine: sec.GoLow().Requirements.ValueNode.Line, + SpecCol: sec.GoLow().Requirements.ValueNode.Column, + HowToFix: "Add an 'Authorization' header to this request", + }, } - return true, nil + errors.PopulateValidationErrors(validationErrors, request, pathValue) + return false, validationErrors + } + if len(authorizationHeader) < len(secScheme.Scheme) || !strings.EqualFold(authorizationHeader[:len(secScheme.Scheme)], secScheme.Scheme) { + validationErrors := []*errors.ValidationError{ + { + Message: fmt.Sprintf("Authorization header scheme '%s' mismatch", secScheme.Scheme), + Reason: "Authorization header had incorrect scheme", + ValidationType: helpers.SecurityValidation, + ValidationSubType: secScheme.Scheme, + SpecLine: sec.GoLow().Requirements.ValueNode.Line, + SpecCol: sec.GoLow().Requirements.ValueNode.Column, + HowToFix: fmt.Sprintf("Use the scheme '%s' in the Authorization header "+ + "for this request", secScheme.Scheme), + }, + } + errors.PopulateValidationErrors(validationErrors, request, pathValue) + return false, validationErrors } return true, nil } diff --git a/parameters/validate_security_test.go b/parameters/validate_security_test.go index 8b90212a..78d9ead5 100644 --- a/parameters/validate_security_test.go +++ b/parameters/validate_security_test.go @@ -998,8 +998,8 @@ components: assert.Empty(t, errors) } -func TestParamValidator_ValidateSecurity_UnknownHTTPScheme(t *testing.T) { - // Test custom HTTP scheme - unknown to our validator, should pass through (not fail) +func TestParamValidator_ValidateSecurity_CustomHTTPScheme(t *testing.T) { + // Test custom HTTP scheme - should pass with correct scheme in header spec := `openapi: 3.1.0 paths: /products: @@ -1017,8 +1017,9 @@ components: m, _ := doc.BuildV3Model() v := NewParameterValidator(&m.Model) - // Request with no auth - should pass because custom scheme is not validated + // Request with custom auth header - should pass request, _ := http.NewRequest(http.MethodGet, "https://things.com/products", nil) + request.Header.Add("Authorization", "Custom dXNlcjpwYXNz") valid, errors := v.ValidateSecurity(request) assert.True(t, valid) @@ -1053,3 +1054,32 @@ components: assert.True(t, valid) assert.Empty(t, errors) } + +func TestParamValidator_ValidateSecurity_HTTPScheme_Mismatch(t *testing.T) { + // Test http scheme with mismatch in header: should return errors + spec := `openapi: 3.1.0 +paths: + /products: + get: + security: + - CustomAuth: [] +components: + securitySchemes: + CustomAuth: + type: http + scheme: custom +` + + doc, _ := libopenapi.NewDocument([]byte(spec)) + m, _ := doc.BuildV3Model() + v := NewParameterValidator(&m.Model) + + // Request with auth header - should fail as header scheme is incorrect + request, _ := http.NewRequest(http.MethodGet, "https://things.com/products", nil) + request.Header.Add("Authorization", "Basic dXNlcjpwYXNz") + + valid, errors := v.ValidateSecurity(request) + assert.False(t, valid) + assert.Len(t, errors, 1) + assert.Contains(t, errors[0].Message, "Authorization header scheme 'custom' mismatch") +}