com.adobe.acs.commons.adobeio.service.impl.IntegrationServiceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of acs-aem-commons-bundle Show documentation
Show all versions of acs-aem-commons-bundle Show documentation
Main ACS AEM Commons OSGi Bundle. Includes commons utilities.
/*
* ACS AEM Commons
*
* Copyright (C) 2013 - 2023 Adobe
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.adobe.acs.commons.adobeio.service.impl;
import static com.adobe.acs.commons.adobeio.service.impl.AdobeioConstants.*;
import static acscommons.io.jsonwebtoken.SignatureAlgorithm.RS256;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.acs.commons.adobeio.service.IntegrationService;
import acscommons.com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import acscommons.io.jsonwebtoken.Jwts;
import acscommons.io.jsonwebtoken.gson.io.GsonSerializer;
import acscommons.io.jsonwebtoken.security.InvalidKeyException;
//scheduler is set to once per hour
//you can use cronmaker.com for generating cron expressions
@Component(service = {IntegrationService.class, Runnable.class},
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = "scheduler.expression=0 0 0/1 1/1 * ? *")
@Designate(ocd = IntegrationConfiguration.class)
public class IntegrationServiceImpl implements IntegrationService, Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IntegrationServiceImpl.class);
private static final Base64.Decoder DECODER = Base64.getMimeDecoder();
@Reference
private AdobeioHelper helper;
private String accessToken = null;
protected IntegrationConfiguration jwtServiceConfig;
@Activate
@Modified
protected void activate(IntegrationConfiguration config) {
this.jwtServiceConfig = config;
}
@Override
public void run() {
// fetch access token from adobe.io
// this method is invoked via the scheduler
accessToken = fetchAccessToken();
LOGGER.info("access token in run()-method {}", accessToken);
}
@Override
public String getAccessToken() {
if (StringUtils.isEmpty(accessToken)) {
accessToken = fetchAccessToken();
}
return accessToken;
}
@Override
public String getApiKey() {
return jwtServiceConfig.clientId();
}
@Override
public int getTimeoutinMilliSeconds() {
return jwtServiceConfig.timeoutInMilliSeocnds();
}
// -------- PRIVATE METHODS ----------
private String fetchAccessToken() {
String token = StringUtils.EMPTY;
try(CloseableHttpClient client = helper.getHttpClient(getTimeoutinMilliSeconds())) {
HttpPost post = new HttpPost(jwtServiceConfig.endpoint());
post.addHeader(CACHE_CONTRL, NO_CACHE);
post.addHeader(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED);
List params = Lists.newArrayList();
params.add(new BasicNameValuePair(CLIENT_ID, jwtServiceConfig.clientId()));
params.add(new BasicNameValuePair(CLIENT_SECRET, jwtServiceConfig.clientSecret()));
params.add(new BasicNameValuePair(JWT_TOKEN, getJwtToken()));
post.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() != 200) {
LOGGER.info("response code {} ", response.getStatusLine().getStatusCode());
}
String result = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
LOGGER.info("JSON Response : {}", result);
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(result).getAsJsonObject();
if (json.has(JSON_ACCESS_TOKEN)) {
token = json.get(JSON_ACCESS_TOKEN).getAsString();
} else {
LOGGER.error("JSON does not contain an access_token");
}
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
LOGGER.info("JWT Access Token : {}", token);
return token;
}
protected String getJwtToken() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
String jwtToken = Jwts
.builder()
.setClaims(getJwtClaims())
.signWith(getPrivateKey(), RS256)
.serializeToJsonWith(new GsonSerializer())
.compact();
LOGGER.info("JWT Token : \n {}", jwtToken);
return jwtToken;
}
private PrivateKey getPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buildPkcs8Key(jwtServiceConfig.privateKey()));
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(keySpec);
}
protected static byte[] buildPkcs8Key(String privateKey) {
if (privateKey.contains("--BEGIN PRIVATE KEY--")) {
return DECODER.decode(privateKey.replaceAll("-----\\w+ PRIVATE KEY-----", ""));
}
if (!privateKey.contains("--BEGIN RSA PRIVATE KEY--")) {
LOGGER.error("Invalid cert format: {}", privateKey);
return StringUtils.EMPTY.getBytes();
}
final byte[] innerKey = DECODER.decode(privateKey.replaceAll("-----\\w+ RSA PRIVATE KEY-----", ""));
final byte[] result = new byte[innerKey.length + 26];
System.arraycopy(DECODER.decode("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKY="), 0, result, 0, 26);
System.arraycopy(BigInteger.valueOf(result.length - 4).toByteArray(), 0, result, 2, 2);
System.arraycopy(BigInteger.valueOf(innerKey.length).toByteArray(), 0, result, 24, 2);
System.arraycopy(innerKey, 0, result, 26, innerKey.length);
return result;
}
private Map getJwtClaims() {
Map jwtClaims = new HashMap<>();
jwtClaims.put("iss", jwtServiceConfig.amcOrgId());
jwtClaims.put("sub", jwtServiceConfig.techAccountId());
jwtClaims.put("exp", getExpirationDate());
jwtClaims.put("aud", String.format("%s%s", jwtServiceConfig.loginEndpoint(), jwtServiceConfig.clientId()));
String [] claims = jwtServiceConfig.adobeLoginClaimKey();
if (claims != null && claims.length > 0) {
for( int i=0; i < claims.length; i++) {
jwtClaims.put(claims[i], Boolean.TRUE);
}
}
if (LOGGER.isDebugEnabled()) {
Gson gson = new Gson();
LOGGER.debug(gson.toJson(jwtClaims));
}
return jwtClaims;
}
private long getExpirationDate() {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.SECOND, jwtServiceConfig.expirationTimeInSeconds());
return cal.getTime().getTime();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy