Last active
December 9, 2020 08:09
-
-
Save kimathie/8ac76f828ade4ec066bb99dbe20168ca to your computer and use it in GitHub Desktop.
Web Services Security SOAP message generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.math.BigInteger; | |
import java.security.MessageDigest; | |
import java.security.SecureRandom; | |
import java.time.LocalDateTime; | |
import java.time.ZoneOffset; | |
import java.util.Base64; | |
/** | |
* Web Services Security (WS-Security) enhancement to SOAP messaging to provide | |
* quality of protection through message integrity, message confidentiality, and | |
* single message authentication. | |
* | |
* @author kimathie | |
*/ | |
public abstract class WSSEUtil { | |
private static final SecureRandom RANDOM; | |
/** | |
* SecureRandom object is initialized in this static initialization block to | |
* ensure there's only one instance of the SecureRandom object used in a | |
* multi-threaded environment. | |
* | |
* The static initialization block is only called once and is thread safe. | |
*/ | |
static { | |
RANDOM = new SecureRandom(); | |
} | |
/** | |
* Generates a 64 bit length random number which is then encoded to BASE64. | |
* The nonce is used to provide a unique value for each request sent to a | |
* server to counter against replay attacks. | |
* | |
* @return a String representation of the Base64 encoded nonce. | |
*/ | |
public static String createNonce() { | |
BigInteger integer = new BigInteger(64, RANDOM); | |
return integer.toString(); | |
} | |
/** | |
* Generates a timestamp to indicate the time the request was created. | |
* | |
* @return a String representation of UTC local time. | |
*/ | |
public static String createTimeStamp() { | |
return LocalDateTime.now().toInstant(ZoneOffset.UTC).toString(); | |
} | |
/** | |
* Generates a timestamp to indicate the time after which the request should | |
* be rejected. | |
* | |
* @param expire the minutes to be added to the current time. | |
* @return a String representation of UTC local time. | |
*/ | |
public static String expireTimeStamp(long expire) { | |
return LocalDateTime.now().plusMinutes(expire).toInstant(ZoneOffset.UTC).toString(); | |
} | |
/** | |
* This is a cryptographic hash of the password and timestamp and nonce. | |
* | |
* @param nonce a unique random value. | |
* @param createdTimeStamp indicates the time the request started. | |
* @param password a secret word or phrase used to gain admission | |
* @return a String representation of the hash | |
* @throws Exception | |
*/ | |
public static String createPasswordDigest(String nonce, String createdTimeStamp, String password) throws Exception { | |
MessageDigest digest = MessageDigest.getInstance("SHA-1"); | |
byte[] bytes = digest.digest((nonce + createdTimeStamp + password).getBytes("UTF-8")); | |
return Base64.getEncoder().encodeToString(bytes); | |
} | |
/** | |
* Generates an XML document containing details of the request to be sent to | |
* the server. | |
* | |
* @param userName a name that uniquely identifies an entity on the server. | |
* @param createTimeStamp indicates the time the request started. | |
* @param expireTimeStamp indicates the time the request should be rejected. | |
* @param nonce a unique random value. | |
* @param passwordDigest cryptographic hash of the password and timestamp | |
* and nonce. | |
* @param messageBody message to be included in the XML document request. | |
* @return an XML document request. | |
*/ | |
public static String createXML(String userName, String createTimeStamp, String expireTimeStamp, String nonce, String passwordDigest, String messageBody) { | |
if (userName == null || userName.isEmpty()) { | |
throw new IllegalArgumentException("'userName' cannot be null or empty"); | |
} | |
if (createTimeStamp == null || createTimeStamp.isEmpty()) { | |
throw new IllegalArgumentException("'createTimeStamp' cannot be null or empty"); | |
} | |
if (expireTimeStamp == null || expireTimeStamp.isEmpty()) { | |
throw new IllegalArgumentException("'expireTimeStamp' cannot be null or empty"); | |
} | |
if (nonce == null || nonce.isEmpty()) { | |
throw new IllegalArgumentException("'nonce' cannot be null or empty"); | |
} | |
if (passwordDigest == null || passwordDigest.isEmpty()) { | |
throw new IllegalArgumentException("'passwordDigest' cannot be null or empty"); | |
} | |
if (messageBody == null || messageBody.isEmpty()) { | |
throw new IllegalArgumentException("'messageBody' cannot be null or empty"); | |
} | |
return "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " | |
+ "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " | |
+ "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" " | |
+ "xmlns:main=\"http://main.dataexchange.billpaygw\">" | |
+ "<soapenv:Header>" | |
+ "<wsse:Security >" | |
+ "<wsu:Timestamp >" | |
+ "<wsu:Created>" + createTimeStamp + "</wsu:Created>" | |
+ "<wsu:Expires>" + expireTimeStamp + "</wsu:Expires>" | |
+ "</wsu:Timestamp>" | |
+ "<wsse:UsernameToken>" | |
+ "<wsse:Username>" + userName + "</wsse:Username>" | |
+ "<wsse:Password Type=\"wsse:PasswordDigest\">" + passwordDigest + "</wsse:Password>" | |
+ "<wsse:Nonce>" + Base64.getEncoder().encodeToString(nonce.getBytes()) + "</wsse:Nonce>" | |
+ "<wsu:Created>" + createTimeStamp + "</wsu:Created> " | |
+ "</wsse:UsernameToken>" | |
+ "</wsse:Security>" | |
+ "</soapenv:Header>" | |
+ "<soapenv:Body>" | |
+ messageBody | |
+ "</soapenv:Body>" | |
+ "</soapenv:Envelope>"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment