I tried multiple ways to call a get url via RestTemplate in spring boot project to get a json, but every time i got the following 403 error:
<200,{"request":{"mbean":"org.apache.activemq.artemis:address=%22my.queue.demo%22,broker=%22141.110.112.13%22,component=addresses,queue=%22my.queue.demo%22,routing-type=%22anycast%22,subcomponent=queues","attribute":"MessageCount","type":"read"},"error_type":"java.lang.Exception","error":"java.lang.Exception
: Reading attribute MessageCount is forbidden for MBean
org.apache.activemq.artemis:address=%22my.queue.demo%22,broker=%22141.110.112.13%22,component=addresses,queue=%22my.queue.demo%22,routing-type=%22anycast%22,subcomponent=queues","status":403},[Date:"Wed,
12 Jun 2019 12:56:22 GMT", Cache-Control:"no-cache",
Pragma:"no-cache", Access-Control-Allow-Origin:"*",
X-Frame-Options:"SAMEORIGIN", X-XSS-Protection:"1",
Content-Type:"text/plain;charset=utf-8", Expires:"Wed, 12 Jun 2019
11:56:22 GMT", Transfer-Encoding:"chunked"]>
This is the url that i try to call:
http://10.185.148.153:1495/console/jolokia/read/org.apache.activemq.artemis:broker=%22141.110.112.13%22,component=addresses,address=%22my.queue.demo%22,subcomponent=queues,routing-type=%22anycast%22,queue=%22my.queue.demo%22/MessageCount
When i use Postman with basic authentification (user= test, pass =test) it works find but not with Resttemplate.
Here is my config class:
#SpringBootApplication
public class StartWebApplication {
public static void main(String[] args) {
SpringApplication.run(StartWebApplication.class, args);
}
}
#Configuration
class Appconfig{
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
My confroller:
...
#Autowired
private RestTemplate restTemplate;
....
restTemplate.exchange(url, HttpMethod.GET, createHeaders("test", "test"), String.class)
....
HttpEntity createHeaders(String username, String password) {
byte[] token = Base64.getEncoder().encode(
(username + ":" + password).getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + new String(token));
HttpEntity<String> request = new HttpEntity<>(headers);
return request;
}
}
With RestTemplate, you can avoid some of the Base64 boilerplate with:
#Bean
RestTemplate rest() {
RestTemplate rest = new RestTemplate();
rest.getInterceptors().add(new BasicAuthenticationInterceptor("test", "test"));
return rest;
}
Then you can simply do:
rest.getForObject(url, String.class);
Not sure if the problem is something in your Base64-ing of the username and password, but doing this would eliminate that as a possibility.
Can you try:
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
headers.add("Authorization", "Basic " + new String(encodedAuth));
You can try this solution:
1/ Your username/password is incorrect:
Configure J4pClient client using:
J4pClient
.url(JOLOKIA_URL)
.user(USERNAME)
.password(PASSWORD)
.authenticator(new BasicAuthenticator().preemptive())
.build();
pom.xml sample:
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-client-java</artifactId>
<version>${jolokia-client-java.version}</version>
</dependency>
2/ JMS Broker does not allow you to access given attribute or CORS issues:
See here: https://jolokia.org/reference/html/security.html how to configure jolokia. E.g. configure etc/jolokia-access.xml for AcviveMQ Artemis.
Related
I'm making an application filled with various rest services, so I create a one-for-all HTTP class in order to allow a client application to keep asking information, via rest, to a server application
public HttpURLConnection HTTPSENDJSON(String urlAPI,String out,String requestmethod) throws IOException {
URL url = new URL(urlAPI);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestMethod(requestmethod);
conn.setDoOutput(true);
conn.setDoInput(true);
OutputStream os = conn.getOutputStream();
System.out.println(out);
os.write(out.getBytes());
os.flush();
os.close();
return conn;
urlAPI is the desired URL, a string is the JSON string (I'm using GSON) and the requestmethod is a string in order to switch from PUT\POST\GET\PATCH.
So, as I wrote, it's all ok if I need to retrieve information from DB\insert a new record
ATM my Client application makes a call to the server who calls an EJB in order to CRUD the information.
this is the Client method who call the upper method (the HTTPSENDJSON )
public String modifica() throws IOException {
Universal_HTTPREQUEST httprequest = new Universal_HTTPREQUEST();
String url= "http://localhost:8080/ModuloWebClientNuovo/rest/clientela/modifica/account/"+ac.getId()+"";
Gson g = new Gson();
String out=g.toJson(ac, Account.class);
httprequest.HTTPSENDJSON(url, out,"PUT");
and this is the working (at least with POSTMAN) services
#PUT
#Path("modifica/account/{id}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response modificaaccount(#PathParam("id") int id,Account a) {
System.out.println("i'm inside the api and i wrote: "+ a.toString());
ac.updateAccount(a);
return Response.status(200).entity(a).build() ;
}
The Client doesn't even make the call to the server, BUT the only with this specific rest, other works fine.
update account EJB is:
#Stateless
public class AccountEJB implements IAccountCrud {
#EJB
Iconnessioni x;
#Override
public void updateAccount(Account account) {
EntityManager entityManager=x.apriconnessione();
entityManager.merge(account);
x.chiudiconnessione(entityManager);
}
}
Fixed whit a new from scratch wildfly
I am facing problem to write test cases for a rest url which calls another URL through Rest Template.
Please find my code below:-
#RestController
public class ParentController{
#Value("${child.url}")
private String childUrl;
#Autowired
private RestTemplateUtil restTemplateUtil;
#RequestMapping(value = "/parent",method = RequestMethod.POST)
public ResponseEntity<Object> callChildController(#RequestBody InputParam inputParam, HttpServletRequest request) {
return restTemplateUtil.templateService(restTemplateUtil.formURL(request, childUrl), HttpMethod.POST,null,inputParam, Object.class);
}}
}
#Service
public class RestTemplateUtil {
RestTemplate restTemplate = new RestTemplate();
public ResponseEntity<Object> templateService(String url, HttpMethod method, HttpHeaders headers, ...............){
logger.info("Rest template service called..");
response = restTemplate.exchange(url,method,entity,responseType);
return response;
}
public String formURL(HttpServletRequest request, String childUrl){
return "http://" + request.getServerName() + ":" + request.getServerPort() + childUrl;
}
}
JUnit Test case written:-
Mockito.when(restTemplateUtil.templateService(Mockito.anyString(),
Mockito.<HttpMethod> eq(HttpMethod.POST),
Mockito.<HttpHeaders> any(),
Mockito.<HttpEntity<?>> any(),
Mockito.<Class<Object>> any())).thenReturn(mockRespEntity);
this.mvc.perform(post("/parent")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(requestObj)))
.andExpect(status().is2xxSuccessful());
I am a newbie to Mockito, so with my meagre knowledge have build the above test case.
Please advise and correct me if I am wrong.
On executing this, I am getting error:-
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:80/child": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
The portno is wrong here.
Please help.
Thanks.
My RESTful client has this method:
public void testGetCateogrywiseData() {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
client.addFilter(new LoggingFilter(System.out));
WebResource service = client
.resource("http://localhost:8080/MyApp/rest/publicdata");
#SuppressWarnings("rawtypes")
MultivaluedMap queryParams = new MultivaluedMapImpl();
queryParams.add("latitude", "18.522387");
queryParams.add("longitude", "73.878437");
queryParams.add("categoryID", "2");
service.queryParams(queryParams);
ClientResponse response = service.get(ClientResponse.class);
System.out.println(response.getStatus());
System.out.println("Form response " + response.getEntity(String.class));
}
On the server side the method looks like this:
#Path("publicdata")
#GET
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String getPublicData() throws JSONException {
MultivaluedMap<String, String> valueMap = uriInfo.getQueryParameters();
Long latString = Long.parseLong(valueMap.getFirst("latitude"));
Long lonString = Long.parseLong(valueMap.getFirst("longitude"));
Long categoryId = Long.parseLong(valueMap.getFirst("categoryID"));
// Do necessary stuff and return json string
return null;
}
My problem is the valueMap at the server end is always empty. It never gets the three parameters that I have sent from the client code. What am I missing?
The problem happens on this line:
service.queryParams(queryParams);
It successfully adds the query params, but it does not change the original service, it returns a new one to you. To make it work you need to change to this:
service = service.queryParams(queryParams);
There is a good example for sharing HttpSession between Websocket and Rest service. (Spring DispatchServlet cannot find resource within Jetty) But it doesn't work for me. I'm not sure is there any thing I'm missing?
I'm using Jetty as websocket server and also I created a WebApp as well which injected by SpringConfig.
private void init() throws Exception
{
Server server = new Server();
// Create SSL Connector
ServerConnector serverConnector = getSSLConnector(server);
// Bundle to server
server.setConnectors(new Connector[] { serverConnector });
// Create request handler collection
HandlerCollection handlers = new HandlerCollection();
// Add WebSocket handler
final ServletContextHandler servletContextHandler = getWebSocketContextHandler();
handlers.addHandler(servletContextHandler);
// Add Servlet handler
handlers.addHandler(getWebAppServletContextHandler());
server.setHandler(handlers);
// Initial WebSocket
WebSocketServerContainerInitializer.configureContext(servletContextHandler);
// Start Jetty
server.start();
server.join();
}
Both WebSocket and Rest are working under same port perfectly, of course, with different context paths.
Now, I created a Rest service:
#RequestMapping(value = "/login", method = RequestMethod.POST)
#Consumes({ MediaType.APPLICATION_JSON_VALUE })
#Produces({ MediaType.APPLICATION_JSON_VALUE })
public #ResponseBody Message login(#RequestBody Credential credential, #Context HttpServletRequest servlerRequest)
{
...
HttpSession session = servlerRequest.getSession(true);
session.setAttribute("userName", credential.getUserName());
...
Message message = new Message();
...
return message;
}
In this service I created a HttpSession and stored something in. As I said, it works, and so does the session.
Rest client:
public void login() throws KeyManagementException, NoSuchAlgorithmException
{
final String loginServiceUri = HTTP_SERVICE_BASE_URI + "/login";
ClientConfig clientConfig = new DefaultClientConfig();
...
Client client = Client.create(clientConfig);
WebResource webResource = client.resource(loginServiceUri);
ClientResponse response = webResource
.type("application/json")
.post(ClientResponse.class, new Credential("user","pass"));
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
List<NewCookie>cookies = response.getCookies();
ClientEndpointConfigurator.setCookies(cookies); <== Store cookies as well as session to ClientEndpointConfigrator class
Message message = response.getEntity(Message.class);
...
}
ClientEndpointConfigrator class has a static list for all cookies which like this:
public class ClientEndpointConfigurator extends ClientEndpointConfig.Configurator {
private static List<NewCookie> cookies = null;
public static void setCookies(List<NewCookie> cookies) {
ClientEndpointConfigurator.cookies = cookies;
}
...
#Override
public void beforeRequest(Map<String, List<String>> headers) {
...
if(null != cookies)
{
List<String> cookieList = new ArrayList<String>();
for(NewCookie cookie: cookies)
{
cookieList.add(cookie.toString());
}
headers.put("Cookie", cookieList);
}
...
}
}
beforeRequest() method will put all cookies to request header. If you inspect the cookieList, you will see:
[JSESSIONID=tvum36z6j2bc1p9uf2gumxguh;Version=1;Path=/rs;Secure]
Things looks prefect.
Finally, create a server end ServerEndpointConfigurator class, and override the modifyHandshake() method to retrieve the session and cookies
public class SpringServerEndpointConfigurator extends ServerEndpointConfig.Configurator {
#Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
httpSession = (HttpSession)request.getHttpSession(); <== **It returns null here!**
...
}
}
}
I can't get my HttpSession back! and if you print headers out, you will see the cookie has been changed:
Cookie: JSESSIONID="tvum36z6j2bc1p9uf2gumxguh";$Path="/rs"
Any one knows what's the reason?
All right, I figured it out, it's because I put WebSocket and Rest to different context handler. Jetty keeps handlers isolate to each other. To share session information, you have to put them together.
But if someone does want to separate them, it is still possible done by sharing SessionManager or SessionHandler. There are many ways to achieve this, you can inject SessionHandler to each ServletContext or just define it as a static variable and put it on somewhere every one can reach, each way works.
I am trying to create a simple Server / Client application that can send a bean as parameter instead of String but failing below is my code
Server
#Controller
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#RequestMapping(method=RequestMethod.POST,value="/returnGreet")
public #ResponseBody Greeting returnGreet(
#RequestBody(required=false) Greeting greet) {
if(greet == null)
return new Greeting(counter.incrementAndGet(),
String.format(template, greet));
else
return new Greeting(0,"Testing");
}
}
Client
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String,Greeting> greet = new LinkedMultiValueMap<String, Greeting>();
greet.add("greet", new Greeting(0,"XOXO"));
greeting = restTemplate.postForObject("http://localhost:8080/returnGreet",greet, Greeting.class,greet);
System.out.println("Content: " + greeting.getContent());
System.out.println("Id: " + greeting.getId() );
The result is always null for the object greet at the server side.
Any Idea ?
You're not using the RestTemplate correctly. Why are you passing a MultiValueMap as the Entity to be sent? This won't get serialized the way your Server expects.
Just use the Greeting object directly.
restTemplate.postForObject("http://localhost:8080/returnGreet", new Greeting(0, "XOXO"), Greeting.class);
Also, the last argument is not necessary, you don't have any URI variables.