Skip to content

No difference between no security requirement and empty security requirement on Operations #1426

Closed

Description

Describe the bug
There is no way of telling 'empty' from 'not defined' security requirement objects, during deserialization.
I.e no way of distinguishing the 2 different security requirement objects

paths:
  /pets:
    post:
      responses:
        '201':
          description: Created
      security: []
    get:
      responses:
        '200':
          description: A paged array of pets

Why is this important?

The specification states the following for Operation Security

To remove a top-level security declaration, an empty array can be used.

i.e security: []

however it is expected that if security is not defined on an operation level

get:
  responses:
    '200':
      description: A paged array of pets

That the global security is applied, defined on the top level document object.

in the following spec

openapi: '3.0.0'
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
security:
  - Authorization:
    - readwrite
servers:
  - url: http://petstore.swagger.io/v1
paths:
  /pets:
    post:
      responses:
        '201':
          description: Created
      security: []
    get:
      responses:
        '200':
          description: A paged array of pets
components:
  securitySchemes:
    Authorization:
      type: http
      scheme: bearer
      bearerFormat: JWT

post deserialization, it is impossible to determine which security is actually applied between the 2 operations, as both security requirements are deserialized into the same value
public IList<OpenApiSecurityRequirement> Security { get; set; } = new List<OpenApiSecurityRequirement>();
which ends up being empty in both cases.

The reason for this is most likely that during reading a new OpenApiSecurityRequirement() and as this is a dictionary, there is no way of specifying a null key, so to speak.

The problem being that the semantics between the 2 operations are different in the spec.

To Reproduce
Deserialize the above spec.

Expected behavior
To have a way of differentiating the 2 scenarios. (feasibly one would be empty, the other would be null.

Screenshots/Code Snippets

var input = @"openapi: '3.0.0'
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
security:
  - Authorization:
    - readwrite
servers:
  - url: http://petstore.swagger.io/v1
paths:
  /pets:
    post:
      responses:
        '201':
          description: Created
      security: []
    get:
      responses:
        '200':
          description: A paged array of pets
components:
  securitySchemes:
    Authorization:
      type: http
      scheme: bearer
      bearerFormat: JWT";
var document = new OpenApiStringReader().Read(input, out var diagnostics);

Activity

  1. darrelmiller commented on Oct 17, 2023

    @darrelmiller
    Member

    Thank you for bringing this to our attention. We have two options here to solve this problem. We can either add a new AnonymousAccess property to the OpenApiOperation object to allow users to explicitly state they want to override the security with no security. Or the other option is to stop defaulting the Security property to an empty list and treat a non-null value as an indication that they want to override the security.

    // Option 1 - Breaking change
    var operation = new OpenApiOperation();
    operation.Security = null;  // Default value
    
    // Set Anonymous access
    operation.Security = new List<OpenApiSecurityRequirement>() [];  
    
    
    // Option 2 - Non breaking change
    var operation = new OpenApiOperation();
    operation.Security = new List<OpenApiSecurityRequirement>() [];  // Default value
    operation.AnonymousAccess = false;  // Anonymous access default
    
    // Set Anonymous access
    operation.AnonymousAccess = true;  

    We can do Option 2 in the current major version of OpenAPI.NET because it is not breaking, however, if we go with Option 1 we will need to wait until the v2 release.

  2. VisualBean commented on Oct 17, 2023

    @VisualBean
    Author

    Personally, I think nulling it, is more in line with what is expected from a dotnet point of view.

    • We specifically found empty vs we found nothing. so to speak.

    Edited: to state the desired option without option number.

    Option 1 does have the added effect of it, then being the ONLY list, that isn't newed up automatically.
    also it 'might' technically be a breaking change for everyone relying on the existing behaviour.
    So waiting for v2 might be the safest bet, in any case.

  3. crudbee commented on Oct 18, 2023

    @crudbee

    I think option 1 and 2 have been flipped around, from the description to the examples: Option 1 adding AnonymousAccess, Option 2 defaulting to null.

    Defaulting to null is the breaking change, so you both seem in agreement to wait for a v2 with it.

    Null vs. default is similar to how it would be treated in F# (to my understanding) with option, where Some [] is the explicit override, and None is the lack of the property. The None tends to be mapped from null. I'd feel more comfortable with this option 2, explicit null, rather than a new property whose name I can't see mapping to the OpenAPI spec itself.

  4. corentinvds commented on Oct 17, 2024

    @corentinvds

    Hello,

    Any update on this issue ?
    Is there a known workaround other than not using global security specifications ?

    Thanks

  5. paulmendix commented on Feb 5, 2025

    @paulmendix
    Contributor

    Hi! Has a decision been reached on how to best proceed? Returning null when no security property is set on the operation?

    There seems to be a v2 version on it's way as preview5 has been released recently. I might be interested in contributing a fix (since I need a fix 😬) but then it's good to be sure what the approach should be.

  6. darrelmiller commented on Mar 12, 2025

    @darrelmiller
    Member

    Paul Rijneveld @ Mendix (@paulmendix) We would be most appreciative of a PR. However, this work should be only done after we have completed the NRT work #1971 and #2146

  7. paulmendix commented on Apr 6, 2025

    @paulmendix
    Contributor

    Thanks for the update! I will keep an eye on these issues

  8. MaggieKimani1 commented on Apr 11, 2025

    @MaggieKimani1
    Contributor

    Paul Rijneveld @ Mendix (@paulmendix) both the NRT and perf work are complete if you'd still like to contribute by sending a PR our way.🙂

  9. paulmendix commented on Apr 11, 2025

    @paulmendix
    Contributor

    Thanks Maggie Kimani (@MaggieKimani1) I will give it a go

  10. crudbee commented on May 13, 2025

    @crudbee

    Having silently watched in on this for over a year, thank you very much for seeing this through to main :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    WIPtype:breaking-changeAn issue that will result in dependent client projects failing.type:bugA broken experience

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions