Expand my Community achievements bar.

SOLVED

HttpPost to AEM 6.4 Author instance using Assets api through apache http client

Avatar

Level 4

Hello All,

I have a requirement that if an asset is modified in one AEM author instance and if it contains specific metadata, we need to send the asset to another AEM author instance. We don't want to write any code in the target AEM author instance.

 

Our approach was to write a custom java workflow process to be fired on asset modification and use apache http client library to post the asset original rendition to the target AEM instance using assets api (eg http://localhost:4602/api/assets/content/dam/folder/asset.name). Has anyone done this before? Can someone share some code snippet to achieve this? Is there a better approach than this since we are not allowed to deploy any custom code to the target instance?

 

 

	public void sendAssetToTarget(Asset asset) {
		log.info("Send Asset to Target called for asset {}", asset.getName());
		
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
                new UsernamePasswordCredentials("admin", "admin"));
		
		CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credentialsProvider).build();
		CloseableHttpResponse response = null;
		try {
			URI uri = new URIBuilder()
			        .setScheme("http")
			        .setHost("localhost:4602")
			        .setPath("/api/assets/content/dam/target-assets/new/" + asset.getName())
			        .build();
			log.info("The post request URI is {}", uri.toString());
			HttpPost postRequest = new HttpPost(uri);
			postRequest.addHeader("content-type", asset.getMimeType());
			InputStreamEntity entity = new InputStreamEntity(asset.getOriginal().getStream());
			entity.setContentEncoding("binary/octet-stream");
			entity.setChunked(true);
			
			postRequest.setEntity(new BufferedHttpEntity(entity));
			
			response = httpClient.execute(postRequest);
			
			log.info("The post request response is: {}", response.toString() );
			
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			log.error("Error sending asset to Target", e);
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			log.error("Error sending asset to Target", e);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			log.error("Error sending asset to Target", e);
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				log.error("Error sending asset to Target", e);
			}
		}
 	}

 

 

 

The target AEM instance is receiving the post request but it is sending 500 response code and i see following exception in the target instance error.log: 

13.05.2020 20:43:56.052 *INFO* [qtp638789605-3595] org.apache.sling.auth.core.impl.SlingAuthenticator getAnonymousResolver: Anonymous access not allowed by configuration - requesting credentials
13.05.2020 20:43:56.155 *ERROR* [127.0.0.1 [1589417036057] POST /api/assets/content/dam/target-assets/new/asset_6.png HTTP/1.1] com.adobe.granite.rest.impl.servlet.PostRequest Exception during request processing.
java.lang.NullPointerException: null
at com.adobe.granite.rest.assets.impl.AssetResourceProvider.getDataPropertyKey(AssetResourceProvider.java:412) [com.adobe.granite.rest.assets:1.0.56]
at com.adobe.granite.rest.assets.impl.AssetResourceProvider.create(AssetResourceProvider.java:209) [com.adobe.granite.rest.assets:1.0.56]
at com.adobe.granite.rest.impl.ApiEndpointResourceProvider.create(ApiEndpointResourceProvider.java:107) [com.adobe.granite.rest.api:1.1.10]
at org.apache.sling.resourceresolver.impl.legacy.LegacyResourceProviderAdapter.create(LegacyResourceProviderAdapter.java:168) [org.apache.sling.resourceresolver:1.5.34]
at org.apache.sling.resourceresolver.impl.legacy.LegacyResourceProviderFactoryAdapter.create(LegacyResourceProviderFactoryAdapter.java:109) [org.apache.sling.resourceresolver:1.5.34]
 

Any help would be greatly appreciated.

-SKMAEM

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

i was able to replicate your issue in my local. while using Asset HTTP API, you no need to mention /content/dam specifically in the POST URI. and Also please make sure your create all subdirectories before your trigger Asset Creation.

 

In your case use "/api/assets/target-assets/new/" instead of "/api/assets/content/dam/target-assets/new/"

View solution in original post

7 Replies

Avatar

Level 4

Hi Ka,

I did refer to that article and got some ideas about using httpclient to send the assets, but that article does not have any examples regarding how to access those assets api through java. Also in my code I am creating httpclient using admin:admin credentials, does that not work? Do you have any java code snippets to perform the post operation?

 

Thanks,

SKM

Avatar

Community Advisor

OOTB any AEM instance will not allow anonymous post requests. Either it needs CSRF token in header or allow anonymous posts in referrer osgi configuration.

1/ http://localhost:4502/system/console/configMgr
2/ Search for 'Apache Sling Referrer Filter'
3/ Remove POST method from the filter. Then you can call your POST method anywhere

Avatar

Level 4

I have tried everything I can think of. Added CSRF token in the header of the post request after getting it using http://localhost:4602/libs/granite/csrf/token.json using this code:

	HttpPost postRequest = new HttpPost(uri);
	postRequest.addHeader("content-type", asset.getMimeType());
	postRequest.addHeader("X-CSRF-Token", "eyJ ...g");

I have tried to remove POST from the Filter Methods of the "Adobe Granite  CSRF Filter" as well as from the Filter Methods of the "Apache Sling Referrer Filter" configs but no luck. I have also tried checking Allow Empty in the "Apache Sling Referrer Filter" config but still same error.

 

I want to clarify that I am sending this post request to the 6.4 author instance. Anyone can share a java code that works for this scenario?

 

Thanks all for your help!

Avatar

Correct answer by
Community Advisor

i was able to replicate your issue in my local. while using Asset HTTP API, you no need to mention /content/dam specifically in the POST URI. and Also please make sure your create all subdirectories before your trigger Asset Creation.

 

In your case use "/api/assets/target-assets/new/" instead of "/api/assets/content/dam/target-assets/new/"

Avatar

Level 4

Thanks Shashi to pointing to the root cause of the issue. I stumbled upon this link: https://github.com/AdobeDocs/experience-manager-65.en/blob/master/help/assets/assets-api-content-fra... about half an hour ago and saw the same thing that you need to exclude /content/dam from the uri. I was about to update this question and I saw your message.

 

In Assets api documentation, they should mention that omit /content/dam from the uri.

 

Thanks again Shashi for looking into this!!

-SKM