com.networknt.soap.SoapSecurityTransformAction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soap-security Show documentation
Show all versions of soap-security Show documentation
A yaml rule action implementation to inject a soap security section on the light-gateway to access Cannex API in the request transform interceptor.
package com.networknt.soap;
import com.networknt.rule.IAction;
import com.networknt.rule.RuleActionValue;
import com.networknt.rule.RuleConstants;
import com.networknt.config.Config;
import com.networknt.utility.ModuleRegistry;
import java.nio.charset.StandardCharsets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Transform a soap request to call the external service with a security section with username, password, nonce and
* timestamp. The original request body, username and password will be passed from the yaml rule instead of hardcoded
* in the action class here.
*
* We don't want to introduce some third party XML library to manipulate the request body to inject the security section,
* so only regex replacement is used. It depends on the original request body has a string soap:Header to be matched.
*
* Please be aware that we are dealing with XML content here instead of JSON.
*
* @author Steve Hu
*/
public class SoapSecurityTransformAction implements IAction {
private static final String CONFIG_NAME = "cannex";
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
private static final Logger logger = LoggerFactory.getLogger(SoapSecurityTransformAction.class);
private static final Map config = Config.getInstance().getJsonMapConfigNoCache(CONFIG_NAME);
String pattern = "(.*?) ";
public SoapSecurityTransformAction() {
if(logger.isInfoEnabled()) logger.info("SoapSecurityTransformAction is constructed.");
List masks = new ArrayList<>();
masks.add("password");
ModuleRegistry.registerPlugin(
SoapSecurityTransformAction.class.getPackage().getImplementationTitle(),
SoapSecurityTransformAction.class.getPackage().getImplementationVersion(),
"cannex",
SoapSecurityTransformAction.class.getName(),
Config.getNoneDecryptedInstance().getJsonMapConfigNoCache(CONFIG_NAME),
masks);
}
@Override
public void performAction(Map objMap, Map resultMap, Collection actionValues) {
// get the body from the objMap and create a new body in the resultMap. Both in string format.
resultMap.put(RuleConstants.RESULT, true);
String requestBody = (String)objMap.get("requestBody");
String username = (String)config.get(USERNAME);
String password = (String)config.get(PASSWORD);
if(logger.isTraceEnabled()) logger.debug("username = " + username + " password = " + password + " original request body = " + requestBody);
String modifiedBody = transform(requestBody, username, password);
if(logger.isTraceEnabled()) logger.trace("transformed request body = " + modifiedBody);
resultMap.put("requestBody", modifiedBody);
}
private String transform(String requestBody, String username, String password) {
// the source input is a string of XML, we will replace the header with security with regex.
String output = requestBody.replaceAll(pattern, "" + generateSecurity(username, password) + " ");
return output;
}
private String generateSecurity(String username, String password) {
String nonce = generateNonce();
if(logger.isTraceEnabled()) logger.trace("Nonce = " + nonce);
System.out.println("Nonce = " + nonce);
// created date/time in UTC format
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Date today = Calendar.getInstance().getTime();
String created = dateFormatter.format(today);
if(logger.isTraceEnabled()) logger.trace("Created = " + created);
// generate the password digest from the nonce + created + fixed password
String passwordDigest = createPasswordDigest(nonce, created, password);
if(logger.isTraceEnabled()) logger.trace("Password Digest = " + passwordDigest);
// SOAP header security section.
String security =
" \n"
+ " \n"
+ " %Username% \n"
+ " %PasswordDigest% \n"
+ " %Nonce% \n"
+ " %Created% \n"
+ " \n"
+ " \n";
security = security.replaceAll("%Username%", username);
security = security.replaceAll("%PasswordDigest%", passwordDigest);
security = security.replaceAll("%Nonce%", nonce);
security = security.replaceAll("%Created%", created);
return security;
}
private String createPasswordDigest(String nonce, String created, String password) {
MessageDigest sha1;
String passwordDigest = null;
try {
sha1 = MessageDigest.getInstance("SHA-1");
sha1.update(Base64.getDecoder().decode(nonce));
sha1.update(created.getBytes("UTF-8"));
passwordDigest = new String(Base64.getEncoder().encode(sha1.digest(password.getBytes("UTF-8"))));
sha1.reset();
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
logger.error("Exception: ", e);
}
return passwordDigest;
}
private String generateNonce() {
String dateTimeString = Long.toString(new Date().getTime());
byte[] nonceByte = dateTimeString.getBytes(StandardCharsets.UTF_8);
return Base64.getEncoder().encodeToString(nonceByte);
}
}