package com.uservoice;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Map;
import java.util.TimeZone;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.net.URLCodec;
public class SSO {
private static final DateFormat dateFormat;
static {
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public static String generateToken(String subdomainName, String ssoKey, Map<String, Object> user)
throws Unauthorized {
return generateToken(subdomainName, ssoKey, user, 3600);
}
public static String generateToken(String subdomainName, String ssoKey, Map<String, Object> user, int validForSeconds)
throws Unauthorized {
URLCodec urlCodec = new URLCodec("ASCII");
Base64 base64 = new Base64();
JSONObject jsonObj = new JSONObject();
jsonObj.putAll(user);
if (!jsonObj.has("expires")) {
Calendar expirationTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
expirationTime.setTimeInMillis(expirationTime.getTimeInMillis() + validForSeconds * 1000);
jsonObj.put("expires", dateFormat.format(expirationTime.getTime()));
}
byte[] data = jsonObj.toString().getBytes();
ByteArrayOutputStream out = new ByteArrayOutputStream();
final byte[] INIT_VECTOR = "OpenSSL for Ruby".getBytes();
for (int i = 0; i < 16; i++) {
data[i] ^= INIT_VECTOR[i];
}
ByteArrayInputStream in = new ByteArrayInputStream(data);
try {
byte[] hash = DigestUtils.sha(ssoKey + subdomainName);
byte[] saltedHash = new byte[16];
System.arraycopy(hash, 0, saltedHash, 0, 16);
SecretKeySpec secretKeySpec = new SecretKeySpec(saltedHash, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(INIT_VECTOR);
byte[] buf = new byte[1024];
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
CipherOutputStream cipherOut = new CipherOutputStream(out, cipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
cipherOut.write(buf, 0, numRead);
}
cipherOut.close();
return new String(urlCodec.encode(base64.encode(out.toByteArray())));
} catch (InvalidKeyException e) {
throw new Unauthorized(e.getMessage());
} catch (NoSuchAlgorithmException e) {
throw new Unauthorized(e.getMessage());
} catch (NoSuchPaddingException e) {
throw new Unauthorized(e.getMessage());
} catch (InvalidAlgorithmParameterException e) {
throw new Unauthorized(e.getMessage());
} catch (java.io.IOException e) {
throw new Unauthorized(e.getMessage());
}
}
}