Single Sign On

Single Sign On is accessed through /sso/Login.aspx page. This page accepts 2 request parameters:

u – username encrypted using TripleDES (with a special algorithm while encrypting – c#code included).

If passing the parameter as a query string as in the example below you might have to URLEncode it (for example using c# - Server.UrlEncode(strEncryptedUsername); ) if passing it through a form and post it should be ok without RLEncode.



d – domain name. Unencrypted domain name. If omitted, default domain will be assumed.

The following is an example of a url:

http://v6dev.webcomcpq.com/sso/Login.aspx?u=daksdhaUpq2nP/5gZw==&d=somedomain

To set up the encryption/decrution same key and init vector have to be used for encryption on client side and for decryption on CPQ side. Two new app parameters have to be added to CPQ. Webcom will have to add these parameters to your domain.

name: SSO_TDES_KEY value: CC0D3f@u17k3Y
name: SSO_TDES_IV value: c0mV3C7

Values can be anything. Above values are examples only.

Single Sign On Using TripleDES Encryption

3rd party will submits a request to SSO page passing username and domain (optional) information as parameters encrypted in TripleDES. WebSouce CPQ will decrypt the parameters and attempt to login that user. Below is shown how the encryption is implementation of the encrypt from CPQ:

C# Example

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
...
public string Key = "anuniquekey"; //This is a key we have to
exchange. Same key has to be used for encrypting and decrypting
public string InitVector = "s0me1V3c7or"; //This is a init vector
we have to exchange. Same key has to be used for encrypting and decrypting
 
public string SymmetricCrypt(SymmetricAlgorithm alg, string msg)
{
            if (msg == null) return "null";
            if (msg == "") return "";
 
            if (String.IsNullOrEmpty(this.Key))
                throw new Exception("Key must not be empty");
            if (String.IsNullOrEmpty(this.InitVector))
                throw new Exception("Init vector must not be empty");
 
            // * 8 cause we are using ASCII
            string longKey = this.Key;
            while ((longKey.Length * 8) < alg.LegalKeySizes[0].MinSize)
                longKey += this.Key;
            longKey = longKey.Substring(0, (alg.LegalKeySizes[0].MinSize / 8));
 
            string longIv = this.InitVector;
            while ((longIv.Length * 8 < alg.LegalBlockSizes[0].MinSize))
                longIv += this.InitVector;
            longIv = longIv.Substring(0, alg.LegalBlockSizes[0].MinSize / 8);
 
            // add some random prefix that will be striped in decrypt to maximize differences in chipers
            Random rnd = new Random((int)DateTime.Now.Ticks);
            msg = rnd.Next(0, 9).ToString() + rnd.Next(0, 9).ToString() + msg;
 
            byte[] key = Encoding.ASCII.GetBytes(longKey);
            byte[] iv = Encoding.ASCII.GetBytes(longIv);
            alg.Mode = CipherMode.CBC;
            alg.Key = key;
            alg.IV = iv;
 
            string result = "";
            ICryptoTransform tra = alg.CreateEncryptor(alg.Key, alg.IV);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, tra, CryptoStreamMode.Write))
                {
                    using (StreamWriter sw = new StreamWriter(cs))
                    {
                        sw.Write(msg);
                    }
                }
                byte[] chip = ms.ToArray();
                result = Convert.ToBase64String(chip);
            }
            return result;   
}


Now to call it:

SymmetricAlgorithm alg = new TripleDESCryptoServiceProvider();
string result = SymmetricCrypt(alg, "MessageToEncrypt");

SymmetricAlgorithm and TripleDESCryptoServiceProvider are part of System.Security.Cryptography

Java Example

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase;
import org.apache.catalina.util.URLEncoder;
 
public class TripleDESforCPQTest extends TestCase {
 
    static final String SSO_TDES_KEY = "CC0D3f@u17k3Y";  
    static final String SSO_TDES_IV = "c0mV3C7";
    static final int KEY_LENGHT = 16;
    static final int IV_LENGTH = 8;
 
    public void testCreateString() throws Exception {
        String enryptedMsg = encrypt("jsmith");
        assertEquals("m7YvzMGQegWOKPl4ExDW3A==", enryptedMsg);
        URLEncoder urlEncoder = new URLEncoder();
        String encodedMsg = urlEncoder.encode(enryptedMsg);
        assertEquals("m7YvzMGQegWOKPl4ExDW3A%3D%3D", encodedMsg);
    }
 
    private String encrypt(String msg) throws Exception {
        StringBuffer keySB = new StringBuffer(SSO_TDES_KEY);
        StringBuffer initialVectorSB = new StringBuffer(SSO_TDES_IV);
 
        while (keySB.length() < KEY_LENGHT)
            keySB.append(SSO_TDES_KEY);
        String key = keySB.substring(0, KEY_LENGHT);
 
        key = key + key.substring(0, 8);  // In Java, we need the key to be 24 bytes long.
 
        while (initialVectorSB.length() < IV_LENGTH)
            initialVectorSB.append(SSO_TDES_IV);
        String initialVector = initialVectorSB.substring(0, IV_LENGTH);
 
        final byte[] keyASCIIBytes = key.getBytes("ASCII");
        final byte[] initialVectorASCIIBytes = initialVector.getBytes("ASCII");
 
        final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE,
                    new SecretKeySpec(keyASCIIBytes, "DESede"),
                    new IvParameterSpec(initialVectorASCIIBytes));
 
        final byte[] cipherText = cipher.doFinal(("11" + msg).getBytes("ASCII")); 
                                    // In the real world, "11" should be replaced with 2 random characters.
        return new sun.misc.BASE64Encoder().encode(cipherText);
    }
 
}
You are here: CallidusCloud SAP CPQ Online HelpUser Side HelpSingle Sign On