Here is my resource
#Path("test")
#DenyAll
public class TestResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response test() {
return Response.status(Response.Status.OK).entity("ok").build();
}
}
When I run the application and call GET /test the response is sent.
I am kind of confused, is there something else to do in addition to the annotation? Am I supposed to deny access myself in a filter?
When I use #RolesAllowed() I don't have to implement anything...
Thanks.
If you look at the source code for RolesAllowedDynamicFeature, you will see two two thing:
DenyAll is never checked for on classes.
There is a comment // DenyAll can't be attached to classes
Related
Assuming I have a controller like:
public class MyController {
public String endpoint1() {...}
public String endpoint2() {...}
}
I want to disable endpoint1 for whatever reason in Spring. Simply, just disable it so that it cannot be accessed. So, I am not looking for how and what response to return in that case or how to secure that endpoint. Just looking to simply disable the endpoint, something like #Disabled annotation on it or so.
SOLUTION UPDATE:
Thanks all who contributed. I decided to go with #AdolinK suggestion . However, that solution will only disable access to the controller resulting into 404 Not Found. However, if you use OpenApi, your controller and all of its models such as request/response body will still show in swagger.
So, in addition to Adolin's suggestion and also added #Hidden OpenApi annotation to my controllers like:
In application.properties, set:
cars.controller.enabled=false
Then in your controller, use it. To hide controller from the OpenApi/Swagger as well, you can use #Hiden tag:
#Hidden
#ConditionalOnExpression("${cars.controller.enabled}")
#RestController
#RequestMapping("/cars")
public class Carontroller {
...
}
After this, every end point handled by this controller will return 404 Not Found and OpenApi/Swagger will not show the controllers nor any of its related schema objects such as CarRequestModel, CarResponseModel etc.
You can use #ConditionalOnExpression annotation.
public class MyController {
#ConditionalOnExpression("${my.controller.enabled:false}")
public String endpoint1() {...}
public String endpoint2() {...}
}
In application.properties, you indicates that controller is enabled by default
my.controller.enabled=true
ConditionalOnExpression sets false your property, and doesn't allow access to end-point
Why not remove the mapping annotation over that method?
Try this simple approach: You can define a property is.enable.enpoint1 to turn on/off your endpoint in a flexible way.
If you turn off the endpoint, then return a 404 or error page, which depends on your situation.
#Value("${is.enable.enpoint1}")
private String isEnableEnpoint1;
public String endpoint1() {
if (!"true".equals(isEnableEnpoint1)) {
return "404";
}
// code
}
Say I have a #RestController like below:
#RestController
#RequestMapping("/1st")
public class MyController {
#GetMapping("/2nd/aaa")
public void getAaa() {
...
}
#GetMapping("/2nd/bbb")
public void getBbb() {
...
}
}
I want to add methods to catch all requests with the base path "/1st" and "/1st/2nd" in between and then continue to the correct endpoint. I tried adding:
#GetMapping("/**")
public void doThisFirst() {
...
}
But that didn't work, a request to "/1st/2nd/bbb" still only landed on the method getBbb() only. Please help, thank you.
I want to add methods to catch all requests with the base path "/1st"
and "/1st/2nd" in between and then continue to the correct endpoint. I
tried adding:
#GetMapping("/**") public void doThisFirst() {
... }
Probably you want to execute some extra code (code in doThisFirst) before you execute the respecting code that each endpoint have.
There are 2 solutions here.
A) You define an aspect with #Before that will be executed before the code that your final endpoint has. Here is some example code
B) You define an interceptor which will be executed only before those 2 endpoints. Check here some previous SO answer.
Either the interceptor or the aspect should contain the code that you have in doThisFirst() and you want to execute before you reach the actual endpoint.
In every case this starting code should not be inside a controller, so you can remove the #GetMapping("/**") from the controller.
I am attempting to implement a filter in a micronaut microservice, using the example code documented in Section 6.18 of the documentation:
https://docs.micronaut.io/latest/guide/index.html#filters
I have a HelloWord service that is essentially the same as the service provided on the documentation, with a controller that goes to "/hello" (as documented). I am also using the same TraceService and trace filter that is provided in Section 6.18. I am compiling and running the server without problems.
Unfortunately, the filter is not being engaged when I test the microservice.
I am pretty sure that something is missing in my code, but as I said I am using the same code that is in the example:
TraceService Class
import io.micronaut.http.HttpRequest;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
import org.slf4j.*;
import javax.inject.Singleton;
#Singleton
public class TraceService {
private static final Logger LOG = LoggerFactory.getLogger(TraceService.class);
Flowable<Boolean> trace(HttpRequest<?> request) {
System.out.println("TRACE ENGAGED!");
return Flowable.fromCallable(() -> {
if (LOG.isDebugEnabled()) {
LOG.debug("Tracing request: " + request.getUri());
}
// trace logic here, potentially performing I/O
return true;
}).subscribeOn(Schedulers.io());
}
}
Trace Filter
import io.micronaut.http.*;
import io.micronaut.http.annotation.Filter;
import io.micronaut.http.filter.*;
import org.reactivestreams.Publisher;
#Filter("/hello/**")
public class TraceFilter implements HttpServerFilter {
private final TraceService traceService;
public TraceFilter(TraceService traceService) {
System.out.println("Filter created!");
this.traceService = traceService;
}
#Override
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
System.out.println("Filter engaged!");
return traceService.trace(request)
.switchMap(aBoolean -> chain.proceed(request))
.doOnNext(res -> res.getHeaders().add("X-Trace-Enabled", "true")
);
}
}
The Controller
import io.micronaut.http.annotation.*;
#Controller("/hello")
public class HelloController {
#Get("/")
public String index() {
return "Hello World";
}
}
Note that the controller uses code from Section 2.2 of the documentation:
https://docs.micronaut.io/latest/guide/index.html#creatingServer
I did a number of things to try and see what was happening with the filter, including putting little printouts in strategic parts of the Service and the filter. These printouts are not printing out, which tells me that the filter is not being created or used by Micronaut.
Clearly I am missing somethning. I suspect that there is something I need to do in order to get the system to engage the filter. Unfortunately the documentation just tells how to make the filter, not how to use it in the microservice. Furthermore, there don't appear to be any complete code examples that tell how to make the request system utilize the filter (maybe there is an annotation I need to add to the controller???).
Could someone tell me what I am missing? How do I get the filter to work? At the very least, could someone provide a complete example of how to create the filter and use it in an actual microservice?
Problem solved.
It actually helps a great deal if one puts the filter and service files in the right place. It was late when I made the files and I put them in the test area, not the development area. Once placed in the right place, the filter was properly injected into the microservice.
Sorry for the waste of space here, folks. Is there any way a poster can delete an embarrassing post?
I am building REST service using Dropwizard 8.2.0. I have 2 resources: FolderResource and FileResource:
#Path("folder")
public class FolderResource {
#Path("{name}/file")
public FileResource getFileResource() {
return new FileResource();
}
}
public class FileResource() {
#GET
#Path("{id}")
#Produces("application/json")
public Response getFileInfo() {
return Response.ok().entity("{}").build();
}
}
The intention here is that when "folder/xyz/file/5" is called, getFileInfo() method will be invoked.
This Jersey feature is described here:
https://jersey.java.net/documentation/latest/jaxrs-resources.html#d0e2464
However when embedded in Dropwizard not only getFileInfo() not called, the getFileResource() function also not being invoked.
If I add #GET annotation to getFileResource() method, then it does get called, but returns FileResource JSON representation which is of course not the goal and is contrary to the documentation that clearly states that method should NOT be annotated with method designators.
What am I doing wrong ?
#Path("folder") and #Path("{name}/file") results in folder{name}/file.
You need to add a slash in between, i.e. #Path("/{name}/file"). You'll have the same issue on getFileInfo as well, so rename it to #Path("/{id}").
I would like to use both #Post and #Get on the same method like
#GET
#POST
#Path("{mode}")
public void paymentFinish(#PathParam("mode") String mode, String s) {
logger.debug("Enter PayStatus POST");
logger.debug(mode);
}
Even I write like this, I got error. What I want is whatever get or post to the sameurl, the same method works. Is it possible? Now I separate two methods, one for get and one for post.
Unfortunately, only one should be used in order to avoid Jersey exception.
But you could do something like :
#GET
#Path("{mode}")
public void paymentFinish(#PathParam("mode") String mode, String s) {
commonFunction(mode);
}
#POST
#Path("{mode}")
public void paymentFinishPOST(#PathParam("mode") String mode, String s) {
commonFunction(mode);
}
private void commonFunction(String mode)
{
logger.debug("Enter PayStatus POST");
logger.debug(mode);
}
By doing so, if you want to change inner behavior of your functions, you will only have to change one function.
Note that method name in java for get vs post need to be different.
After searching a lot trying to avoid the solution above, I found nothing....
Then I decided to create a custom annotation so I didn't have to waste time duplicating methods.
Here's the github link: Jersey-Gest
It allows you to create GET and Post Methods on a single Annotation by generating a new class from it.
I hope it helps you the same way it helped me :)
Edit:
If for some reason the above link stops working, here's what I did:
Created a compile-time annotation #RestMethod for class methods.
Created a compile-time annotation #RestClass for classes.
Create an AnnotationProcessor which generates a new class with Jersey's corresponding annotations and for each method creates a GET and a POST method which callsback to the original method annotated with #RestClass.
All methods annotated with #RestMethod must be static and contained within a class annotated with #RestClass.
Example (TestService.java):
#RestClass(path = "/wsdl")
public class TestService
{
#RestMethod(path = "/helloGest")
public static String helloGest()
{
return "Hello Gest!";
}
}
Generates something like (TestServiceImpl.java):
#Path("/wsdl")
#Produces("application/xml")
public class TestServiceImpl
{
#GET
#Path("/helloGest")
#Produces(MediaType.APPLICATION_XML)
public String helloGestGet()
{
return TestService.helloGest();
}
#POST
#Path("/helloGest")
#Consumes(MediaType.WILDCARD)
#Produces(MediaType.APPLICATION_XML)
public String helloGestPost()
{
return TestService.helloGest();
}
}