package org.keycloak.models;
import org.jboss.logging.Logger;
import org.keycloak.models.utils.Base32;
import org.keycloak.models.utils.HmacOTP;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* @author Bill Burke
* @version $Revision: 1 $
*/
public class OTPPolicy implements Serializable {
protected static final Logger logger = Logger.getLogger(OTPPolicy.class);
protected String type;
protected String algorithm;
protected int initialCounter;
protected int digits;
protected int lookAheadWindow;
protected int period;
private static final Map algToKeyUriAlg = new HashMap<>();
static {
algToKeyUriAlg.put(HmacOTP.HMAC_SHA1, "SHA1");
algToKeyUriAlg.put(HmacOTP.HMAC_SHA256, "SHA256");
algToKeyUriAlg.put(HmacOTP.HMAC_SHA512, "SHA512");
}
public OTPPolicy() {
}
public OTPPolicy(String type, String algorithm, int initialCounter, int digits, int lookAheadWindow, int period) {
this.type = type;
this.algorithm = algorithm;
this.initialCounter = initialCounter;
this.digits = digits;
this.lookAheadWindow = lookAheadWindow;
this.period = period;
}
public static OTPPolicy DEFAULT_POLICY = new OTPPolicy(UserCredentialModel.TOTP, HmacOTP.HMAC_SHA1, 0, 6, 1, 30);
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAlgorithm() {
return algorithm;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
public int getInitialCounter() {
return initialCounter;
}
public void setInitialCounter(int initialCounter) {
this.initialCounter = initialCounter;
}
public int getDigits() {
return digits;
}
public void setDigits(int digits) {
this.digits = digits;
}
public int getLookAheadWindow() {
return lookAheadWindow;
}
public void setLookAheadWindow(int lookAheadWindow) {
this.lookAheadWindow = lookAheadWindow;
}
public int getPeriod() {
return period;
}
public void setPeriod(int period) {
this.period = period;
}
public String getKeyURI(RealmModel realm, UserModel user, String secret) {
String displayName = realm.getDisplayName();
String uri = null;
if (displayName == null || displayName.isEmpty()) { displayName = realm.getName(); }
uri = "otpauth://" + type + "/" + displayName + ":" + user.getUsername() + "?secret=" +
Base32.encode(secret.getBytes()) + "&digits=" + digits + "&algorithm=" + algToKeyUriAlg.get(algorithm);
try {
uri += "&issuer=" + URLEncoder.encode(realm.getName(), "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.debug("Failed to add issuer parameter to OTP URI becasue UTF-8 is not supported.");
}
if (type.equals(UserCredentialModel.HOTP)) {
uri += "&counter=" + initialCounter;
}
if (type.equals(UserCredentialModel.TOTP)) {
uri += "&period=" + period;
}
return uri;
}
}