spec/saml/saml.cfm
2025-06-02 16:16:51 +03:00

146 lines
4.9 KiB
Plaintext

<!---
https://gist.github.com/guillaumemolter/3e210855881ec5f09294
Reading, decoding and inflating a SAML XML respone with Coldfusion
This script is heavily inspired by the following posts:
- Ciarán Archer : https://flydillonfly.wordpress.com/2011/06/28/using-coldfusion-to-unzip-a-gzip-base64-string/
- Ryan Loda : http://www.coderanch.com/t/545270/java/java/Decode-SAML-Request
- Ben Nadel : http://www.bennadel.com/blog/1343-converting-a-base64-value-back-into-a-string-using-coldfusion.htm
--->
<cffunction
name="inflate"
access="public"
output="false"
returntype="string">
<cfargument name="s" type="string" required="true" />
<!--- We convert the string to binary and a ByteArrayInputStream to be able to read the stream --->
<cfset byteIn = createObject("java", "java.io.ByteArrayInputStream").init(ToBinary(s)) />
<cfset byteClass = CreateObject("Java", "java.lang.Byte").TYPE />
<cfset byteArray = CreateObject("Java", "java.lang.reflect.Array").NewInstance(byteClass, 1024) />
<!--- We init the output object where we are going to inflate our response --->
<cfset byteOut = CreateObject("Java", "java.io.ByteArrayOutputStream").init() />
<!--- We init the zip inflater --->
<cfset inflater = CreateObject("Java", "java.util.zip.Inflater").init(true) />
<!--- We are specifying to the ibnflater what to read --->
<cfset inflaterStream = CreateObject("Java", "java.util.zip.InflaterInputStream").init(byteIn, inflater) />
<!--- We loop through our byte array, inflate the buffer and store it inside of our output buffer --->
<cfset Count = inflaterStream.read(byteArray) />
<cfloop condition="Count neq -1">
<cfset byteOut.write(byteArray, 0, Count) />
<cfset Count = inflaterStream.read(byteArray) />
</cfloop>
<!--- We end/close our inflater --->
<cfset inflater.end() />
<cfset inflaterStream.close() />
<!--- Finally we convert back our bytes stream to a nice string :-) --->
<cfreturn ToString(byteOut.tobyteArray()) />
</cffunction>
<cffunction
name="deflate"
access="public"
output="false"
returntype="string">
<cfargument name="s" type="string" />
<cfscript>
var emptyByteArray = createObject("java", "java.io.ByteArrayOutputStream").init().toByteArray();
var byteClass = emptyByteArray.getClass().getComponentType();
var output = createObject("java","java.lang.reflect.Array").newInstance(byteClass, 500);
var deflater = createObject("java", "java.util.zip.Deflater");
deflater.init(9,true);
deflater.setInput(ARGUMENTS.s.getBytes("UTF-8"));
deflater.finish();
var compressedDataLength = deflater.deflate(output);
return output;
</cfscript>
</cffunction>
<cffunction
name="deflate2base64"
access="public"
output="false"
returntype="string">
<cfargument name="s" type="string" />
<cfscript>
var emptyByteArray = createObject("java", "java.io.ByteArrayOutputStream").init().toByteArray();
var byteClass = emptyByteArray.getClass().getComponentType();
var output = createObject("java","java.lang.reflect.Array").newInstance(byteClass, 500);
var deflater = createObject("java", "java.util.zip.Deflater");
deflater.init(9,true);
deflater.setInput(ARGUMENTS.s.getBytes("UTF-8"));
deflater.finish();
compressedDataLength = deflater.deflate(output);
return toBase64(output, 'UTF-8');
</cfscript>
</cffunction>
<cffunction
name="sign"
access="public"
output="false"
returntype="string">
<cfargument name="s" type="string" />
<cfargument name="pk" type="ANY" />
<cfargument name="algorithm" type="string" default="SHA256withRSA"/>
<cfscript>
var signer = createObject("java", "java.security.Signature").getInstance(ARGUMENTS.algorithm);;
var signer.initSign(ARGUMENTS.pk);
var signer.update(ARGUMENTS.s.getBytes("us-ASCII"));
return signer.sign();
</cfscript>
</cffunction>
<cffunction
name="sign2base64"
access="public"
output="false"
returntype="string">
<cfargument name="s" type="string" />
<cfargument name="pk" type="ANY" />
<cfargument name="algorithm" type="string" default="SHA256withRSA"/>
<cfscript>
var signer = createObject("java", "java.security.Signature").getInstance(ARGUMENTS.algorithm);;
var signer.initSign(ARGUMENTS.pk);
var signer.update(ARGUMENTS.s.getBytes("us-ASCII"));
return binaryEncode(signer.sign(), "base64");
</cfscript>
</cffunction>
<cffunction
name="urlEncodeRfc2396"
output="false"
returntype="string">
<cfargument name="s" type="string" />
<!--- replace back mark (unreserved) characters, otherwise when POSTing to the same URL,
browser changes escaped mark characters to originall characters, and the signature becomes invalid,
because the string signed already is not exactly the same --->
<cfreturn replaceList(urlEncodedFormat(s),"%2D,%5F,%2E,%21,%7E,%2A,%27,%28,%29", "-,_,.,!,~,*,',(,)")/>
</cffunction>