How to protect restful webservice from unauhtorised access - java

I have a JAX-RS Restful webservice. This resource/webservice is asset for us. I am exposing this service url to third party client that would call this service resource. I want to protect this service from another authorised client/vendors.
Thus my question is -
How to protect this.
I thought to include an API key and the API key should be matched with a perticuler client API Key. And I also need to match the client url address means from whcih url the request is coming.
How to do this. How to get the URL that is calling the our rest service. I am deploying my rest in Tomcat 7.0.
Thanks
Update --
#Path("report")
#Produces(javax.ws.rs.core.MediaType.APPLICATION_XML)
public class DnaReportResource {
#GET
#Produces(javax.ws.rs.core.MediaType.APPLICATION_XML)
public void getDnaReport(#Context UriInfo uri) {
System.out.println(uri.getRequestUri());
System.out.println(uri.getPath());
System.out.println(uri.getAbsolutePath());
System.out.println(uri.getBaseUri());
//MultivaluedMap<String, String> queryParams = uri.getQueryParameters();
}
}

From your servlet handler you can call
String url = request.getRequestURL().toString();
Getting request URL in a servlet
EDIT
did you try
String url = uri.getRequestUri().toString();
What does it return?

You can make use of Tomcat Realm configuration to achieve authenticate your clients.

Related

Method Not Allowed REST Java when trying to do POST

I just want to create a simple REST service and it uses #GET and #POST.
for the #GET function, everything is ok but for #POST, when I want to create a new user on my server the browser just keeps sating (METHOD NOT ALLOWED).
I read so many articles about how to fix this error but I haven't got anything yet.
My code for #POST :
#Path("/hello")
public class HelloResource(){
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("/post")
public Response createUser(#PathParam("name") String name,#PathParam("address") String address,#PathParam("birthYear") String birth,#PathParam("ps") String password) throws NotAllowedException,MethodNotFoundException,Exception {
DataStore.getInstance().putPerson(new Person(name, address, Integer.parseInt(birth), password));
String json = "{\n";
json += "\"status\": " + '"'+"CREATED" +'"'+ ",\n";
json+="}";
return Response.status(200).entity(json).build();
}}
I also tried adding #Consumes function with (MediaType.APPLICATION.JSON) and (MediaType.TEXT_PLAIN) but nothing changed.
Also the URL I enter for posting is :
http://localhost:8080/HelloREST/rest/hello/post?name=PouYad&address=mustbejsonlater&birthYear=2005&ps=12345
As you see I also tried so many exception handlers.
Can someone please help?
if you enter your URL in the browser URL address field, it won't work because the browser will send a "GET" request. So you must use a client that will allow you to send a "POST" like PostMan. Or write your own small httpConnection function that sends a "POST"
You also have to change the #PathParam to #FormParam for it to work (#QueryParam will also work, but because it is POST, it is best to use #FormParm).
Access URL directly through browser can only create Get Request, not POST Request
You should
Create HTML Form, set the action to your service url with POST method, and then submit it.
Use Rest Client like postman to access your service with POST method.
Write your own Http Client using java.net.http api or just simply use
one of the handy libraries/frameworks (Like Spring has RestTemplate).

Spring Cloud Zuul: RedirectView redirecting to service and not gateway

I'm a bit new to microservices and Spring. I have Spring Cloud microservices (ports: 8xxx-8xxx) with a Zuul gateway running on port 9000. There's a method inside a controller on a UI service which should do a login and then return to a index.html page:
#RequestMapping(value="/do-login", method = RequestMethod.POST)
public RedirectView doLogin (#ModelAttribute("authEntity") final AuthEntity authEntity, final Model model) {
model.addAttribute(VERSION, applicationVersion);
model.addAttribute("authEntity", new AuthEntity());
authenticatedStatus = true;
model.addAttribute(AUTHENTICATED, authenticatedStatus);
return new RedirectView("index");
}
The problem is that when above method completes it returns an url of the microservice itself localhost:8888/index but not localhost:9000/services/ui/.
If I use a simpler method:
#RequestMapping(value="/do-login", method = RequestMethod.POST)
public String doLogin (#ModelAttribute("authEntity") final AuthEntity authEntity, final Model model) {
model.addAttribute(VERSION, applicationVersion);
model.addAttribute("authEntity", new AuthEntity());
authenticatedStatus = true;
model.addAttribute(AUTHENTICATED, authenticatedStatus);
return "index";
}
This returns correctly an url of gateway localhost:9000/services/ui/do-login but with a /do-login which I do not need.
Maybe I can get rid of /do-login/ part of url? Or maybe there is a solution for the incorrect redirect?
Thanks in advance!
If you use relative path like in return "index"; the result of the POST request sent to http://localhost:9000/services/ui/do-login will include URLs to http://localhost:9000/... unless coded otherwise in the jsp / freemarker / thymeleaf file.
If you want to get rid of the do-login, you would need to implement what's called a Redirect After Post (or redirect after form submit) approach so that a page refresh doesn't resubmit the form. If you take this approach, which seem what you were doing when using: return new RedirectView("index");, I can think of a couple ways of fixing the URL and set it to the proxy host.
1) http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/view/RedirectView.html, there are a couple of constructors that takes a host parameter, you would need to inject the proxy host in the controller class and most-likely in every controller class that implements Redirect After Post.
2) http://tuckey.org/urlrewrite/, include UrlRewriteFilter and configure rules to rewrite from webapp host to proxy host when webapp http status code response is 302. With this approach it would only be once rule and no need to inject proxy host to controller classes or change the return new RedirectView("index");`
3) Maybe this rewriting is implemented in Zuul and you don't need include and configure UrlRewriteFilter as suggested in 2).
As a side note, I have configured Nginx's proxy_pass to a Java webapps (where I implemented Redirect After Post) in the past and I don't recall having this issue. Will have to take a look at both UrlRewriteFilter and Nginx config files to expand on this.
I found that this (thanks to answer in here: Spring redirect url issue when behind Zuul proxy) seems to work as required (but is considered a 'workaround'):
#RequestMapping(value="/do-login", method = RequestMethod.POST)
public void doLogin (#ModelAttribute("authEntity") final AuthEntity authEntity,
final Model model,
HttpServletResponse servletResponse) throws IOException {
...
String rUrl = ServletUriComponentsBuilder.fromCurrentContextPath().path("/").build().toUriString();
servletResponse.sendRedirect(rUrl);
}

What should my url be for JAX-RS API

Pardon for the amateur question, however, I am struggling with testing a java Rest Api Locally.
#Path("/Product") //URL to call
public class ProductSearch {
#Path("/item")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON})
public List<ProductObject> getProjects(Credentials login) throws ConnectionException{
Assuming credentials has username, password, url, itemname, What should the localhost url look like? I get a 404 when I go to http://localhost:8080/productsearchapi/Product/item
I am able to deploy to heroku and test by sending json string but I need to be able to test and debug locally.
You could use postman to test your POST call to the API without deploying to heroku.
Your request in postman would look similar to the following, and under the body tab you would have to create the valid JSON that your path is consuming.
Postman Call
After hitting send with providing a valid JSON you should get the response json returned to you

Cloud Endpoints: Access Paramters in Servlet Filter

I'm trying to build an api with Google Cloud Endpoints.
As Cloud Endpoints does not provide authentication beside Googles own OAuth I try to build my own. Therefore I want to access the parameters provided for the API (for example #Named("token") token) inside a servlet filter.
Unfortunately I cannot find any of the provided information inside the httpRequest. Is that normal? Is there a possibility to access the parameters?
I would appreciate if someone could help me!
UPDATE:
With the infos from jirungaray I tried to build an authentication using headers but ran into the same problem. Used a REST-Client to send some headers as I could not figure out how to do this with the API Explorer. Inside my filter I try to access the token from the headers:
#Override
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader(Constants.AUTH_TOKEN);
...
chain.doFilter(request, response);
}
The reason why I try to do something like this, is that I'm using Guice for Dependency Injection and want my token to be injected inside another object.
With Guice I have the following Provider using the token to inject a FacebookClient (using the token) per request.
#Provides
public FacebookClient getFacebookClientProvider(#Named("fbToken") Provider<String> fbToken) {
return new DefaultFacebookClient(fbToken.get(), Version.VERSION_2_2);
}
As described in the Guice wiki (SevletModule) this uses a sevlet filter to get the information from the request.
Is there any solution to achieve this kind of DI with Cloud Endpoints?
Philip,
Yes, it does makes sense you are getting an empty request. Your endpoint calls are first handled by Google (they receive the API calls) and then those are processed and sent to a handler in your app. As this is all done in the background it's very easy to miss that your endpoints aren't actually getting the same request you sent, they get a completely different request sent from Google's infrastructure.
Even though your approach should work including tokens info in url makes them easier to sniff, even if you use SSL or encrypt your params the token is there in plain sight.
For what you are trying to achieve I recommend you include the token as a header in your request and retrieve that header by accessing the HTTPRequest directly on the endpoint, this is injected automatically if you include an HTTPServletRequest param in you endpoint method.
eg.
public APIResponse doSomething(SomeComplexRquestModel request,
HttpServletRequest rawRequest) {
}
If you still feel you should go with your original approach just comment and I'll help you debug the issue.

Consuming a RESTful WebService passing a JSON object as request body

I've defined a RESTful WebService (by using RESTEasy on JBoss AS 7) that consumes a JSON data stream.
#PUT
#Path("/send")
#Consumes(MediaType.APPLICATION_JSON)
public Response consumeJSON(Student student) {
String output = student.toString();
// Do something...
return Response.status(200).entity(output).build();
}
How can I call my WS from another Spring-based webapp, by properly using the RestTemplate, mapping a Java Object to JSON and passing it as request body?
Note: I'm asking about Spring with the aim to investigate the facilities provided by the framework. I well know that it is possible to do that by defining manually the request body.
Cheers, V.
In the client application, you can create an interface with the same signature as the one you expose on the server side, and the same path.
Then, in the spring configuration file, you can use the RESTeasy client API to generate a proxy connecting to the exposed webservice.
In the client application, it would look like this :
SimpleClient.java
#PUT
#Path("/send")
#Consumes(MediaType.APPLICATION_JSON)
public Response consumeJSON(Student student);
Config.java
#Bean
public SimpleClient getSimpleClient(){
Client client = ClientFactory.newClient();
WebTarget target = client.target("http://example.com/base/uri");
ResteasyWebTarget rtarget = (ResteasyWebTarget)target;
SimpleClient simple = rtarget.proxy(SimpleClient.class);
return simple;
}
Then, in the place where you want to invoke this web service, you inject it with Spring and you can call the method. RESTeasy will search for the webservice matching with with your client (according to the path and the request type) and will create a connection.
Launcher.java
#Resource
private SimpleClient simpleClient;
public void sendMessage(Student student) {
simpleClient.consumeJSON(student);
}
Docs on the RESTesay client API : http://docs.jboss.org/resteasy/docs/3.0.7.Final/userguide/html/RESTEasy_Client_Framework.html
Hope this was helpfull.

Categories

Resources