Repository: quarkusio/quarkus
Issue: RolesAllowed overrides OpenAPI definitions for 401 and 403 responses

### Describe the bug

I noticed the when I added `APIResponse` annotations to my REST endpoint to document the 401 and 403 responses, the OpenAPI documentation overrides my descriptions, and instead shows "Not Authorized" (401) and "Not Allowed" (403).  I've traced this down to using the `RolesAllowed` annotation.  If I use `Authenticated`, or no annotation at all, then the documentation reflects the `APIResponse` annotations.

### Expected behavior

OpenAPI documentation should be using the provided `APIResponse` annotations to document the 401 and 403 endpoint responses.

### Actual behavior

OpenAPI documentation is using hard-coded "Not Authorized" and "Not Allowed" response descriptions for the 401 and 403 response status codes.  This appears to be coming from https://github.com/quarkusio/quarkus/blob/e21e338d19ef3d15e2eec07cd2fd613a76375565/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoRolesAllowedFilter.java#L80

### How to Reproduce?

See attached reproducer.  

1. Run in dev mode (./mvnw clean compile quarkus:dev)
2. check the OpenAPI documentation at http://localhost:8080/q/openapi.json
3. Note that the 401 and 403 documentation use the references
4. Change the GreetingResource class to use the RolesAllowed annotation (either at the class or method level, doesn't matter)
5. refresh the OpenAPI documentation
6. Note that the 401 and 403 documentation is now ignoring the references, and is instead hard-coded to "Not Authorized" and "Not Allowed"

### Output of `uname -a` or `ver`

Linux laverne 5.11.0-40-generic #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

### Output of `java -version`

openjdk version "11.0.13" 2021-10-19

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

2.7.1.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)

### Additional information

_No response_

Changed files:
extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel.java
extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java
extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoRolesAllowedFilter.java
extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java

diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoRolesAllowedFilter.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoRolesAllowedFilter.java
old mode 100644
new mode 100755
index 60a3bc946c8..aab73cd9abb
--- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoRolesAllowedFilter.java
+++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoRolesAllowedFilter.java
@@ -95,7 +95,9 @@ public void filterOpenAPI(OpenAPI openAPI) {
                                     operation = operation.addSecurityRequirement(securityRequirement);
                                     APIResponses responses = operation.getResponses();
                                     for (APIResponseImpl response : getSecurityResponses()) {
-                                        responses.addAPIResponse(response.getResponseCode(), response);
+                                        if (!responses.hasAPIResponse(response.getResponseCode())) {
+                                            responses.addAPIResponse(response.getResponseCode(), response);
+                                        }
                                     }
                                     operation = operation.responses(responses);
                                 } else if (hasAuthenticatedMethodReferences()
@@ -105,7 +107,9 @@ public void filterOpenAPI(OpenAPI openAPI) {
                                     operation = operation.addSecurityRequirement(securityRequirement);
                                     APIResponses responses = operation.getResponses();
                                     for (APIResponseImpl response : getSecurityResponses()) {
-                                        responses.addAPIResponse(response.getResponseCode(), response);
+                                        if (!responses.hasAPIResponse(response.getResponseCode())) {
+                                            responses.addAPIResponse(response.getResponseCode(), response);
+                                        }
                                     }
                                     operation = operation.responses(responses);
                                 }
diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java
index c17095d201d..a9d4b797170 100644
--- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java
+++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java
@@ -55,4 +55,78 @@ public void testAutoSecurityRequirement() {
 
     }
 
+    @Test
+    public void testOpenAPIAnnotations() {
+        RestAssured.given().header("Accept", "application/json")
+                .when().get("/q/openapi")
+                .then()
+                .log().body()
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/1'.get.responses.401.description",
+                        Matchers.equalTo("Not Authorized"))
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/1'.get.responses.403.description",
+                        Matchers.equalTo("Not Allowed"))
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/2'.get.responses.401.description",
+                        Matchers.equalTo("Not Authorized"))
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/2'.get.responses.403.description",
+                        Matchers.equalTo("Not Allowed"))
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/3'.get.responses.401.description",
+                        Matchers.nullValue())
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/3'.get.responses.403.description",
+                        Matchers.nullValue())
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/4'.get.responses.401.description",
+                        Matchers.equalTo("Who are you?"))
+                .and()
+                .body("paths.'/resource2/test-security/classLevel/4'.get.responses.403.description",
+                        Matchers.equalTo("You cannot do that."))
+                .and()
+                .body("paths.'/resource2/test-security/naked'.get.responses.401.description",
+                        Matchers.equalTo("Not Authorized"))
+                .and()
+                .body("paths.'/resource2/test-security/naked'.get.responses.403.description",
+                        Matchers.equalTo("Not Allowed"))
+                .and()
+                .body("paths.'/resource2/test-security/annotated'.get.responses.401.description",
+                        Matchers.nullValue())
+                .and()
+                .body("paths.'/resource2/test-security/annotated'.get.responses.403.description",
+                        Matchers.nullValue())
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/1'.get.responses.401.description",
+                        Matchers.equalTo("Not Authorized"))
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/1'.get.responses.403.description",
+                        Matchers.equalTo("Not Allowed"))
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/2'.get.responses.401.description",
+                        Matchers.equalTo("Not Authorized"))
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/2'.get.responses.403.description",
+                        Matchers.equalTo("Not Allowed"))
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/public'.get.responses.401.description",
+                        Matchers.nullValue())
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/public'.get.responses.403.description",
+                        Matchers.nullValue())
+                .and()
+                .body("paths.'/resource2/test-security/annotated/documented'.get.responses.401.description",
+                        Matchers.equalTo("Who are you?"))
+                .and()
+                .body("paths.'/resource2/test-security/annotated/documented'.get.responses.403.description",
+                        Matchers.equalTo("You cannot do that."))
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/3'.get.responses.401.description",
+                        Matchers.equalTo("Who are you?"))
+                .and()
+                .body("paths.'/resource2/test-security/methodLevel/3'.get.responses.403.description",
+                        Matchers.equalTo("You cannot do that."));
+    }
+
 }
diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel.java
old mode 100644
new mode 100755
index fe0e2d7b1aa..2d6749566c6
--- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel.java
+++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel.java
@@ -4,6 +4,8 @@
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 
+import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
+import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
 import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
 import org.eclipse.microprofile.openapi.annotations.servers.Server;
 import org.eclipse.microprofile.openapi.annotations.tags.Tag;
@@ -35,4 +37,14 @@ public String secureEndpoint3() {
         return "secret";
     }
 
+    @APIResponses({
+            @APIResponse(responseCode = "401", description = "Who are you?"),
+            @APIResponse(responseCode = "403", description = "You cannot do that.")
+    })
+    @GET
+    @Path("/test-security/classLevel/4")
+    public String secureEndpoint4() {
+        return "secret";
+    }
+
 }
diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java
old mode 100644
new mode 100755
index af31dad4c85..ff3e17182fa
--- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java
+++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java
@@ -4,6 +4,8 @@
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 
+import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
+import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
 import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
 import org.eclipse.microprofile.openapi.annotations.servers.Server;
 import org.eclipse.microprofile.openapi.annotations.tags.Tag;
@@ -50,4 +52,27 @@ public String publicEndpoint() {
         return "boo";
     }
 
+    @APIResponses({
+            @APIResponse(responseCode = "401", description = "Who are you?"),
+            @APIResponse(responseCode = "403", description = "You cannot do that.")
+    })
+    @GET
+    @Path("/test-security/annotated/documented")
+    @RolesAllowed("admin")
+    @SecurityRequirement(name = "JWTCompanyAuthentication")
+    public String secureEndpointWithSecurityAnnotationAndDocument() {
+        return "secret";
+    }
+
+    @APIResponses({
+            @APIResponse(responseCode = "401", description = "Who are you?"),
+            @APIResponse(responseCode = "403", description = "You cannot do that.")
+    })
+    @GET
+    @Path("/test-security/methodLevel/3")
+    @RolesAllowed("admin")
+    public String secureEndpoint3() {
+        return "secret";
+    }
+
 }