07-25-2016 12:08 AM
Hi,
I have written a Simple Java REST client using Spring boot framework and tried to access APIs exposed by APIC.
1. I am 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"
Kindly suggest.
Solved! Go to Solution.
07-26-2016 11:39 AM
Customer replied later, and apparently it didn't make it into this thread:
I have added following header to second REST request : header1.add("Cookie", "APIC-Cookie="+apicCookie); And I am getting 200 Ok result and hence my issue has been resolved. Thanks Abhishek |
07-25-2016 12:15 AM
Also, if REST request made by browser clients like POSTMAN required results are observed
07-25-2016 06:24 PM
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 could you send us your Java code so we can have a look, and try it here?
Thanks,
Dave
07-25-2016 08:56 PM
I have created a simple REST Client using Spring boot, when I try 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]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:784) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:771) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174) [spring-boot-1.3.6.RELEASE.jar:1.3.6.RELEASE]
at borderlessodc.api.Application.main(Application.java:135) [main/:na]
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://192.168.1.145/api/aaaLogin.json?gui-token-request=yes": java.security.cert.CertificateException: No subject alternative names present; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:607) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at borderlessodc.api.Application.run(Application.java:200) [main/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spri-1.3.6.RELEASE.jar:1.3.6.RELEASE]
... 6 common frames omitted
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[na:1.8.0_91]
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949) ~[na:1.8.0_91]
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) ~[na:1.8.0_91]
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) ~[na:1.8.0_91]
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509) ~[na:1.8.0_91]
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) ~[na:1.8.0_91]
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) ~[na:1.8.0_91]
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914) ~[na:1.8.0_91]
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) ~[na:1.8.0_91]
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) ~[na:1.8.0_91]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) ~[na:1.8.0_91]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) ~[na:1.8.0_91]
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) ~[na:1.8.0_91]
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) ~[na:1.8.0_91]
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153) ~[na:1.8.0_91]
at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:80) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) ~[spring-web-4.2.7.RELEASE.jar:4.2.7 .RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:596) ~[spring-web-4.2.7.RELEASE.jar:4.2.7.RELEASE]
... 10 common frames omitted
Caused by: java.security.cert.CertificateException: No subject alternative names present
at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:144) ~[na:1.8.0_91]
at sun.security.util.HostnameChecker.match(HostnameChecker.java:93) ~[na:1.8.0_91]
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) ~[na:1.8.0_91]
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) ~[na:1.8.0_91]
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:200) ~[na:1.8.0_91]
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) ~[na:1.8.0_91]
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491) ~[na:1.8.0_91]
... 24 common frames omitted
To overcome above mentioned error I have 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 my first REST call completed with expected response and I am able to extract the urlToken from it which I 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 I am 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"}}}]}
I 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 of this security from APIC web GUI and accordingly later on roll back?
Kindly suggest.
Thanks,
Abhishek
07-26-2016 11:39 AM
Customer replied later, and apparently it didn't make it into this thread:
I have added following header to second REST request : header1.add("Cookie", "APIC-Cookie="+apicCookie); And I am getting 200 Ok result and hence my issue has been resolved. Thanks Abhishek |
05-21-2018 04:45 PM
Does anyone know where this header is added if using Postman?
03-19-2019 08:37 AM
For anyone else having this issue in Postman (which does automatically handle cookies by default), make sure you are using an HTTPS:// URI. If you copied/pasted from API Inspector in the APIC, it uses HTTP which only works from within the interface. Outside requires HTTPS and will give this (above) error if trying with HTTP.
Switch to HTTPS and it should work.
03-07-2020 11:07 AM
Where do I add this code
header1.add("Cookie", "APIC-Cookie="+apicCookie);
in the login request?
03-12-2020 02:52 PM
For all of you who make API calls with Ansible URI module, this is what you need to do:
- name: Login uri: url: "https://<IPADDRESS>/api/aaaLogin.json" method: POST headers: Content-Type: application/json body_format: json body: { "aaaUser":{ "attributes":{ "name": "<USER>", "pwd": "<PASSWORD>" } } } return_content: yes validate_certs: no register: output This will return a token so that you can make any API call without using any password and username, for instance: Getting the local users via API call using the token we just got from the API call above: - name: Create Token set_fact: aci_token: "{{ output['cookies_string'] }}" - uri: url: "https://<IPADDRESS>/api/class/aaaUser.json" method: GET headers: Content-Type: application/json Cookie: "{{ aci_token }}" return_content: yes validate_certs: no register: local_user - debug: var=local_user
Hope it helps !
Regards,
Ernesto Quintana
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide