mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
139 lines
4.8 KiB
Java
139 lines
4.8 KiB
Java
package com.duosecurity.duoweb;
|
|
|
|
import java.io.IOException;
|
|
import java.security.InvalidKeyException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
public final class DuoWeb {
|
|
private static final String DUO_PREFIX = "TX";
|
|
private static final String APP_PREFIX = "APP";
|
|
private static final String AUTH_PREFIX = "AUTH";
|
|
|
|
private static final int DUO_EXPIRE = 300;
|
|
private static final int APP_EXPIRE = 3600;
|
|
|
|
private static final int IKEY_LEN = 20;
|
|
private static final int SKEY_LEN = 40;
|
|
private static final int AKEY_LEN = 40;
|
|
|
|
public static final String ERR_USER = "ERR|The username passed to sign_request() is invalid.";
|
|
public static final String ERR_IKEY = "ERR|The Duo integration key passed to sign_request() is invalid.";
|
|
public static final String ERR_SKEY = "ERR|The Duo secret key passed to sign_request() is invalid.";
|
|
public static final String ERR_AKEY = "ERR|The application secret key passed to sign_request() must be at least " + AKEY_LEN + " characters.";
|
|
public static final String ERR_UNKNOWN = "ERR|An unknown error has occurred.";
|
|
|
|
public static String signRequest(final String ikey, final String skey, final String akey, final String username) {
|
|
return signRequest(ikey, skey, akey, username, System.currentTimeMillis() / 1000);
|
|
}
|
|
|
|
public static String signRequest(final String ikey, final String skey, final String akey, final String username, final long time) {
|
|
final String duo_sig;
|
|
final String app_sig;
|
|
|
|
if (username.equals("")) {
|
|
return ERR_USER;
|
|
}
|
|
if (username.indexOf('|') != -1) {
|
|
return ERR_USER;
|
|
}
|
|
if (ikey.equals("") || ikey.length() != IKEY_LEN) {
|
|
return ERR_IKEY;
|
|
}
|
|
if (skey.equals("") || skey.length() != SKEY_LEN) {
|
|
return ERR_SKEY;
|
|
}
|
|
if (akey.equals("") || akey.length() < AKEY_LEN) {
|
|
return ERR_AKEY;
|
|
}
|
|
|
|
try {
|
|
duo_sig = signVals(skey, username, ikey, DUO_PREFIX, DUO_EXPIRE, time);
|
|
app_sig = signVals(akey, username, ikey, APP_PREFIX, APP_EXPIRE, time);
|
|
} catch (Exception e) {
|
|
return ERR_UNKNOWN;
|
|
}
|
|
|
|
return duo_sig + ":" + app_sig;
|
|
}
|
|
|
|
public static String verifyResponse(final String ikey, final String skey, final String akey, final String sig_response)
|
|
throws DuoWebException, NoSuchAlgorithmException, InvalidKeyException, IOException {
|
|
return verifyResponse(ikey, skey, akey, sig_response, System.currentTimeMillis() / 1000);
|
|
}
|
|
|
|
public static String verifyResponse(final String ikey, final String skey, final String akey, final String sig_response, final long time)
|
|
throws DuoWebException, NoSuchAlgorithmException, InvalidKeyException, IOException {
|
|
String auth_user = null;
|
|
String app_user = null;
|
|
|
|
final String[] sigs = sig_response.split(":");
|
|
final String auth_sig = sigs[0];
|
|
final String app_sig = sigs[1];
|
|
|
|
auth_user = parseVals(skey, auth_sig, AUTH_PREFIX, ikey, time);
|
|
app_user = parseVals(akey, app_sig, APP_PREFIX, ikey, time);
|
|
|
|
if (!auth_user.equals(app_user)) {
|
|
throw new DuoWebException("Authentication failed.");
|
|
}
|
|
|
|
return auth_user;
|
|
}
|
|
|
|
private static String signVals(final String key, final String username, final String ikey, final String prefix, final int expire, final long time)
|
|
throws InvalidKeyException, NoSuchAlgorithmException {
|
|
final long expire_ts = time + expire;
|
|
final String exp = Long.toString(expire_ts);
|
|
|
|
final String val = username + "|" + ikey + "|" + exp;
|
|
final String cookie = prefix + "|" + Base64.encodeBytes(val.getBytes());
|
|
final String sig = Util.hmacSign(key, cookie);
|
|
|
|
return cookie + "|" + sig;
|
|
}
|
|
|
|
private static String parseVals(final String key, final String val, final String prefix, final String ikey, final long time)
|
|
throws InvalidKeyException, NoSuchAlgorithmException, IOException, DuoWebException {
|
|
|
|
final String[] parts = val.split("\\|");
|
|
if (parts.length != 3) {
|
|
throw new DuoWebException("Invalid response");
|
|
}
|
|
|
|
final String u_prefix = parts[0];
|
|
final String u_b64 = parts[1];
|
|
final String u_sig = parts[2];
|
|
|
|
final String sig = Util.hmacSign(key, u_prefix + "|" + u_b64);
|
|
if (!Util.hmacSign(key, sig).equals(Util.hmacSign(key, u_sig))) {
|
|
throw new DuoWebException("Invalid response");
|
|
}
|
|
|
|
if (!u_prefix.equals(prefix)) {
|
|
throw new DuoWebException("Invalid response");
|
|
}
|
|
|
|
final byte[] decoded = Base64.decode(u_b64);
|
|
final String cookie = new String(decoded);
|
|
|
|
final String[] cookie_parts = cookie.split("\\|");
|
|
if (cookie_parts.length != 3) {
|
|
throw new DuoWebException("Invalid response");
|
|
}
|
|
final String username = cookie_parts[0];
|
|
final String u_ikey = cookie_parts[1];
|
|
final String expire = cookie_parts[2];
|
|
|
|
if (!u_ikey.equals(ikey)) {
|
|
throw new DuoWebException("Invalid response");
|
|
}
|
|
|
|
final long expire_ts = Long.parseLong(expire);
|
|
if (time >= expire_ts) {
|
|
throw new DuoWebException("Transaction has expired. Please check that the system time is correct.");
|
|
}
|
|
|
|
return username;
|
|
}
|
|
}
|