Written a Simple Java REST client using Spring boot framework and tried to access APIs exposed by APIC.
1. Able to get proper response from POST request :
POST : https://[apic ip]/api/aaaLogin.json?gui-token-request=yes
payload
{
"aaaUser" : {
"attributes" : {
"name" : "username",
"pwd" : "password"
}
}
}
2. To make subsequent REST request I have used url token provide by above REST response as header with name 'APIC-challenge'
GET : https://[apic-ip]/api/class/topSystem.json
I got following response : Response code : 403
"text":"Need a valid webtoken cookie (named APIC-Cookie) or a signed request with signature in the cookie APIC-Request-Signature for all REST API requests"
If REST request made by browser clients like POSTMAN required results are observed
If it worked in POSTMAN, then it should have worked in Java. From this, it looks like cookies may be blocked in your Java app.
If that's not the case, then the Java code need to be verified.
Created a simple REST Client using Spring boot, when tried to make first POST call to following service :
https://192.168.1.145/api/aaaLogin.json?gui-token-request=yes
Using following implementation :
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
@SpringBootApplication
public class RestApplication implements CommandLineRunner {
String jsonStringUser = "{" + "\"aaaUser\":" + "{" + "\"attributes\":" + "{" + "\"name\":\"user\"" + ","
+ "\"pwd\":\"password\"" + "} } }";
public static void main(String args[]) {
SpringApplication.run(RestApplication.class);
}
@Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
String urlToken = "";
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
List<MediaType> aList = new ArrayList<MediaType>();
aList.add(MediaType.APPLICATION_JSON);
header.setAccept(aList);
HttpEntity<String> entity = new HttpEntity<String>(jsonStringUser, header);
try {
ResponseEntity<String> result = restTemplate.exchange(
"http://192.168.1.145/api/aaaLogin.json?gui-token-request=yes", HttpMethod.POST, entity,
String.class);
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(result.getBody().toString());
while (!parser.isClosed()) {
JsonToken jsonToken = parser.nextToken();
if (JsonToken.VALUE_STRING.equals(jsonToken)) {
String fieldName = (String) parser.getCurrentName();
if (fieldName.equals("urlToken")) {
urlToken = parser.getValueAsString();
System.out.println("Value : " + urlToken);
break;
}
}
}
}
catch (HttpClientErrorException ex) {
System.out.println("Exception is " + ex.getMessage());
System.out.println("Exception is " + ex.getResponseBodyAsString());
System.out.println("Exception is " + ex.getMostSpecificCause());
}
}
}
It failed throwing following exception :
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
<-- Logs Removed--->
... 10 common frames omitted
Caused by: java.security.cert.CertificateException: No subject alternative names present
... 24 common frames omitted
To overcome above mentioned error added this code before the first call to the REST :
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
return hostname.equals("192.168.1.145");
}
});
Then REST call completed with expected response and able to extract the urlToken from it which is again passed to subsequent REST call as "APIC-challenger" header.
RestTemplate restTemplate1 = new RestTemplate();
HttpHeaders header1 = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
List<MediaType> aList1 = new ArrayList<MediaType>();
aList1.add(MediaType.APPLICATION_JSON);
header1.setAccept(aList1);
header1.set("APIC-challenge", urlToken);
HttpEntity<String> entity1 = new HttpEntity<String>(header1);
System.out.println("Second Entity " + entity1);
ResponseEntity<String> result1 = restTemplate1.exchange("https://192.168.1.145/api/class/topSystem.json",
HttpMethod.GET, entity1, String.class);
Now making this subsequent call getting following response :
{"imdata":[{"error":{"attributes":{"code":"403","text":"Need a valid webtoken cookie (named APIC-Cookie) or a signed request with signature in the cookie APIC-Request-Signature for all REST API requests"}}}]}
Also tried passing APIC-Cookie header with the value received from first POST response header but response remains the same.
- Can security imposed by APIC be bypassed i.e. is there any way to turn off the security from APIC web GUI and accordingly later on roll back.
added following header to second REST request :
header1.add("Cookie", "APIC-Cookie="+apicCookie);
And I am got 200 Ok result and hence issue has been resolved.
Comments
0 comments
Please sign in to leave a comment.