diff --git a/pom.xml b/pom.xml index 6adf25e..5a4e51e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.sinistral proteus-core - 0.3.7-SNAPSHOT + 0.3.7 proteus core Proteus is an extremely light, fast, and flexible Java REST API framework built atop Undertow. http://github.com/noboomu/proteus @@ -192,9 +192,6 @@ test - - org.junit.jupiter junit-jupiter-api @@ -202,7 +199,6 @@ test - org.junit.vintage junit-vintage-engine diff --git a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java index dcc3cc7..002096e 100644 --- a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java +++ b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java @@ -13,7 +13,6 @@ import io.sinistral.proteus.server.ServerRequest; import io.sinistral.proteus.server.ServerResponse; import io.sinistral.proteus.server.endpoints.EndpointInfo; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.undertow.server.HandlerWrapper; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; @@ -34,10 +33,8 @@ import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; import java.io.File; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; +import java.lang.annotation.Annotation; +import java.lang.reflect.*; import java.net.URI; import java.net.URL; import java.util.*; @@ -354,12 +351,30 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class cla List typeLevelSecurityDefinitions = new ArrayList<>(); if (Optional.ofNullable(clazz.getAnnotation(Path.class)).isPresent()) { - SecurityRequirement securityRequirementAnnotation = clazz.getAnnotation(SecurityRequirement.class); + + Annotation[] annotations = clazz.getAnnotations(); + + Annotation securityRequirementAnnotation = Arrays.stream(annotations).filter(a -> a.getClass().getName().contains("SecurityRequirement" + + "")).findFirst().orElse(null); if (securityRequirementAnnotation != null) { - String securityRequirement = securityRequirementAnnotation.name(); - typeLevelSecurityDefinitions.add(securityRequirement); + if (securityRequirementAnnotation != null) { + + try { + Field nameField = securityRequirementAnnotation.getClass().getField("name"); + + if (nameField != null) { + Object securityRequirement = nameField.get(securityRequirementAnnotation); + typeLevelSecurityDefinitions.add(securityRequirement.toString()); + } + + } catch (Exception e) { + log.warn("No name field on security requirement"); + } + + } + } } @@ -754,12 +769,31 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class cla */ if (Optional.ofNullable(m.getAnnotation(Path.class)).isPresent()) { - SecurityRequirement securityRequirementAnnotation = m.getAnnotation(SecurityRequirement.class); + + Annotation[] annotations = clazz.getAnnotations(); + + Annotation securityRequirementAnnotation = Arrays.stream(annotations).filter( a -> a.getClass().getName().contains("SecurityRequirement") ).findFirst().orElse(null); if (securityRequirementAnnotation != null) { - String securityRequirement = securityRequirementAnnotation.name(); - securityDefinitions.add(securityRequirement); + if (securityRequirementAnnotation != null) { + + try + { + Field nameField = securityRequirementAnnotation.getClass().getField("name"); + + if(nameField != null) { + Object securityRequirement = nameField.get(securityRequirementAnnotation); + securityDefinitions.add(securityRequirement.toString()); + } + + } catch( Exception e ) + { + log.warn("No name field on security requirement"); + } + + } + } } diff --git a/src/test/java/io/sinistral/proteus/test/controllers/Tests.java b/src/test/java/io/sinistral/proteus/test/controllers/Tests.java index 27769cc..820466b 100644 --- a/src/test/java/io/sinistral/proteus/test/controllers/Tests.java +++ b/src/test/java/io/sinistral/proteus/test/controllers/Tests.java @@ -44,8 +44,10 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tags; +import io.swagger.v3.oas.models.servers.Server; import io.undertow.server.HttpServerExchange; /** @@ -108,7 +110,7 @@ public void exchangeJsonSerializeToBytes(HttpServerExchange exchange) @GET - @Path("/exchange/user/json") + @Path("exchange/user/json") @Operation(description = "User serialization endpoint" ) public void exchangeUserJson(HttpServerExchange exchange) { @@ -116,7 +118,7 @@ public void exchangeUserJson(HttpServerExchange exchange) } @GET - @Path("/exchange/user/xml") + @Path("exchange/user/xml") @Produces((MediaType.APPLICATION_XML)) @Operation(description = "User serialization endpoint" ) public void exchangeUserXml(HttpServerExchange exchange) @@ -125,7 +127,7 @@ public void exchangeUserXml(HttpServerExchange exchange) } @GET - @Path("/response/user/json") + @Path("response/user/json") @Operation(description = "User serialization endpoint" ) public ServerResponse responseUserJson(ServerRequest request) { @@ -135,7 +137,7 @@ public ServerResponse responseUserJson(ServerRequest request) } @GET - @Path("/response/user/xml") + @Path("response/user/xml") @Produces((MediaType.APPLICATION_XML)) @Operation(description = "User serialization endpoint" ) public ServerResponse responseUserXml(ServerRequest request) @@ -147,7 +149,7 @@ public ServerResponse responseUserXml(ServerRequest request) @GET - @Path("/exchange/plaintext") + @Path("exchange/plaintext") @Produces((MediaType.TEXT_PLAIN)) @Operation(description = "Plaintext endpoint" ) public void exchangePlaintext(HttpServerExchange exchange) @@ -157,7 +159,7 @@ public void exchangePlaintext(HttpServerExchange exchange) } @GET - @Path("/exchange/plaintext2") + @Path("exchange/plaintext2") @Produces((MediaType.TEXT_PLAIN)) @Operation(description = "Plaintext endpoint 2" ) public void exchangePlaintext2(HttpServerExchange exchange) @@ -167,7 +169,7 @@ public void exchangePlaintext2(HttpServerExchange exchange) } @GET - @Path("/response/plaintext") + @Path("response/plaintext") @Produces((MediaType.TEXT_PLAIN)) @Operation(description = "Plaintext endpoint" ) public ServerResponse responsePlaintext(ServerRequest request) @@ -177,7 +179,7 @@ public ServerResponse responsePlaintext(ServerRequest request) } @GET - @Path("/response/future/map") + @Path("response/future/map") @Operation(description = "Future map endpoint" ) public CompletableFuture>> responseFutureMap( ServerRequest request ) { @@ -186,7 +188,7 @@ public CompletableFuture>> responseFutureMap( } @GET - @Path("/response/map") + @Path("response/map") @Operation(description = "Map endpoint" ) public ServerResponse> futureMap( ServerRequest request ) { @@ -195,7 +197,7 @@ public ServerResponse> futureMap( ServerRequest request ) } @POST - @Path("/response/file/path") + @Path("response/file/path") @Produces(MediaType.APPLICATION_OCTET_STREAM) @Consumes(MediaType.MULTIPART_FORM_DATA) @Operation(description = "Upload file path endpoint" ) @@ -205,7 +207,7 @@ public ServerResponse responseUploadFilePath(ServerRequest request, } @POST - @Path("/response/file/path/optional") + @Path("response/file/path/optional") @Produces(MediaType.APPLICATION_OCTET_STREAM) @Consumes(MediaType.MULTIPART_FORM_DATA) @Operation(description = "Upload optional file path endpoint" ) @@ -222,7 +224,7 @@ public ServerResponse responseUploadOptionalFilePath(ServerRequest r } @POST - @Path("/response/json/echo") + @Path("response/json/echo") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.MULTIPART_FORM_DATA) @Operation(description = "Echo json endpoint" ) @@ -232,7 +234,7 @@ public ServerResponse responseEchoJson(ServerRequest request, @FormParam(" } @POST - @Path("/response/json/beanparam") + @Path("response/json/beanparam") @Produces(MediaType.APPLICATION_OCTET_STREAM) @Consumes(MediaType.APPLICATION_JSON) @Operation(description = "Echo json inner class endpoint" ) @@ -243,7 +245,7 @@ public ServerResponse responseInnerClassTest(ServerRequest request, @BeanP @GET - @Path("/generic/set") + @Path("generic/set") @Produces((MediaType.APPLICATION_JSON)) @Operation(description = "Generic set endpoint" ) public ServerResponse> genericSet( ServerRequest request, @QueryParam("ids") Set ids ) throws Exception @@ -253,7 +255,7 @@ public ServerResponse> genericSet( ServerRequest request, @QueryParam @POST - @Path("/generic/set/bean") + @Path("generic/set/bean") @Produces((MediaType.APPLICATION_JSON)) @Consumes(MediaType.APPLICATION_JSON) @Operation(description = "Generic bean set endpoint" ) @@ -264,7 +266,7 @@ public ServerResponse> genericBeanSet( ServerRequest request, @BeanPa @POST - @Path("/generic/list/bean") + @Path("generic/list/bean") @Produces((MediaType.APPLICATION_JSON)) @Consumes(MediaType.APPLICATION_JSON) @@ -275,7 +277,7 @@ public ServerResponse> genericBeanList( ServerRequest request, @Bean } @GET - @Path("/optional/set") + @Path("optional/set") @Produces((MediaType.APPLICATION_JSON)) @Operation(description = "Generic optional set endpoint" ) public ServerResponse> genericOptionalSet( ServerRequest request, @QueryParam("ids") Optional> ids ) throws Exception @@ -285,7 +287,7 @@ public ServerResponse> genericOptionalSet( ServerRequest request, @Qu @GET - @Path("/redirect/permanent") + @Path("redirect/permanent") @Operation(description = "Permanent redirect endpoint" ) @Produces(MediaType.WILDCARD) public ServerResponse testPermanentRedirect() @@ -294,7 +296,7 @@ public ServerResponse testPermanentRedirect() } @GET - @Path("/redirect") + @Path("redirect") @Operation(description = "Redirect endpoint" ) @Produces(MediaType.WILDCARD) public ServerResponse testRedirect() @@ -303,7 +305,7 @@ public ServerResponse testRedirect() } @POST - @Path("/response/parse/ids") + @Path("response/parse/ids") @Blocking @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @@ -317,7 +319,7 @@ public ServerResponse> listConversion( ServerRequest request, @BeanPa } @GET - @Path("/response/parse/timestamp") + @Path("response/parse/timestamp") @Blocking @Produces(MediaType.TEXT_PLAIN) @Operation(description = "Convert timestamp") @@ -330,7 +332,7 @@ public ServerResponse timestampConversion( ServerRequest request, @Q } @GET - @Path("/response/parse/instant") + @Path("response/parse/instant") @Blocking @Produces(MediaType.TEXT_PLAIN) @Operation(description = "Convert instant") @@ -343,7 +345,7 @@ public ServerResponse instantConversion( ServerRequest request, @Que } @POST - @Path("/response/bytebuffer") + @Path("response/bytebuffer") @Produces(MediaType.APPLICATION_OCTET_STREAM) @Consumes("*/*") @Operation(description = "Upload file path endpoint") @@ -356,7 +358,7 @@ public ServerResponse responseUploadByteBuffer(ServerRequest request } @POST - @Path("/response/file") + @Path("response/file") @Produces(MediaType.APPLICATION_OCTET_STREAM) @Consumes("*/*") @Operation(description = "Upload file path endpoint") @@ -372,7 +374,7 @@ public ServerResponse responseUploadFile(ServerRequest request, @For } @GET - @Path("/response/debug") + @Path("response/debug") @Operation(description = "Debug endpoint") public ServerResponse> debugEndpoint(ServerRequest request) { @@ -389,7 +391,7 @@ public ServerResponse> debugEndpoint(ServerRequest request) @GET - @Path("/response/debug/blocking") + @Path("response/debug/blocking") @Blocking @Operation(description="Debug blocking endpoint") public ServerResponse> debugBlockingEndpoint(ServerRequest request) @@ -406,7 +408,7 @@ public ServerResponse> debugBlockingEndpoint(ServerRequest re } @GET - @Path("/response/future/user") + @Path("response/future/user") @Operation(description="Future user endpoint") @Produces((MediaType.APPLICATION_JSON)) public CompletableFuture> responseFutureUser() @@ -415,7 +417,7 @@ public CompletableFuture> responseFutureUser() } @GET - @Path("/response/parameters/complex/{pathLong}") + @Path("response/parameters/complex/{pathLong}") @Operation(description = "Complex parameters" ) @Produces((MediaType.APPLICATION_JSON)) public ServerResponse> complexParameters( @@ -454,4 +456,17 @@ public ServerResponse> complexParameters( responseMap.put("queryIntegerList", queryIntegerList); return response(responseMap).applicationJson(); } + + @GET + @SecurityRequirement(name = "testRequirement") + @Path("secure/resource") + @Operation(description="Secure resource") + @Produces(MediaType.APPLICATION_JSON) + public ServerResponse> responseSecureContext() + { + Map responseMap = new HashMap<>(); + responseMap.put("secure",true); + + return response(responseMap); + } } diff --git a/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java b/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java index b7708cd..a20b5ea 100644 --- a/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java +++ b/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java @@ -89,6 +89,12 @@ public void testOpenAPIDocs() { when().get("openapi.yaml").then().statusCode(200); } + + @Test + public void testSecurityRequirementEndpoint() + { + when().get("tests/secure/resource").then().statusCode(200); + } @Test public void testDebugEndpoint() diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 8b93a28..265ca0f 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -17,8 +17,8 @@ - - + +