This post should be written two years ago...
WMB 7.0 lacks of some basic functionality related to WS-Security - UsernameToken for Consumer scenario. It was probably implemented in next Broker version.Some companies still use this version though.
Two years ago I had to implement WS-Security based on UsernameToken and Signature. Second part was easier as it is supported by Policy Sets.
First part wasn't supported and I had to write it by myself. Below you can find snippets with code chunks.
What is Username Token?
According to oasis-open.org UsernameToken element was introduced to SOAP Security as a way of providing username.syntax:
<wsse:UsernameToken>
<wsse:Username> ... </wsse:Username>
<wsse:Password Type="..."> ... </wsse:Password>
<wsse:Nonce EncodingType="..."> ... </wsse:Nonce>
<wsu:Created> ... </wsu:Created>
</wsse:UsernameToken>
Where:
- Username is plaintext username
- Password is a password or password equivalent - for example of type #Password_Digest - Base64 ( SHA-1 ( nonce + created + password ) )
- Nonce is random value to detect replay attacks encoded with Base64
- Created is datetime of creation time of the request, helps detect replay attacks
You can read more here: http://www.ws-i.org/profiles/basicsecurityprofile-1.0.html#UsernameToken
Implementation
Code below should be pasted to compute module where SOAP envelope is created.
1) Define procedures:
create PROCEDURE encrypt (IN P1 CHARACTER) RETURNS CHARACTER LANGUAGE JAVA EXTERNAL NAME "com.zagwozdka.broker.UsernameTokenUtils.encrypt";
create PROCEDURE getTime () RETURNS CHARACTER LANGUAGE JAVA EXTERNAL NAME "com.zagwozdka.broker.UsernameTokenUtils.getTime";
create PROCEDURE getNonce () RETURNS CHARACTER LANGUAGE JAVA EXTERNAL NAME "com.zagwozdka.broker.UsernameTokenUtils.getNonce";
create PROCEDURE b64Encode(IN source BLOB) RETURNS CHARACTER LANGUAGE JAVA EXTERNAL NAME "com.ibm.broker.javacompute.Base64.encode";
2) Java UsernameTokenUtils class with static methods:
public class UsernameTokenUtils {
public static synchronized String getTime(){
Calendar c = new GregorianCalendar();
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
return s.format(c.getTime());
}
public static synchronized String getNonce(){
Random generator = new Random();
String nonceString = String.valueOf(generator.nextInt(999999999));
return nonceString;
}
public static synchronized String encrypt(String plaintext)
{
MessageDigest md = null;
try
{
md = MessageDigest.getInstance("SHA");
}
catch(NoSuchAlgorithmException e)
{
return null;
}
try
{
md.update(plaintext.getBytes("UTF-8"));
}
catch(UnsupportedEncodingException e)
{
return null;
}
byte raw[] = md.digest();
String hash = (new BASE64Encoder()).encode(raw);
return hash;
}
}
3) declare oasis-open namespaces
DECLARE soapenv NAMESPACE 'http://schemas.xmlsoap.org/soap/envelope/';
DECLARE wsse NAMESPACE 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
DECLARE wsu NAMESPACE 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
4) declare variables, generate time and nonce
DECLARE toEncode BLOB;
DECLARE ctime CHARACTER;
DECLARE nonce CHARACTER;
SET ctime= getTime();
SET nonce = getNonce();
5) prepare soap header with UsernameToken and fill it with proper values
CREATE LASTCHILD OF OutputRoot.SOAP DOMAIN('SOAP') TYPE Name NAME 'Header';
Set OutputRoot.SOAP.Header.wsse:Security.wsse:UsernameToken.wsse:Username = username; -- here is username
Set OutputRoot.SOAP.Header.wsse:Security.wsse:UsernameToken.wsse:Password = encrypt(nonce||ctime||password); -- here is password
Set OutputRoot.SOAP.Header.wsse:Security.wsse:UsernameToken.wsse:Password.(XMLNSC.Attribute)"Type"='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest';
SET toEncode = CAST(nonce as BLOB CCSID 1208);
Set OutputRoot.SOAP.Header.wsse:Security.wsse:UsernameToken.wsse:Nonce = b64Encode(toEncode);
Set OutputRoot.SOAP.Header.wsse:Security.wsse:UsernameToken.wsse:Nonce.(XMLNSC.Attribute)"EncodingType"='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary';
Set OutputRoot.SOAP.Header.wsse:Security.wsse:UsernameToken.wsu:Created=ctime;
Set OutputRoot.SOAP.Header.wsse:Security.(XMLNSC.Attribute)soapenv:mustUnderstand='true';
I hope someone will google this article and find it useful :-)
Very clearly written good article! I am not able to work out the b64Encode method is it a static method defined separately or part of esql execution?
OdpowiedzUsuńsorry for late answer:
Usuńb64Encode is a static method from ibm jar:
create PROCEDURE b64Encode(IN source BLOB) RETURNS CHARACTER LANGUAGE JAVA EXTERNAL NAME "com.ibm.broker.javacompute.Base64.encode";
Yes it is very useful.
OdpowiedzUsuń