How do I connect REST services (inside containers) together, in Spring Boot? - java

I'm supposed to build a system with individual REST services using docker compose. One of them is a web app where a user can login, and one of them is an authentication service, so I need to connect to the rest authentication service using a post request, and get the confirmation.
This is my authentication service:
#RestController
public class AuthenticationController {
private final List<User> users=GetUsers();
#PostMapping ("/verify")
public String greeting(#RequestParam String username, #RequestParam String password) {
for (User u :users)
if (u.getUsername().equals(username)&&u.getPassword().equals(password))
return u.getRole();
return "Invalid Credentials ";
}
}
So, how exactly do I connect from inside the web app code into this service and send a post request?
I know I can send a get using this:
String uri = "http://localhost:8080/verify";
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
How would I send a post? And how would it work inside containers? I know I can link them together inside docker compose, but how do I do it on the code level? Do I replace the localhost:8080 with containerName:exposedPort?

As you know, Docker containers are individual Linux virtual machines which means localhost inside a Docker container refers to the container itself, not the host.
Docker compose has a feature called DNS resolutions which basically means you can call other services by their container name or container hash id.
So in your web app, you can call API by containerName:containerPort instead of localhost.
For more information, look at this complete implementation.

Related

Spring RESTful API getting client information

Iv'e been using this guide:
https://spring.io/guides/gs/rest-service
to create a RESTFul web service, my issue I am having is that I do not know how to get information such as the clients IP address, is this possible with this API?
Thanks,
In your Spring Rest Controller you can add HttpServletRequest to get client info.
Example
#GetMapping("/dummyurl")
public Boolean syncWithServNow(HttpServletRequest httpReq, #RequestParam("username") String username) {
System.out.println(httpReq.getRemoteAddr()); // Line 1
}
In most cases it will work. In case like
url is accessed by web server over a proxy server or has a load balancer this will do.
httpReq.getHeader("X-FORWARDED-FOR");

Spring REST API - direct activation of API(No Webserver)

I have a Java application that gets information on a general purpose channel.
I cannot listen on another port, and the application does not have(or implements) a webserver.
I want to activate some of the application's functionalities via REST API.
I already have the requested URI and parameters(of a single client request), but they are not in an HTTPRequest class.
How can I directly call the Spring REST API, using the data I have?
To illustrate what I want to do:
In myREST.java:
class myREST {
#RequestMapping(value = "/foos", method = RequestMethod.GET)
#ResponseBody
public List<Foo> getAllFoos {
return foos;
}
}
and in another file:
JSONObject restAPICaller(String uri, JSONObject params) {
JSONObject response = springRestAPI.call(uri, "GET", params);
return response;
}
where for instance, my uri is /foos/ , and params is {} (will have content for other examples)
How can I directly call the Spring REST API, using the data I have?
You cannot use an API via an HTTP client without an HTTP server.
I guess you can either:
Embed a server in your app and have it listen on some network port (you can bind to 127.0.0.1, so that the service is not accessible from other machines).
Directly call into the REST API classes (eg: new myREST(). getAllFoos())
Call into the business logic layer your API classes call into (iff you properly structured your code there)

How to access endpoints in a controller in Spring?

I have a controller class this way with endpoints. I know that we can access RESTful endpoints in a web application through a tool like 'postman' using the URL. But I am not sure how to access these endpoints. This is not a web application.
This is a java application deployed as a JAR on server using embedded tomcat.
How can I access these endpoints?
#Controller
public class TopicStatsController {
#Autowired
private QueueDepths depths;
#RequestMapping("/topicDepth")
#ResponseBody
public Long topicDepth() throws Exception {
return depths.topicDepth();
}
#RequestMapping("/subscribersDepth")
#ResponseBody
public List<Long> subscribersDepth() throws Exception {
return depths.subscribersDepth();
}
}
You can access the endpoints using RestTemplate.
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl
= "/topicDepth";
ResponseEntity<String> response
= restTemplate.getForEntity(fooResourceUrl + "/1", Long.class);
Your remote must be having an IP address and a port number.
You can use it to hit a GET or POST request.
On localhost - http://localhost:8080/myapp-oracle/api/v1/user
On remote - http://172.16.254.1:8080/myapp-oracle/api/v1/user
Note: You also need to change the http protocol depending upon the server.

I am trying to access Facebook using spring.io social but the isAuthorized() method fails

I am trying to access Facebook using https://spring.io/guides/gs/accessing-facebook/.
I imported the application in Spring Tool Suite using "Import Spring Getting Started Content". I am able to run the application using "gradlew bootRun" and also using "gradlew build".
The problem I encounter is: It seems that in the HelloController class the test
if (!facebook.isAuthorized())
doesn't work. Instead of executing the remaining statements and a return to the "hello" view, the application keeps executing the statement
return "redirect:/connect/facebook"
as if the .isAutorized() method fails.
However, when I open in the same webbrowser www.facebook.com than I get my (logged on) Facebook homepage. The login into Facebook using the application seems to work normally. Please note that I explicitly logout from Facebook before I test the application.
Please note that:
I have registered the application within developer.facebook.com.
I submitted my Facebook AppID and AppSecret into the application.properties file.
I submitted in the Facebook Apps Site URL a hostname.domain using Vitalwerks No-IP. In my router I mapped my public IP address port 80 to the internal IP address of my server
port 8080. I am able to access the application using hostname.domain.
What am I doing wrong? The controller class looks like this:
#Controller
#RequestMapping("/")
public class HelloController {
private Facebook facebook;
#Inject
public HelloController(Facebook facebook) {
this.facebook = facebook;
}
#RequestMapping(method=RequestMethod.GET)
public String helloFacebook(Model model) {
if (!facebook.isAuthorized()) {
return "redirect:/connect/facebook";
}
model.addAttribute(facebook.userOperations().getUserProfile());
PagedList<Post> homeFeed = facebook.feedOperations().getHomeFeed();
model.addAttribute("feed", homeFeed);
return "hello";
}
}
In the Facebook Apps Advanced settings my application was configured as a "Native or desktop app". This resulted in an Error 400 during the OAuth calls.

How can I store information in the context of a web service?

I use a web service which is responsible for user logins. If a login is successful, a token should be generated.
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/login")
public String login(#QueryParam("userName") String name,
#QueryParam("password") String password) {
//Spring Securtity Check
HttpResponse r =loginResponse(name,password);
String s = r.getFirstHeader("Location").toString();
boolean isError = s.contains("login_error");
if(!isError){
//TODO store Token in the application context
MD5 token = new MD5(name+System.currentTimeMillis());
return "token:"+token.getMD5();
}
return "fail";
}
I would like to store the token in the application context, but I don't know how. The token should exist as long as the server application is running. Does the web service have its own application context? Should I use some kind of HTTP servlet to store the information?
store it in memcached, using it you can apply some expiration policy, and also when you have more than one server, it will be an problem to store it in the local memory, store it in global cache like memcached is more apropariate.
I don't quite understand what you call the application context.
Is it ServletContext? You can get it in Jersey using the #Context annotation: #Context ServletContext. You can get is either as a field in your resource, or as a parameter to your method.
The ServletContext is up, while servlet is up. It may be removed by the servlet container depending on its configuration.
Btw. your design is really really bad and insecure. You use GET for login operation and pass both username and password on the url. This means few things:
GET requests can be cached by intermediaries. Do you want it to happen?
Everybody will see password in url. Even if you use SSL, password will be still in url, seen to everyone.
URL is often logged, both by client, servers and intermediaries. You really, really, really don't want the password to be logged.
I'm voting your question up, since it's a great example of a bad design for login.

Categories