使用ColdFusion为单点登录数据

我为此帖子的长度提前道歉。 我对这个问题的真正了解还不够充分,以确定具体的问题实际上可能是什么! 但无论如何,我们一直在使用我们的会员API进行调用,以查询有关我们会员的信息(加入日期,会员类型等),使用@Leigh提供的步骤和建议,他们一直在努力! 再次感谢Leigh,我们的成员非常高兴能够做到这一点!

现在,我想为我们的会员设置单一登录,允许他们登录我们的页面,然后将其登录到他们的会员资料中,并已登录该网站。 根据API文档,我需要做的一件事是:

“使用签名证书签署登录人员的Portal用户名。”

我完全停留在这个上面。 我已经在表单中提供了一个XML私钥(由他们的.NET应用程序生成)

<RSAKeyValue><Modulus>{stuff}</Modulus><Exponent>{stuff}</Exponent><P>... etc etc

我收集到我无法直接使用此格式,必须将其转换为PEM格式或类似格式。 使用OpenSSL,我想我已经完成了这个工作,现在有一个格式为“----- BEGIN PRIVATE KEY ----- {stuff} ----- END PRIVATE KEY -----”的文件。

使用Leigh的解决方案确实给了我一个签名,但它与API文档中提供的示例不匹配。 我认为这是因为它使用HmacSHA1,而他们注意到“标题中的签名使用HMAC SHA1,而创建安全令牌的签名使用公钥/私钥对和RSA-SHA1。同样的方法不能用于生成两者。 “ 我试着改变

<cfset key = key.init(jKey,"HmacSHA1") />

<cfset key = key.init(jKey,"RSA-SHA1") />

并得到“算法RSA-SHA1不可用”。

我试图复制和粘贴其他一些建议的解决方案,但都没有工作。 一个例子(从12Robots.com得到):

<!--- Create a Java Cipher object and get a mode --->
<cfset cipher = createObject('java', 'javax.crypto.Cipher').getInstance("RSA") />

<!--- The mode tells the Cipher whether is will be encrypting or decrypting --->
<cfset encMode = cipher.ENCRYPT_MODE />

<cfset encryptedValue = "" /> <!--- Return variable --->

<!--- Initialize the Cipher with the mode and the key --->
<cfset cipher.init(encMode, key) />

<!--- Convert the string to bytes --->
<cfset stringBytes = stringToSign.getBytes("UTF8") />

<!--- Perform encryption --->
<cfset encryptedValue = cipher.doFinal(stringBytes, 0, len(inputString)) />

<cfdump var="#encryptedValue#">

这个实例中的“Key”是我前面提到的PEM文本,“stringToSign”是用户名。 我得到的错误是“无法使用指定方法名称和参数类型的方法,或者init方法被ColdFusion无法可靠解密的参数类型重载,ColdFusion找到了与提供的参数相匹配的0个方法如果这是一个Java对象并验证了该方法存在,请使用Javacast函数来减少歧义。“

我尝试过的另一件事是:

<cfset rsaPrivateKey = toBase64(key, "utf-8")>

<cfset jKey = JavaCast("string", rsaPrivateKey)>
<cfset jMsg = JavaCast("string", stringToSign).getBytes("ASCII")>

<cfset key = createObject("java", "java.security.PrivateKey")>
<cfset keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec")>

<cfset keyFactory = createObject("java", "java.security.KeyFactory")>
<cfset b64dec = createObject("java", "sun.misc.BASE64Decoder")>
<cfset sig = createObject("java", "java.security.Signature")>

<cfset byteClass = createObject("java", "java.lang.Class")>
<cfset byteArray = createObject("java", "java.lang.reflect.Array")>

<cfset byteClass = byteClass.forName(JavaCast("string", "java.lang.Byte"))>
<cfset keyBytes = byteArray.newInstance(byteClass, JavaCast("int", "1024"))>
<cfset keyBytes = b64dec.decodeBuffer(jKey)>

<cfset sig = sig.getInstance("SHA1withRSA", "SunJSSE")>
<cfset sig.initSign(keyFactory.getInstance("RSA").generatePrivate(keySpec.init(keyBytes)))>
<cfset sig.update(jMsg)>
<cfset signBytes = sig.sign()>

<cfset finalSig = ToBase64(signBytes)>

<cfdump var="#finalSig#">

这给了我“java.security.InvalidKeyException:无效的密钥格式。” 顺便说一句,如果我设置rsaPrivateKey只是“键”我得到一个不同的错误,“java.security.InvalidKeyException:IOException:DerInputStream.getLength():lengthTag = 127,太大。” 我很高兴得到不同的错误信息; 至少发生了一些事情! :-)

再次,我不知道这些Java函数在做什么。 我当然不明白为什么看似简单的事情变得如此复杂! 但是我的怀疑是,我不正确地存储私钥PEM,或者不正确地读出数据库(或两者),这就是导致这些不同解决方案失败的原因。 但是,我不确定是否可以肯定地说。

我欢迎任何有助于我的见解或建议! 如果有人需要更多信息,我很乐意提供。 非常感谢您提前!


我收集到我无法直接使用此格式,必须将其转换为PEM格式或类似格式

这样做没有错,但它不是技术上的要求。 关键信息可以从PEM文件或直接从XML加载。

选项1:从XML加载密钥:

将示例XML字符串解析为对象。 然后提取模数和私有指数(即<D>元素)。 使用模数和指数来创建RSAPrivateKeySpec并加载RSA私钥:

xmlKeyString = "<RSAKeyValue><Modulus>........</D></RSAKeyValue>";
xmlDoc = xmlParse(xmlKeyString);
modBytes = binaryDecode(xmlDoc.RSAKeyValue.Modulus.xmlText, "base64");
dBytes = binaryDecode(xmlDoc.RSAKeyValue.D.xmlText, "base64");
modulus = createObject("java","java.math.BigInteger").init(1, modBytes);
exponent = createObject("java","java.math.BigInteger").init(1, dBytes);
keySpec = createObject("java", "java.security.spec.RSAPrivateKeySpec").init(modulus, exponent);
keyFactory = createObject("java", "java.security.KeyFactory").getInstance("RSA");
privateKey = keyFactory.generatePrivate(keySpec);

选项2:从PEM文件加载密钥:

将PEM文件读入一个变量。 删除标题/预告片,即“--- BEGIN / END RSA PRIVATE KEY -----”。 然后解码base64内容并使用KeyFactory加载私钥:

rawKey = replace( pemContent, "-----BEGIN RSA PRIVATE KEY-----", "" );
rawKey = replace( rawKey, "-----END RSA PRIVATE KEY-----", "" );
keyBytes = rawKey.trim().binaryDecode("base64");
keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec");
keyFactory = createObject("java", "java.security.KeyFactory").getInstance("RSA");
privateKey = keyFactory.generatePrivate(keySpec.init(keyBytes));

加载私钥后,可以使用Signature对象执行SHA1哈希并使用RSA密钥生成签名:

stringToSign = "test@membersuite.com";
signer = createObject("java", "java.security.Signature").getInstance("SHA1withRSA");;
signer.initSign(privateKey);
signer.update( stringToSign.getBytes("us-ASCII"));
signedBytes = binaryEncode(signer.sign(), "base64");

writeDump(signedBytes);

结果 (使用示例XML):

jTDKoH+INi19kGWn7WRk/PZegLv/9fPUOluaM57x8y1tkuwxOiyX86gxsZ7gU/OsStIT9Q5SVSG5NoaL3B+AxjuLY8b7XBMfTXHv2vidrDkkTTBW0D2LsrkZ3xzmvvPqqfA3tF2HXUYF+zoiTsr3bQdA32CJ+lDNkf+QjV3ZEoc= 

注意:无论您选择哪种方法,正确保护私钥都非常重要。 一旦你有了样本的工作,一定要阅读如何最好地存储和保护私钥。

链接地址: http://www.djcxy.com/p/37231.html

上一篇: Using ColdFusion to sign data for single sign

下一篇: Why are stdin and stdout seemingly interchangeable?