format
This commit is contained in:
@@ -5,7 +5,7 @@ import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
|
||||
import org.maxkey.config.ApplicationConfig;
|
||||
import org.maxkey.constants.LOGINTYPE;
|
||||
import org.maxkey.crypto.password.PasswordReciprocal;
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
@@ -37,8 +37,8 @@ public abstract class AbstractAuthenticationProvider {
|
||||
protected AbstractAuthenticationRealm authenticationRealm;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("tfaOTPAuthn")
|
||||
protected AbstractOTPAuthn tfaOptAuthn;
|
||||
@Qualifier("tfaOptAuthn")
|
||||
protected AbstractOptAuthn tfaOptAuthn;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("remeberMeService")
|
||||
|
||||
@@ -3,19 +3,19 @@ package org.maxkey.crypto;
|
||||
import org.apache.commons.codec.binary.Base32;
|
||||
|
||||
public class Base32Utils {
|
||||
|
||||
static Base32 base32=new Base32();
|
||||
|
||||
public static String encode(String simple){
|
||||
return base32.encodeToString(simple.getBytes());
|
||||
}
|
||||
|
||||
public static String encode(byte[] simple){
|
||||
return base32.encodeToString(simple);
|
||||
}
|
||||
|
||||
public static byte[] decode(String cipher){
|
||||
return base32.decode(cipher);
|
||||
}
|
||||
|
||||
|
||||
static Base32 base32 = new Base32();
|
||||
|
||||
public static String encode(String simple) {
|
||||
return base32.encodeToString(simple.getBytes());
|
||||
}
|
||||
|
||||
public static String encode(byte[] simple) {
|
||||
return base32.encodeToString(simple);
|
||||
}
|
||||
|
||||
public static byte[] decode(String cipher) {
|
||||
return base32.decode(cipher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,121 +3,128 @@ package org.maxkey.crypto;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
/**
|
||||
* Base64 Utils
|
||||
* Base64 Utils.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public final class Base64Utils {
|
||||
|
||||
public static String encodeBase64(byte[] simple) {
|
||||
String cipher = BytesUtils.bytes2String(Base64.encodeBase64(simple));
|
||||
return cipher;
|
||||
}
|
||||
public static String encodeBase64(byte[] simple) {
|
||||
String cipher = BytesUtils.bytes2String(Base64.encodeBase64(simple));
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public static byte[] decoderBase64(String cipher) {
|
||||
byte[] simple = Base64.decodeBase64(cipher);
|
||||
return simple;
|
||||
}
|
||||
public static byte[] decoderBase64(String cipher) {
|
||||
byte[] simple = Base64.decodeBase64(cipher);
|
||||
return simple;
|
||||
}
|
||||
|
||||
public static String encode(String simple) {
|
||||
return encodeBase64(simple.getBytes());
|
||||
}
|
||||
public static String encode(String simple) {
|
||||
return encodeBase64(simple.getBytes());
|
||||
}
|
||||
|
||||
public static String encoder(byte[] simple) {
|
||||
return encodeBase64(simple);
|
||||
}
|
||||
public static String encoder(byte[] simple) {
|
||||
return encodeBase64(simple);
|
||||
}
|
||||
|
||||
public static String decode(String cipher) {
|
||||
return BytesUtils.bytes2String(decoderBase64(cipher));
|
||||
}
|
||||
public static String decode(String cipher) {
|
||||
return BytesUtils.bytes2String(decoderBase64(cipher));
|
||||
}
|
||||
|
||||
public static byte[] decoder(String cipher) {
|
||||
return decoderBase64(cipher);
|
||||
}
|
||||
public static byte[] decoder(String cipher) {
|
||||
return decoderBase64(cipher);
|
||||
}
|
||||
|
||||
/**
|
||||
* encode file to base64 Code String
|
||||
*
|
||||
* @param fileName
|
||||
* file path
|
||||
* @return *
|
||||
* @throws Exception
|
||||
*/
|
||||
/**
|
||||
* encode file to base64 Code String.
|
||||
*
|
||||
* @param fileName file path
|
||||
* @return *
|
||||
* @throws Exception e
|
||||
*/
|
||||
|
||||
public static String fileToBase64(String fileName) throws Exception {
|
||||
File file = new File(fileName);
|
||||
FileInputStream inputFile = new FileInputStream(file);
|
||||
byte[] buffer = new byte[(int) file.length()];
|
||||
inputFile.read(buffer);
|
||||
inputFile.close();
|
||||
return encodeBase64(buffer);
|
||||
public static String fileToBase64(String fileName) throws Exception {
|
||||
File file = new File(fileName);
|
||||
FileInputStream inputFile = new FileInputStream(file);
|
||||
byte[] buffer = new byte[(int) file.length()];
|
||||
inputFile.read(buffer);
|
||||
inputFile.close();
|
||||
return encodeBase64(buffer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* base64 Code decode String save to targetPath
|
||||
*
|
||||
* @param base64Code
|
||||
* @param targetPath
|
||||
* @throws Exception
|
||||
*/
|
||||
/**
|
||||
* base64 Code decode String save to targetPath.
|
||||
*
|
||||
* @param base64Code String
|
||||
* @param targetPath String
|
||||
* @throws Exception e
|
||||
*/
|
||||
|
||||
public static void decodeBase64ToFile(String base64Code, String targetPath)
|
||||
throws Exception {
|
||||
byte[] buffer = decoderBase64(base64Code);
|
||||
FileOutputStream out = new FileOutputStream(targetPath);
|
||||
out.write(buffer);
|
||||
out.close();
|
||||
public static void decodeBase64ToFile(String base64Code, String targetPath) throws Exception {
|
||||
byte[] buffer = decoderBase64(base64Code);
|
||||
FileOutputStream out = new FileOutputStream(targetPath);
|
||||
out.write(buffer);
|
||||
out.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* base64 code save to file
|
||||
*
|
||||
* @param base64Code
|
||||
* @param targetPath
|
||||
* @throws Exception
|
||||
*/
|
||||
/**
|
||||
* base64 code save to file.
|
||||
*
|
||||
* @param base64Code String
|
||||
* @param targetPath String
|
||||
* @throws Exception e
|
||||
*/
|
||||
|
||||
public static void base64ToFile(String base64Code, String targetPath)
|
||||
throws Exception {
|
||||
byte[] buffer = base64Code.getBytes();
|
||||
FileOutputStream out = new FileOutputStream(targetPath);
|
||||
out.write(buffer);
|
||||
out.close();
|
||||
}
|
||||
public static void base64ToFile(String base64Code, String targetPath) throws Exception {
|
||||
byte[] buffer = base64Code.getBytes();
|
||||
FileOutputStream out = new FileOutputStream(targetPath);
|
||||
out.write(buffer);
|
||||
out.close();
|
||||
}
|
||||
|
||||
public static String base64UrlEncode(byte[] simple) {
|
||||
String s = new String(Base64.encodeBase64(simple)); // Regular base64
|
||||
// encoder
|
||||
s = s.split("=")[0]; // Remove any trailing '='s
|
||||
s = s.replace('+', '-'); // 62nd char of encoding
|
||||
s = s.replace('/', '_'); // 63rd char of encoding
|
||||
return s;
|
||||
}
|
||||
/**
|
||||
* base64UrlEncode.
|
||||
* @param simple byte
|
||||
* @return
|
||||
*/
|
||||
public static String base64UrlEncode(byte[] simple) {
|
||||
// Regular base64
|
||||
String s = new String(Base64.encodeBase64(simple));
|
||||
// encoder
|
||||
s = s.split("=")[0]; // Remove any trailing '='s
|
||||
s = s.replace('+', '-'); // 62nd char of encoding
|
||||
s = s.replace('/', '_'); // 63rd char of encoding
|
||||
return s;
|
||||
}
|
||||
|
||||
public static byte[] base64UrlDecode(String cipher) {
|
||||
String s = cipher;
|
||||
s = s.replace('-', '+'); // 62nd char of encoding
|
||||
s = s.replace('_', '/'); // 63rd char of encoding
|
||||
switch (s.length() % 4) { // Pad with trailing '='s
|
||||
case 0:
|
||||
break; // No pad chars in this case
|
||||
case 2:
|
||||
s += "==";
|
||||
break; // Two pad chars
|
||||
case 3:
|
||||
s += "=";
|
||||
break; // One pad char
|
||||
default:
|
||||
System.err.println("Illegal base64url String!");
|
||||
}
|
||||
return Base64.decodeBase64(s); // Standard base64 decoder
|
||||
}
|
||||
/**
|
||||
* base64UrlDecode.
|
||||
* @param cipher String
|
||||
* @return
|
||||
*/
|
||||
public static byte[] base64UrlDecode(String cipher) {
|
||||
String s = cipher;
|
||||
s = s.replace('-', '+'); // 62nd char of encoding
|
||||
s = s.replace('_', '/'); // 63rd char of encoding
|
||||
switch (s.length() % 4) { // Pad with trailing '='s
|
||||
case 0 :
|
||||
break; // No pad chars in this case
|
||||
case 2 :
|
||||
s += "==";
|
||||
break; // Two pad chars
|
||||
case 3 :
|
||||
s += "=";
|
||||
break; // One pad char
|
||||
default:
|
||||
System.err.println("Illegal base64url String!");
|
||||
}
|
||||
return Base64.decodeBase64(s); // Standard base64 decoder
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,51 +3,70 @@ package org.maxkey.crypto.password;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* PasswordGen.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PasswordGen {
|
||||
|
||||
public static String CHAR_LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
|
||||
public static String CHAR_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
public static String CHAR_NUMBERS = "0123456789";
|
||||
public static String CHAR_SPECIAL = "~@#^()[]*$-+?_&=!%{}/";
|
||||
public static String CHAR_DEFAULT = CHAR_LOWERCASE + CHAR_NUMBERS + CHAR_UPPERCASE;
|
||||
private Random random = new Random();
|
||||
public static int DEFAULT_LENGTH = 8;
|
||||
|
||||
public PasswordGen() {
|
||||
|
||||
}
|
||||
|
||||
public String gen() {
|
||||
return gen(DEFAULT_LENGTH);
|
||||
}
|
||||
|
||||
public String gen(int length) {
|
||||
return gen(CHAR_DEFAULT,length);
|
||||
public static String CHAR_LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
|
||||
public static String CHAR_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
public static String CHAR_NUMBERS = "0123456789";
|
||||
public static String CHAR_SPECIAL = "~@#^()[]*$-+?_&=!%{}/";
|
||||
public static String CHAR_DEFAULT = CHAR_LOWERCASE + CHAR_NUMBERS + CHAR_UPPERCASE;
|
||||
private Random random = new Random();
|
||||
public static int DEFAULT_LENGTH = 8;
|
||||
|
||||
public PasswordGen() {
|
||||
|
||||
}
|
||||
|
||||
public String gen(int lowerCase,int upperCase,int numbers,int special) {
|
||||
StringBuffer password=new StringBuffer("");
|
||||
password.append(gen(CHAR_LOWERCASE,lowerCase));
|
||||
password.append(gen(CHAR_NUMBERS,numbers));
|
||||
password.append(gen(CHAR_UPPERCASE,upperCase));
|
||||
password.append(gen(CHAR_SPECIAL,special));
|
||||
return gen(password.toString(),password.length());//random generator String by sequence password
|
||||
}
|
||||
|
||||
public String gen(final String charString, int length) {
|
||||
if (length < 1) {return "";}
|
||||
|
||||
public String gen() {
|
||||
return gen(DEFAULT_LENGTH);
|
||||
}
|
||||
|
||||
public String gen(int length) {
|
||||
return gen(CHAR_DEFAULT, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* gen .
|
||||
* @param lowerCase int
|
||||
* @param upperCase int
|
||||
* @param numbers int
|
||||
* @param special int
|
||||
* @return
|
||||
*/
|
||||
public String gen(int lowerCase, int upperCase, int numbers, int special) {
|
||||
StringBuffer password = new StringBuffer("");
|
||||
password.append(gen(CHAR_LOWERCASE, lowerCase));
|
||||
password.append(gen(CHAR_NUMBERS, numbers));
|
||||
password.append(gen(CHAR_UPPERCASE, upperCase));
|
||||
password.append(gen(CHAR_SPECIAL, special));
|
||||
// random generator String by sequence password
|
||||
return gen(password.toString(), password.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* gen.
|
||||
* @param charString String
|
||||
* @param length int
|
||||
* @return
|
||||
*/
|
||||
public String gen(final String charString, int length) {
|
||||
if (length < 1) {
|
||||
return "";
|
||||
}
|
||||
int i = 0;
|
||||
StringBuffer password=new StringBuffer("");
|
||||
while(i < length) {
|
||||
int randomPosition = random.nextInt(charString.length());
|
||||
if(password.indexOf(charString.charAt(randomPosition)+"")<0){//duplicate check
|
||||
password.append(charString.charAt(randomPosition));
|
||||
i++;
|
||||
}
|
||||
StringBuffer password = new StringBuffer("");
|
||||
while (i < length) {
|
||||
int randomPosition = random.nextInt(charString.length());
|
||||
// duplicate check
|
||||
if (password.indexOf(charString.charAt(randomPosition) + "") < 0) {
|
||||
password.append(charString.charAt(randomPosition));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return password.toString();
|
||||
}
|
||||
|
||||
@@ -1,49 +1,48 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.maxkey.crypto.password;
|
||||
|
||||
import org.maxkey.crypto.ReciprocalUtils;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* PasswordReciprocal.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class PasswordReciprocal implements PasswordEncoder{
|
||||
public class PasswordReciprocal implements PasswordEncoder {
|
||||
|
||||
public static PasswordReciprocal passwordReciprocal;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public PasswordReciprocal() {
|
||||
|
||||
}
|
||||
public static PasswordReciprocal passwordReciprocal;
|
||||
|
||||
public static PasswordReciprocal getInstance(){
|
||||
|
||||
if(passwordReciprocal==null){
|
||||
passwordReciprocal=new PasswordReciprocal();
|
||||
}
|
||||
|
||||
return passwordReciprocal;
|
||||
}
|
||||
|
||||
public String rawPassword(String username,String password) {
|
||||
return password+"@"+username;
|
||||
}
|
||||
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return ReciprocalUtils.encode(rawPassword.toString());
|
||||
}
|
||||
public PasswordReciprocal() {
|
||||
|
||||
}
|
||||
|
||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||
return ReciprocalUtils.encode(rawPassword.toString()).equals(encodedPassword);
|
||||
}
|
||||
|
||||
public String decoder(CharSequence encodedPassword) {
|
||||
return ReciprocalUtils.decoder(encodedPassword.toString());
|
||||
}
|
||||
/**
|
||||
* getInstance.
|
||||
* @return
|
||||
*/
|
||||
public static PasswordReciprocal getInstance() {
|
||||
|
||||
if (passwordReciprocal == null) {
|
||||
passwordReciprocal = new PasswordReciprocal();
|
||||
}
|
||||
|
||||
return passwordReciprocal;
|
||||
}
|
||||
|
||||
public String rawPassword(String username, String password) {
|
||||
return password + "@" + username;
|
||||
}
|
||||
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return ReciprocalUtils.encode(rawPassword.toString());
|
||||
}
|
||||
|
||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||
return ReciprocalUtils.encode(rawPassword.toString()).equals(encodedPassword);
|
||||
}
|
||||
|
||||
public String decoder(CharSequence encodedPassword) {
|
||||
return ReciprocalUtils.decoder(encodedPassword.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.maxkey.constants.STATUS;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.util.StringGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
public abstract class AbstractOTPAuthn {
|
||||
private final static Logger logger = LoggerFactory.getLogger(AbstractOTPAuthn.class);
|
||||
|
||||
protected int interval = 30;
|
||||
|
||||
protected int digits = 6;
|
||||
|
||||
protected String crypto = "HmacSHA1";
|
||||
|
||||
StringGenerator stringGenerator;
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public static class OPT_TYPES{
|
||||
//手机
|
||||
public static int MOBILE = 2;
|
||||
//短信
|
||||
public static int SMS = 3;
|
||||
//邮箱
|
||||
public static int EMAIL = 4;
|
||||
|
||||
public static int TIMEBASED_OPT = 5;
|
||||
|
||||
public static int COUNTERBASED_OPT = 6;
|
||||
|
||||
public static int HOTP_OPT = 7;
|
||||
|
||||
public static int RSA_OPT = 8;
|
||||
|
||||
}
|
||||
|
||||
private static final String DEFAULT_DEFAULT_INSERT_STATEMENT = "INSERT INTO ONE_TIME_PASSWORD(ID ,OPTTYPE,USERNAME,TOKEN,RECEIVER,CREATETIME,STATUS) VALUES(?,?,?,?,?,?,"+STATUS.ACTIVE+")";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_SELECT_STATEMENT = "SELECT ID ,OPTTYPE,USERNAME,TOKEN,RECEIVER,CREATETIME FROM ONE_TIME_PASSWORD WHERE STATUS ="+STATUS.ACTIVE+" AND USERNAME = ? AND TOKEN = ? AND OPTTYPE = ?";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_DELETE_STATEMENT = "UPDATE ONE_TIME_PASSWORD SET STATUS ="+STATUS.DELETE+" WHERE USERNAME = ? AND TOKEN = ? AND OPTTYPE = ?";
|
||||
|
||||
abstract public boolean produce(UserInfo userInfo);
|
||||
|
||||
abstract public boolean validate(UserInfo userInfo,String token);
|
||||
|
||||
protected String defaultProduce(UserInfo userInfo){
|
||||
return genToken(userInfo);
|
||||
}
|
||||
|
||||
public String genToken(UserInfo userInfo){
|
||||
if(stringGenerator==null){
|
||||
stringGenerator=new StringGenerator(StringGenerator.DEFAULT_CODE_NUMBER,digits);
|
||||
}
|
||||
return stringGenerator.randomGenerate();
|
||||
}
|
||||
|
||||
|
||||
public AbstractOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
protected void insertDataBase(UserInfo userInfo,String token,String receiver,int type){
|
||||
jdbcTemplate.update(DEFAULT_DEFAULT_INSERT_STATEMENT,
|
||||
new Object[] {
|
||||
java.util.UUID.randomUUID(),
|
||||
type,
|
||||
userInfo.getUsername(),
|
||||
token,
|
||||
receiver,
|
||||
new Date()
|
||||
},
|
||||
new int[] {Types.VARCHAR,Types.INTEGER,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR, Types.TIMESTAMP}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean validateDataBase(UserInfo userInfo,String token,int type){
|
||||
OneTimePassword oneTimePassword=jdbcTemplate.queryForObject(
|
||||
DEFAULT_DEFAULT_SELECT_STATEMENT,
|
||||
new OneTimePasswordRowMapper(),
|
||||
userInfo.getUsername(),
|
||||
token,
|
||||
type);
|
||||
|
||||
if(oneTimePassword!=null){
|
||||
|
||||
jdbcTemplate.update(DEFAULT_DEFAULT_DELETE_STATEMENT,
|
||||
new Object[] {
|
||||
userInfo.getUsername(),
|
||||
token,
|
||||
type},
|
||||
new int[] {Types.VARCHAR,Types.VARCHAR, Types.INTEGER}
|
||||
);
|
||||
DateTime currentdateTime = new DateTime();
|
||||
DateTime oneTimePwdData=DateTime.parse(oneTimePassword.getCreateTime(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
Duration duration = new Duration(oneTimePwdData, currentdateTime);
|
||||
int intDuration=Integer.parseInt(duration.getStandardSeconds()+"");
|
||||
logger.debug("validate duration "+intDuration);
|
||||
logger.debug("validate result "+(intDuration<=interval));
|
||||
if(intDuration<=interval){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the interval
|
||||
*/
|
||||
public int getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param interval the interval to set
|
||||
*/
|
||||
public void setInterval(int interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the digits
|
||||
*/
|
||||
public int getDigits() {
|
||||
return digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param digits the digits to set
|
||||
*/
|
||||
public void setDigits(int digits) {
|
||||
this.digits = digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the crypto
|
||||
*/
|
||||
public String getCrypto() {
|
||||
return crypto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param crypto the crypto to set
|
||||
*/
|
||||
public void setCrypto(String crypto) {
|
||||
this.crypto = crypto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class OneTimePasswordRowMapper implements RowMapper<OneTimePassword> {
|
||||
|
||||
public OneTimePassword mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
OneTimePassword oneTimePassword=new OneTimePassword();
|
||||
oneTimePassword.setId(rs.getString("ID"));
|
||||
oneTimePassword.setType(rs.getInt("OPTTYPE"));
|
||||
oneTimePassword.setUsername(rs.getString("USERNAME"));
|
||||
oneTimePassword.setToken(rs.getString("TOKEN"));
|
||||
oneTimePassword.setUsername(rs.getString("USERNAME"));
|
||||
oneTimePassword.setReceiver(rs.getString("RECEIVER"));
|
||||
oneTimePassword.setCreateTime(rs.getString("CREATETIME"));
|
||||
return oneTimePassword;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package org.maxkey.crypto.password.opt;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Date;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.maxkey.constants.STATUS;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.util.StringGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* AbstractOTPAuthn.
|
||||
* @author Administrator
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractOptAuthn {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractOptAuthn.class);
|
||||
|
||||
protected int interval = 30;
|
||||
|
||||
protected int digits = 6;
|
||||
|
||||
protected String crypto = "HmacSHA1";
|
||||
|
||||
StringGenerator stringGenerator;
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public static final class OPT_TYPES {
|
||||
// 手机
|
||||
public static int MOBILE = 2;
|
||||
// 短信
|
||||
public static int SMS = 3;
|
||||
// 邮箱
|
||||
public static int EMAIL = 4;
|
||||
|
||||
public static int TIMEBASED_OPT = 5;
|
||||
|
||||
public static int COUNTERBASED_OPT = 6;
|
||||
|
||||
public static int HOTP_OPT = 7;
|
||||
|
||||
public static int RSA_OPT = 8;
|
||||
|
||||
}
|
||||
|
||||
private static final String DEFAULT_DEFAULT_INSERT_STATEMENT =
|
||||
"INSERT INTO ONE_TIME_PASSWORD(ID ,OPTTYPE,USERNAME,TOKEN,RECEIVER,CREATETIME,STATUS)"
|
||||
+ " VALUES(?,?,?,?,?,?," + STATUS.ACTIVE + ")";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_SELECT_STATEMENT =
|
||||
"SELECT ID ,OPTTYPE,USERNAME,TOKEN,RECEIVER,CREATETIME FROM ONE_TIME_PASSWORD"
|
||||
+ " WHERE STATUS =" + STATUS.ACTIVE
|
||||
+ " AND USERNAME = ? AND TOKEN = ? AND OPTTYPE = ?";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_DELETE_STATEMENT =
|
||||
"UPDATE ONE_TIME_PASSWORD SET STATUS ="
|
||||
+ STATUS.DELETE + " WHERE USERNAME = ? AND TOKEN = ? AND OPTTYPE = ?";
|
||||
|
||||
public abstract boolean produce(UserInfo userInfo);
|
||||
|
||||
public abstract boolean validate(UserInfo userInfo, String token);
|
||||
|
||||
protected String defaultProduce(UserInfo userInfo) {
|
||||
return genToken(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* genToken.
|
||||
* @param userInfo UserInfo
|
||||
* @return
|
||||
*/
|
||||
public String genToken(UserInfo userInfo) {
|
||||
if (stringGenerator == null) {
|
||||
stringGenerator = new StringGenerator(StringGenerator.DEFAULT_CODE_NUMBER, digits);
|
||||
}
|
||||
return stringGenerator.randomGenerate();
|
||||
}
|
||||
|
||||
public AbstractOptAuthn(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
protected void insertDataBase(UserInfo userInfo, String token, String receiver, int type) {
|
||||
jdbcTemplate.update(DEFAULT_DEFAULT_INSERT_STATEMENT,
|
||||
new Object[] {
|
||||
java.util.UUID.randomUUID(),
|
||||
type,
|
||||
userInfo.getUsername(),
|
||||
token,
|
||||
receiver,
|
||||
new Date()
|
||||
},
|
||||
new int[] { Types.VARCHAR, Types.INTEGER,
|
||||
Types.VARCHAR, Types.VARCHAR,
|
||||
Types.VARCHAR,Types.TIMESTAMP
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* validateDataBase.
|
||||
* @param userInfo UserInfo
|
||||
* @param token String
|
||||
* @param type int
|
||||
* @return
|
||||
*/
|
||||
public boolean validateDataBase(UserInfo userInfo, String token, int type) {
|
||||
OneTimePassword oneTimePassword = jdbcTemplate.queryForObject(
|
||||
DEFAULT_DEFAULT_SELECT_STATEMENT,
|
||||
new OneTimePasswordRowMapper(), userInfo.getUsername(), token, type);
|
||||
|
||||
if (oneTimePassword != null) {
|
||||
|
||||
jdbcTemplate.update(
|
||||
DEFAULT_DEFAULT_DELETE_STATEMENT,
|
||||
new Object[] { userInfo.getUsername(), token, type },
|
||||
new int[] { Types.VARCHAR, Types.VARCHAR, Types.INTEGER }
|
||||
);
|
||||
DateTime currentdateTime = new DateTime();
|
||||
DateTime oneTimePwdData = DateTime.parse(oneTimePassword.getCreateTime(),
|
||||
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
Duration duration = new Duration(oneTimePwdData, currentdateTime);
|
||||
int intDuration = Integer.parseInt(duration.getStandardSeconds() + "");
|
||||
logger.debug("validate duration " + intDuration);
|
||||
logger.debug("validate result " + (intDuration <= interval));
|
||||
if (intDuration <= interval) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* the interval.
|
||||
* @return the interval
|
||||
*/
|
||||
public int getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* interval the interval to set.
|
||||
* @param interval the interval to set
|
||||
*/
|
||||
public void setInterval(int interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* digits.
|
||||
* @return the digits
|
||||
*/
|
||||
public int getDigits() {
|
||||
return digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* digits the digits to set.
|
||||
* @param digits the digits to set
|
||||
*/
|
||||
public void setDigits(int digits) {
|
||||
this.digits = digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto.
|
||||
* @return the crypto
|
||||
*/
|
||||
public String getCrypto() {
|
||||
return crypto;
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto the crypto to set.
|
||||
* @param crypto the crypto to set
|
||||
*/
|
||||
public void setCrypto(String crypto) {
|
||||
this.crypto = crypto;
|
||||
}
|
||||
|
||||
public class OneTimePasswordRowMapper implements RowMapper<OneTimePassword> {
|
||||
|
||||
/**
|
||||
*ResultSet.
|
||||
*/
|
||||
public OneTimePassword mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
OneTimePassword oneTimePassword = new OneTimePassword();
|
||||
oneTimePassword.setId(rs.getString("ID"));
|
||||
oneTimePassword.setType(rs.getInt("OPTTYPE"));
|
||||
oneTimePassword.setUsername(rs.getString("USERNAME"));
|
||||
oneTimePassword.setToken(rs.getString("TOKEN"));
|
||||
oneTimePassword.setUsername(rs.getString("USERNAME"));
|
||||
oneTimePassword.setReceiver(rs.getString("RECEIVER"));
|
||||
oneTimePassword.setCreateTime(rs.getString("CREATETIME"));
|
||||
return oneTimePassword;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +1,69 @@
|
||||
package org.maxkey.crypto.password.opt;
|
||||
|
||||
public class OneTimePassword {
|
||||
private String id;
|
||||
private int type;
|
||||
private String token;
|
||||
private String username;
|
||||
private String receiver;
|
||||
private String createTime;
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return the token
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
/**
|
||||
* @param token the token to set
|
||||
*/
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
/**
|
||||
* @return the username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
/**
|
||||
* @param username the username to set
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
/**
|
||||
* @return the receiver
|
||||
*/
|
||||
public String getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
/**
|
||||
* @param receiver the receiver to set
|
||||
*/
|
||||
public void setReceiver(String receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
/**
|
||||
* @return the createTime
|
||||
*/
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
/**
|
||||
* @param createTime the createTime to set
|
||||
*/
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public OneTimePassword() {
|
||||
private String id;
|
||||
private int type;
|
||||
private String token;
|
||||
private String username;
|
||||
private String receiver;
|
||||
private String createTime;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public void setReceiver(String receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("OneTimePassword [id=").append(id)
|
||||
.append(", type=").append(type).append(", token=").append(token)
|
||||
.append(", username=").append(username).append(", receiver=").append(receiver)
|
||||
.append(", createTime=").append(createTime).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
/**
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OneTimePassword [id=" + id + ", token=" + token + ", username="
|
||||
+ username + ", receiver=" + receiver + ", createTime="
|
||||
+ createTime + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +1,35 @@
|
||||
package org.maxkey.crypto.password.opt.algorithm;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* IETF RFC 4226 http://tools.ietf.org/html/rfc4226
|
||||
* HOTP Include HmacOTP's implement
|
||||
* same as HmacOTP's, when addChecksum = false & truncationOffset = -1
|
||||
* IETF RFC 4226 http://tools.ietf.org/html/rfc4226 HOTP Include HmacOTP's
|
||||
* implement same as HmacOTP's, when addChecksum = false & truncationOffset = -1
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class HOTP {
|
||||
// These are used to calculate the check-sum digits.
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// These are used to calculate the check-sum digits.
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
private static final int[] doubleDigits = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 };
|
||||
|
||||
/**
|
||||
* Calculates the checksum using the credit card algorithm.
|
||||
* This algorithm has the advantage that it detects any single
|
||||
* mistyped digit and any single transposition of
|
||||
* adjacent digits.
|
||||
* Calculates the checksum using the credit card algorithm. This algorithm has
|
||||
* the advantage that it detects any single mistyped digit and any single
|
||||
* transposition of adjacent digits.
|
||||
*
|
||||
* @param num the number to calculate the checksum for
|
||||
* @param num the number to calculate the checksum for
|
||||
* @param digits number of significant places in the number
|
||||
*
|
||||
* @return the checksum of num
|
||||
*/
|
||||
public static int calcChecksum(long num, int digits) {
|
||||
boolean doubleDigit = true;
|
||||
int total = 0;
|
||||
int total = 0;
|
||||
while (0 < digits--) {
|
||||
int digit = (int) (num % 10);
|
||||
num /= 10;
|
||||
@@ -48,124 +47,107 @@ public class HOTP {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method uses the JCE to provide the HMAC-SHA-1
|
||||
* * algorithm.
|
||||
* HMAC computes a Hashed Message Authentication Code and
|
||||
* in this case SHA1 is the hash algorithm used.
|
||||
*
|
||||
* @param keyBytes the bytes to use for the HMAC-SHA-1 key
|
||||
* @param text the message or text to be authenticated.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException if no provider makes
|
||||
* either HmacSHA1 or HMAC-SHA-1
|
||||
* digest algorithms available.
|
||||
* @throws InvalidKeyException
|
||||
* The secret provided was not a valid HMAC-SHA-1 key.
|
||||
*
|
||||
*/
|
||||
* This method uses the JCE to provide the HMAC-SHA-1 * algorithm. HMAC computes
|
||||
* a Hashed Message Authentication Code and in this case SHA1 is the hash
|
||||
* algorithm used.
|
||||
*
|
||||
* @param keyBytes the bytes to use for the HMAC-SHA-1 key
|
||||
* @param text the message or text to be authenticated.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException if no provider makes either HmacSHA1 or
|
||||
* HMAC-SHA-1 digest algorithms available.
|
||||
* @throws InvalidKeyException The secret provided was not a valid
|
||||
* HMAC-SHA-1 key.
|
||||
*
|
||||
*/
|
||||
|
||||
public static byte[] hmac_sha1(byte[] keyBytes, byte[] text)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException
|
||||
{
|
||||
// try {
|
||||
Mac hmacSha1;
|
||||
try {
|
||||
hmacSha1 = Mac.getInstance("HmacSHA1");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
hmacSha1 = Mac.getInstance("HMAC-SHA-1");
|
||||
}
|
||||
SecretKeySpec macKey =
|
||||
new SecretKeySpec(keyBytes, "RAW");
|
||||
hmacSha1.init(macKey);
|
||||
return hmacSha1.doFinal(text);
|
||||
// } catch (GeneralSecurityException gse) {
|
||||
// throw new UndeclaredThrowableException(gse);
|
||||
// }
|
||||
}
|
||||
public static byte[] hmac_sha1(byte[]
|
||||
keyBytes, byte[] text) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
// try {
|
||||
Mac hmacSha1;
|
||||
try {
|
||||
hmacSha1 = Mac.getInstance("HmacSHA1");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
hmacSha1 = Mac.getInstance("HMAC-SHA-1");
|
||||
}
|
||||
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
|
||||
hmacSha1.init(macKey);
|
||||
return hmacSha1.doFinal(text);
|
||||
// } catch (GeneralSecurityException gse) {
|
||||
// throw new UndeclaredThrowableException(gse);
|
||||
// }
|
||||
}
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
private static final int[] DIGITS_POWER
|
||||
= { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
|
||||
|
||||
private static final int[] DIGITS_POWER
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
= {1,10,100,1000,10000,100000,1000000,10000000,100000000};
|
||||
/**
|
||||
* This method generates an OTP value for the given set of parameters.
|
||||
*
|
||||
* @param secret the shared secret
|
||||
* @param movingFactor the counter, time, or other value that changes on a
|
||||
* per use basis.
|
||||
* @param codeDigits the number of digits in the OTP, not including the
|
||||
* checksum, if any.
|
||||
* @param addChecksum a flag that indicates if a checksum digit
|
||||
*
|
||||
*
|
||||
*
|
||||
* M'Raihi, et al. Informational [Page 29]
|
||||
*
|
||||
* RFC 4226 HOTP Algorithm December 2005
|
||||
*
|
||||
*
|
||||
* should be appended to the OTP.
|
||||
* @param truncationOffset the offset into the MAC result to begin truncation.
|
||||
* If this value is out of the range of 0 ... 15, then
|
||||
* dynamic truncation will be used. Dynamic truncation
|
||||
* is when the last 4 bits of the last byte of the MAC
|
||||
* are used to determine the start offset.
|
||||
* @return A numeric String in base 10 that includes {@link codeDigits} digits
|
||||
* @throws NoSuchAlgorithmException if no provider makes either HmacSHA1 or
|
||||
* HMAC-SHA-1 digest algorithms available.
|
||||
* @throws InvalidKeyException The secret provided was not a valid
|
||||
* HMAC-SHA-1 key.
|
||||
*
|
||||
* plus the optional checksum digit if requested.
|
||||
*/
|
||||
public static String generateOTP(byte[]
|
||||
secret, long movingFactor, int codeDigits, boolean addChecksum,
|
||||
int truncationOffset) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
// put movingFactor value into text byte array
|
||||
String result = null;
|
||||
final int digits = addChecksum ? (codeDigits + 1) : codeDigits;
|
||||
|
||||
/**
|
||||
* This method generates an OTP value for the given
|
||||
* set of parameters.
|
||||
*
|
||||
* @param secret the shared secret
|
||||
* @param movingFactor the counter, time, or other value that
|
||||
* changes on a per use basis.
|
||||
* @param codeDigits the number of digits in the OTP, not
|
||||
* including the checksum, if any.
|
||||
* @param addChecksum a flag that indicates if a checksum digit
|
||||
byte[] text = new byte[8];
|
||||
for (int i = text.length - 1; i >= 0; i--) {
|
||||
text[i] = (byte) (movingFactor & 0xff);
|
||||
movingFactor >>= 8;
|
||||
}
|
||||
|
||||
// compute hmac hash
|
||||
byte[] hash = hmac_sha1(secret, text);
|
||||
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
|
||||
M'Raihi, et al. Informational [Page 29]
|
||||
|
||||
RFC 4226 HOTP Algorithm December 2005
|
||||
if ((0 <= truncationOffset) && (truncationOffset < (hash.length - 4))) {
|
||||
offset = truncationOffset;
|
||||
}
|
||||
|
||||
int binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16)
|
||||
| ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
|
||||
|
||||
* should be appended to the OTP.
|
||||
* @param truncationOffset the offset into the MAC result to
|
||||
* begin truncation. If this value is out of
|
||||
* the range of 0 ... 15, then dynamic
|
||||
* truncation will be used.
|
||||
* Dynamic truncation is when the last 4
|
||||
* bits of the last byte of the MAC are
|
||||
* used to determine the start offset.
|
||||
* @throws NoSuchAlgorithmException if no provider makes
|
||||
* either HmacSHA1 or HMAC-SHA-1
|
||||
* digest algorithms available.
|
||||
* @throws InvalidKeyException
|
||||
* The secret provided was not
|
||||
* a valid HMAC-SHA-1 key.
|
||||
*
|
||||
* @return A numeric String in base 10 that includes
|
||||
* {@link codeDigits} digits plus the optional checksum
|
||||
* digit if requested.
|
||||
*/
|
||||
static public String generateOTP(byte[] secret,
|
||||
long movingFactor,
|
||||
int codeDigits,
|
||||
boolean addChecksum,
|
||||
int truncationOffset)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException{
|
||||
// put movingFactor value into text byte array
|
||||
String result = null;
|
||||
int digits = addChecksum ? (codeDigits + 1) : codeDigits;
|
||||
|
||||
byte[] text = new byte[8];
|
||||
for (int i = text.length - 1; i >= 0; i--) {
|
||||
text[i] = (byte) (movingFactor & 0xff);
|
||||
movingFactor >>= 8;
|
||||
}
|
||||
int otp = binary % DIGITS_POWER[codeDigits];
|
||||
if (addChecksum) {
|
||||
otp = (otp * 10) + calcChecksum(otp, codeDigits);
|
||||
}
|
||||
result = Integer.toString(otp);
|
||||
while (result.length() < digits) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// compute hmac hash
|
||||
byte[] hash = hmac_sha1(secret, text);
|
||||
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
|
||||
if ( (0<=truncationOffset) &&
|
||||
(truncationOffset<(hash.length-4)) ) {
|
||||
offset = truncationOffset;
|
||||
}
|
||||
|
||||
int binary =
|
||||
((hash[offset] & 0x7f) << 24)
|
||||
| ((hash[offset + 1] & 0xff) << 16)
|
||||
| ((hash[offset + 2] & 0xff) << 8)
|
||||
| (hash[offset + 3] & 0xff);
|
||||
|
||||
int otp = binary % DIGITS_POWER[codeDigits];
|
||||
if (addChecksum) {
|
||||
otp = (otp * 10) + calcChecksum(otp, codeDigits);
|
||||
}
|
||||
result = Integer.toString(otp);
|
||||
while (result.length() < digits) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,80 +1,98 @@
|
||||
package org.maxkey.crypto.password.opt.algorithm;
|
||||
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* same as HOTP,but addChecksum = false & truncationOffset = -1
|
||||
* same as HOTP,but addChecksum = false & truncationOffset = -1.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class HmacOTP {
|
||||
private final static Logger logger = LoggerFactory.getLogger(HmacOTP.class);
|
||||
|
||||
public static String gen(byte[] seed, int count, int digits){
|
||||
try{
|
||||
return generateOTP(seed, count, digits);
|
||||
} catch (InvalidKeyException e){
|
||||
e.printStackTrace();
|
||||
LoggerFactory.getLogger(HmacOTP.class).error(e.getMessage());
|
||||
} catch (NoSuchAlgorithmException e){
|
||||
e.printStackTrace();
|
||||
LoggerFactory.getLogger(HmacOTP.class).error(e.getMessage());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private static final Logger logger = LoggerFactory.getLogger(HmacOTP.class);
|
||||
|
||||
public static byte[] hmac_sha1(byte[] keyBytes, byte[] text)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException{
|
||||
Mac hmacSha1;
|
||||
try {
|
||||
hmacSha1 = Mac.getInstance("HmacSHA1");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
hmacSha1 = Mac.getInstance("HMAC-SHA-1");
|
||||
}
|
||||
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
|
||||
hmacSha1.init(macKey);
|
||||
return hmacSha1.doFinal(text);
|
||||
}
|
||||
/**
|
||||
* gen.
|
||||
* @param seed byte
|
||||
* @param count int
|
||||
* @param digits int
|
||||
* @return
|
||||
*/
|
||||
public static String gen(byte[] seed, int count, int digits) {
|
||||
try {
|
||||
return generateOTP(seed, count, digits);
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
LoggerFactory.getLogger(HmacOTP.class).error(e.getMessage());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
LoggerFactory.getLogger(HmacOTP.class).error(e.getMessage());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static private String generateOTP(byte[] secret, long movingFactor,
|
||||
int codeDigits) throws NoSuchAlgorithmException,
|
||||
InvalidKeyException{
|
||||
// put movingFactor value into text byte array
|
||||
String result = null;
|
||||
byte[] text = new byte[8];
|
||||
|
||||
for (int i = text.length - 1; i >= 0; i--){
|
||||
text[i] = (byte) (movingFactor & 0xff);
|
||||
movingFactor >>= 8;
|
||||
}
|
||||
/**
|
||||
* @param keyBytes
|
||||
* @param text
|
||||
* @return
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws InvalidKeyException
|
||||
*/
|
||||
public static byte[] hmac_sha1(byte[] keyBytes, byte[] text)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
Mac hmacSha1;
|
||||
try {
|
||||
hmacSha1 = Mac.getInstance("HmacSHA1");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
hmacSha1 = Mac.getInstance("HMAC-SHA-1");
|
||||
}
|
||||
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
|
||||
hmacSha1.init(macKey);
|
||||
return hmacSha1.doFinal(text);
|
||||
}
|
||||
|
||||
// compute hmac hash
|
||||
byte[] hash = hmac_sha1(secret, text);
|
||||
/**
|
||||
* @param secret
|
||||
* @param movingFactor
|
||||
* @param codeDigits
|
||||
* @return
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws InvalidKeyException
|
||||
*/
|
||||
static private String generateOTP(byte[] secret,
|
||||
long movingFactor, int codeDigits)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
// put movingFactor value into text byte array
|
||||
String result = null;
|
||||
byte[] text = new byte[8];
|
||||
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
|
||||
int binary = ((hash[offset] & 0x7f) << 24)
|
||||
| ((hash[offset + 1] & 0xff) << 16)
|
||||
| ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
|
||||
for (int i = text.length - 1; i >= 0; i--) {
|
||||
text[i] = (byte) (movingFactor & 0xff);
|
||||
movingFactor >>= 8;
|
||||
}
|
||||
|
||||
// compute hmac hash
|
||||
byte[] hash = hmac_sha1(secret, text);
|
||||
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
|
||||
int binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16)
|
||||
| ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
|
||||
|
||||
int otp = (int) (binary % Math.pow(10, codeDigits));
|
||||
// int otp = binary % DIGITS_POWER[codeDigits];
|
||||
result = Integer.toString(otp);
|
||||
|
||||
while (result.length() < codeDigits) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int otp = (int) (binary % Math.pow(10, codeDigits));
|
||||
//int otp = binary % DIGITS_POWER[codeDigits];
|
||||
result = Integer.toString(otp);
|
||||
|
||||
while (result.length() < codeDigits){
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,214 +1,205 @@
|
||||
package org.maxkey.crypto.password.opt.algorithm;
|
||||
|
||||
public class KeyUriFormat {
|
||||
|
||||
public class Types{
|
||||
public static final String HOTP = "hotp";
|
||||
public static final String TOTP = "totp";
|
||||
|
||||
}
|
||||
|
||||
String crypto = "HmacSHA1";
|
||||
String type;
|
||||
String secret;
|
||||
String issuer;
|
||||
String domain;
|
||||
int digits = 6;
|
||||
//just for hotp
|
||||
Long counter = 0L;
|
||||
//just for totp
|
||||
int period = 30;
|
||||
|
||||
String account;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public KeyUriFormat() {
|
||||
public class Types {
|
||||
public static final String HOTP = "hotp";
|
||||
public static final String TOTP = "totp";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param secret
|
||||
*/
|
||||
public KeyUriFormat(String type, String secret) {
|
||||
this.type = type;
|
||||
this.secret = secret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String crypto = "HmacSHA1";
|
||||
String type;
|
||||
String secret;
|
||||
String issuer;
|
||||
String domain;
|
||||
int digits = 6;
|
||||
// just for hotp
|
||||
Long counter = 0L;
|
||||
// just for totp
|
||||
int period = 30;
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param secret
|
||||
* @param issuer
|
||||
*/
|
||||
public KeyUriFormat(String type, String secret, String issuer) {
|
||||
this.type = type;
|
||||
this.secret = secret;
|
||||
this.issuer = issuer;
|
||||
}
|
||||
String account;
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public KeyUriFormat() {
|
||||
|
||||
/**
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the secret
|
||||
*/
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
/**
|
||||
* @param type
|
||||
* @param secret
|
||||
*/
|
||||
public KeyUriFormat(String type, String secret) {
|
||||
this.type = type;
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param secret the secret to set
|
||||
*/
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
/**
|
||||
* @param type
|
||||
* @param secret
|
||||
* @param issuer
|
||||
*/
|
||||
public KeyUriFormat(String type, String secret, String issuer) {
|
||||
this.type = type;
|
||||
this.secret = secret;
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the issuer
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param issuer the issuer to set
|
||||
*/
|
||||
public void setIssuer(String issuer) {
|
||||
this.issuer = issuer;
|
||||
}
|
||||
/**
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the digits
|
||||
*/
|
||||
public int getDigits() {
|
||||
return digits;
|
||||
}
|
||||
/**
|
||||
* @return the secret
|
||||
*/
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param digits the digits to set
|
||||
*/
|
||||
public void setDigits(int digits) {
|
||||
this.digits = digits;
|
||||
}
|
||||
/**
|
||||
* @param secret the secret to set
|
||||
*/
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the counter
|
||||
*/
|
||||
public Long getCounter() {
|
||||
return counter;
|
||||
}
|
||||
/**
|
||||
* @return the issuer
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param counter the counter to set
|
||||
*/
|
||||
public void setCounter(Long counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
/**
|
||||
* @param issuer the issuer to set
|
||||
*/
|
||||
public void setIssuer(String issuer) {
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the period
|
||||
*/
|
||||
public int getPeriod() {
|
||||
return period;
|
||||
}
|
||||
/**
|
||||
* @return the digits
|
||||
*/
|
||||
public int getDigits() {
|
||||
return digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param period the period to set
|
||||
*/
|
||||
public void setPeriod(int period) {
|
||||
this.period = period;
|
||||
}
|
||||
/**
|
||||
* @param digits the digits to set
|
||||
*/
|
||||
public void setDigits(int digits) {
|
||||
this.digits = digits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the account
|
||||
*/
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
/**
|
||||
* @return the counter
|
||||
*/
|
||||
public Long getCounter() {
|
||||
return counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account the account to set
|
||||
*/
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the crypto
|
||||
*/
|
||||
public String getCrypto() {
|
||||
return crypto;
|
||||
}
|
||||
/**
|
||||
* @param counter the counter to set
|
||||
*/
|
||||
public void setCounter(Long counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the period
|
||||
*/
|
||||
public int getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param period the period to set
|
||||
*/
|
||||
public void setPeriod(int period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param crypto the crypto to set
|
||||
*/
|
||||
public void setCrypto(String crypto) {
|
||||
this.crypto = crypto;
|
||||
}
|
||||
/**
|
||||
* @return the account
|
||||
*/
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account the account to set
|
||||
*/
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the crypto
|
||||
*/
|
||||
public String getCrypto() {
|
||||
return crypto;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
/**
|
||||
* @param crypto the crypto to set
|
||||
*/
|
||||
public void setCrypto(String crypto) {
|
||||
this.crypto = crypto;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
public String format() {
|
||||
return format(this.account);
|
||||
}
|
||||
|
||||
/**
|
||||
* format account.
|
||||
* @param account String
|
||||
* @return
|
||||
*/
|
||||
public String format(String account) {
|
||||
StringBuffer uri = new StringBuffer("otpauth://");
|
||||
uri.append(type).append("/");
|
||||
if (null != this.domain) {
|
||||
uri.append(this.domain).append("/").append(account);
|
||||
} else {
|
||||
uri.append(account);
|
||||
}
|
||||
uri.append("?secret=").append(secret);
|
||||
|
||||
if (null != issuer) {
|
||||
uri.append("&issuer=").append(issuer);
|
||||
}
|
||||
if (digits != 6) {
|
||||
uri.append("&digits=").append(digits);
|
||||
}
|
||||
|
||||
if (type.equalsIgnoreCase(Types.TOTP) && period != 30) {
|
||||
uri.append("&period=").append(period);
|
||||
}
|
||||
|
||||
if (type.equalsIgnoreCase(Types.HOTP)) {
|
||||
uri.append("&counter=").append(counter);
|
||||
}
|
||||
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
public String format(){
|
||||
return format(this.account);
|
||||
}
|
||||
|
||||
public String format(String account){
|
||||
StringBuffer uri=new StringBuffer("otpauth://");
|
||||
uri.append(type).append("/");
|
||||
if(null!=this.domain){
|
||||
uri.append(this.domain).append("/").append(account);
|
||||
}else{
|
||||
uri.append(account);
|
||||
}
|
||||
uri.append("?secret=").append(secret);
|
||||
|
||||
if(null!=issuer){
|
||||
uri.append("&issuer=").append(issuer);
|
||||
}
|
||||
if(digits!=6){
|
||||
uri.append("&digits=").append(digits);
|
||||
}
|
||||
|
||||
if(type.equalsIgnoreCase(Types.TOTP)&&period!=30){
|
||||
uri.append("&period=").append(period);
|
||||
}
|
||||
|
||||
if(type.equalsIgnoreCase(Types.HOTP)){
|
||||
uri.append("&counter=").append(counter);
|
||||
}
|
||||
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.algorithm;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
public class OTPSecret {
|
||||
|
||||
private static final Random rand = new Random();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Seed for HMAC-SHA1 - 20 bytes
|
||||
* Generates random 20 bytes long TOTP Secret
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate() {
|
||||
int size = 20;
|
||||
byte[] b = new byte[size];
|
||||
rand.nextBytes(b);
|
||||
return Arrays.copyOf(b, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed by crypto
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate(String crypto) {
|
||||
if(crypto.equalsIgnoreCase("HmacSHA1")||crypto.equalsIgnoreCase("HMAC-SHA-1")){
|
||||
return generate();
|
||||
}if(crypto.equalsIgnoreCase("HmacSHA256")||crypto.equalsIgnoreCase("HMAC-SHA-256")){
|
||||
return generate32();
|
||||
}if(crypto.equalsIgnoreCase("HmacSHA512")||crypto.equalsIgnoreCase("HMAC-SHA-512")){
|
||||
return generate64();
|
||||
}
|
||||
return generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed for HMAC-SHA256 - 32 bytes
|
||||
* Generates random 32 bytes long TOTP Secret
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate32() {
|
||||
int size = 32;
|
||||
byte[] b = new byte[size];
|
||||
rand.nextBytes(b);
|
||||
return Arrays.copyOf(b, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed forHMAC-SHA512 - 64 bytes
|
||||
* Generates random 64 bytes long TOTP Secret
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate64() {
|
||||
int size = 64;
|
||||
byte[] b = new byte[size];
|
||||
rand.nextBytes(b);
|
||||
return Arrays.copyOf(b, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.maxkey.crypto.password.opt.algorithm;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
public class OtpSecret {
|
||||
|
||||
private static final Random rand = new Random();
|
||||
|
||||
/**
|
||||
* Seed for HMAC-SHA1 - 20 bytes Generates random 20 bytes long TOTP Secret.
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate() {
|
||||
int size = 20;
|
||||
byte[] b = new byte[size];
|
||||
rand.nextBytes(b);
|
||||
return Arrays.copyOf(b, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed by crypto.
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate(String crypto) {
|
||||
if (crypto.equalsIgnoreCase("HmacSHA1") || crypto.equalsIgnoreCase("HMAC-SHA-1")) {
|
||||
return generate();
|
||||
}
|
||||
if (crypto.equalsIgnoreCase("HmacSHA256") || crypto.equalsIgnoreCase("HMAC-SHA-256")) {
|
||||
return generate32();
|
||||
}
|
||||
if (crypto.equalsIgnoreCase("HmacSHA512") || crypto.equalsIgnoreCase("HMAC-SHA-512")) {
|
||||
return generate64();
|
||||
}
|
||||
return generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed for HMAC-SHA256 - 32 bytes Generates random 32 bytes long TOTP Secret.
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate32() {
|
||||
int size = 32;
|
||||
byte[] b = new byte[size];
|
||||
rand.nextBytes(b);
|
||||
return Arrays.copyOf(b, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed forHMAC-SHA512 - 64 bytes Generates random 64 bytes long TOTP Secret.
|
||||
*
|
||||
* @return generated secret
|
||||
*/
|
||||
public static final byte[] generate64() {
|
||||
int size = 64;
|
||||
byte[] b = new byte[size];
|
||||
rand.nextBytes(b);
|
||||
return Arrays.copyOf(b, size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,214 +7,199 @@ import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class TimeBasedOTP {
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
private static final int[] DIGITS_POWER
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
= {1,10,100,1000,10000,100000,1000000,10000000,100000000 };
|
||||
|
||||
static String seed64 = "";
|
||||
|
||||
static String steps = "0";
|
||||
|
||||
static String steps2 = "0";
|
||||
|
||||
TimeBasedOTP() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method uses the JCE to provide the crypto algorithm.
|
||||
* HMAC computes a Hashed Message Authentication Code with the
|
||||
* crypto hash algorithm as a parameter.
|
||||
*
|
||||
* @param crypto: the crypto algorithm (HmacSHA1, HmacSHA256,
|
||||
* HmacSHA512)
|
||||
* @param keyBytes: the bytes to use for the HMAC key
|
||||
* @param text: the message or text to be authenticated
|
||||
*/
|
||||
= { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
|
||||
|
||||
private static byte[] hmac_sha(String crypto, byte[] keyBytes,
|
||||
byte[] text){
|
||||
try {
|
||||
Mac hmac;
|
||||
hmac = Mac.getInstance(crypto);
|
||||
SecretKeySpec macKey =
|
||||
new SecretKeySpec(keyBytes, "RAW");
|
||||
hmac.init(macKey);
|
||||
return hmac.doFinal(text);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new UndeclaredThrowableException(gse);
|
||||
}
|
||||
}
|
||||
static String seed64 = "";
|
||||
|
||||
static String steps = "0";
|
||||
|
||||
/**
|
||||
* This method converts a HEX string to Byte[]
|
||||
*
|
||||
* @param hex: the HEX string
|
||||
*
|
||||
* @return: a byte array
|
||||
*/
|
||||
private static byte[] hexStr2Bytes(String hex){
|
||||
// Adding one byte to get the right conversion
|
||||
// Values starting with "0" can be converted
|
||||
byte[] bArray = new BigInteger("10" + hex,16).toByteArray();
|
||||
static String steps2 = "0";
|
||||
|
||||
// Copy all the REAL bytes, not the "first"
|
||||
byte[] ret = new byte[bArray.length - 1];
|
||||
for (int i = 0; i < ret.length; i++)
|
||||
ret[i] = bArray[i+1];
|
||||
return ret;
|
||||
}
|
||||
TimeBasedOTP() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method generates a OTP value for the given
|
||||
* set of parameters.
|
||||
* Default Crypto HmacSHA512
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
public static String genOTP(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA1");
|
||||
}
|
||||
|
||||
/* * This method generates a OTP value for the given
|
||||
* set of parameters.
|
||||
* Crypto HmacSHA1
|
||||
* @param key
|
||||
* @param time
|
||||
* @param returnDigits
|
||||
* @return
|
||||
*/
|
||||
public static String generateTOTPHmacSHA1(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA1");
|
||||
}
|
||||
/**
|
||||
* This method uses the JCE to provide the crypto algorithm. HMAC computes a
|
||||
* Hashed Message Authentication Code with the crypto hash algorithm as a
|
||||
* parameter.
|
||||
*
|
||||
* @param crypto the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512)
|
||||
* @param keyBytes the bytes to use for the HMAC key
|
||||
* @param text the message or text to be authenticated
|
||||
*/
|
||||
|
||||
private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {
|
||||
try {
|
||||
Mac hmac;
|
||||
hmac = Mac.getInstance(crypto);
|
||||
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
|
||||
hmac.init(macKey);
|
||||
return hmac.doFinal(text);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new UndeclaredThrowableException(gse);
|
||||
}
|
||||
}
|
||||
|
||||
/* * This method generates a OTP value for the given
|
||||
* set of parameters.
|
||||
* Crypto HmacSHA256
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
/**
|
||||
* This method converts a HEX string to Byte[].
|
||||
*
|
||||
* @param hex the HEX string
|
||||
*
|
||||
* @return: a byte array
|
||||
*/
|
||||
private static byte[] hexStr2Bytes(String hex) {
|
||||
// Adding one byte to get the right conversion
|
||||
// Values starting with "0" can be converted
|
||||
byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();
|
||||
|
||||
public static String genOTPHmacSHA256(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA256");
|
||||
}
|
||||
|
||||
/* *
|
||||
* This method generates a OTP value for the given
|
||||
* set of parameters.
|
||||
* Crypto HmacSHA256
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
public static String genOTPHmacSHA512(String key,
|
||||
String time,
|
||||
String returnDigits){
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA512");
|
||||
}
|
||||
// Copy all the REAL bytes, not the "first"
|
||||
byte[] ret = new byte[bArray.length - 1];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = bArray[i + 1];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method generates a OTP value for the given set of parameters. Default
|
||||
* Crypto HmacSHA512
|
||||
*
|
||||
* @param key the shared secret, HEX encoded
|
||||
* @param time a value that reflects a time
|
||||
* @param returnDigits number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes {@link truncationDigits}
|
||||
* digits
|
||||
*/
|
||||
public static String genOTP(String key, String time, String returnDigits) {
|
||||
|
||||
/**
|
||||
* This method generates a TOTP value for the given
|
||||
* set of parameters.
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
* @param time: a value that reflects a time
|
||||
* @param returnDigits: number of digits to return
|
||||
* @param crypto: the crypto function to use
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes
|
||||
* {@link truncationDigits} digits
|
||||
*/
|
||||
public static void actualiseTime(){
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA1");
|
||||
}
|
||||
|
||||
/*
|
||||
* * This method generates a OTP value for the given set of parameters. Crypto
|
||||
* HmacSHA1
|
||||
*
|
||||
* @param key
|
||||
*
|
||||
* @param time
|
||||
*
|
||||
* @param returnDigits
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String generateTOTPHmacSHA1(String key, String time, String returnDigits) {
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA1");
|
||||
}
|
||||
|
||||
/*
|
||||
* * This method generates a OTP value for the given set of parameters. Crypto
|
||||
* HmacSHA256
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
*
|
||||
* @param time: a value that reflects a time
|
||||
*
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes {@link truncationDigits}
|
||||
* digits
|
||||
*/
|
||||
|
||||
public static String genOTPHmacSHA256(String key, String time, String returnDigits) {
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA256");
|
||||
}
|
||||
|
||||
/*
|
||||
* * This method generates a OTP value for the given set of parameters. Crypto
|
||||
* HmacSHA256
|
||||
*
|
||||
* @param key: the shared secret, HEX encoded
|
||||
*
|
||||
* @param time: a value that reflects a time
|
||||
*
|
||||
* @param returnDigits: number of digits to return
|
||||
*
|
||||
* @return: a numeric String in base 10 that includes {@link truncationDigits}
|
||||
* digits
|
||||
*/
|
||||
public static String genOTPHmacSHA512(String key, String time, String returnDigits) {
|
||||
return generateOTP(key, time, returnDigits, "HmacSHA512");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method generates a TOTP value for the given set of parameters.
|
||||
*/
|
||||
public static void actualiseTime() {
|
||||
// double random = Math.random();
|
||||
long T0 = 0;
|
||||
long X = 30;
|
||||
Date d = new Date();
|
||||
Long k = d.getTime()/1000;
|
||||
long T0 = 0;
|
||||
long X = 30;
|
||||
Date d = new Date();
|
||||
Long k = d.getTime() / 1000;
|
||||
|
||||
long testTime[] = {d.getTime()};
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
df.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
long testTime[] = { d.getTime() };
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
df.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
for (int i=0; i<testTime.length; i++) {
|
||||
long T = (k - T0)/X;
|
||||
long T2 = ((k - T0)/X)-1;
|
||||
// System.out.println(T);
|
||||
steps = Long.toHexString(T).toUpperCase();
|
||||
steps2 = Long.toHexString(T2).toUpperCase();
|
||||
while (steps.length() < 16) steps = "0" + steps;
|
||||
//String fmtTime = String.format("%1$-11s", k/1000);
|
||||
//String utcTime = df.format(new Date(testTime[i]));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static String generateOTP(String key,
|
||||
String time,
|
||||
String returnDigits,
|
||||
String crypto){
|
||||
int codeDigits = Integer.decode(returnDigits).intValue();
|
||||
|
||||
String result = null;
|
||||
for (int i = 0; i < testTime.length; i++) {
|
||||
long T = (k - T0) / X;
|
||||
long T2 = ((k - T0) / X) - 1;
|
||||
// System.out.println(T);
|
||||
steps = Long.toHexString(T).toUpperCase();
|
||||
steps2 = Long.toHexString(T2).toUpperCase();
|
||||
while (steps.length() < 16) {
|
||||
steps = "0" + steps;
|
||||
}
|
||||
//String fmtTime = String.format("%1$-11s", k/1000);
|
||||
//String utcTime = df.format(new Date(testTime[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Using the counter
|
||||
// First 8 bytes are for the movingFactor
|
||||
// Compliant with base RFC 4226 (HOTP)
|
||||
while (time.length() < 16 )
|
||||
time = "0" + time;
|
||||
/**
|
||||
* generateOTP.
|
||||
* @param key String
|
||||
* @param time String
|
||||
* @param returnDigits String
|
||||
* @param crypto String
|
||||
* @return
|
||||
*/
|
||||
public static String generateOTP(String key, String time, String returnDigits, String crypto) {
|
||||
int codeDigits = Integer.decode(returnDigits).intValue();
|
||||
|
||||
// Get the HEX in a Byte[]
|
||||
byte[] msg = hexStr2Bytes(time);
|
||||
byte[] k = hexStr2Bytes(key);
|
||||
String result = null;
|
||||
|
||||
// Using the counter
|
||||
// First 8 bytes are for the movingFactor
|
||||
// Compliant with base RFC 4226 (HOTP)
|
||||
while (time.length() < 16) {
|
||||
time = "0" + time;
|
||||
}
|
||||
// Get the HEX in a Byte[]
|
||||
byte[] msg = hexStr2Bytes(time);
|
||||
byte[] k = hexStr2Bytes(key);
|
||||
|
||||
byte[] hash = hmac_sha(crypto, k, msg);
|
||||
byte[] hash = hmac_sha(crypto, k, msg);
|
||||
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
// put selected bytes into result int
|
||||
int offset = hash[hash.length - 1] & 0xf;
|
||||
|
||||
int binary =
|
||||
((hash[offset] & 0x7f) << 24) |
|
||||
((hash[offset + 1] & 0xff) << 16) |
|
||||
((hash[offset + 2] & 0xff) << 8) |
|
||||
(hash[offset + 3] & 0xff);
|
||||
int binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16)
|
||||
| ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
|
||||
|
||||
int otp = binary % DIGITS_POWER[codeDigits];
|
||||
int otp = binary % DIGITS_POWER[codeDigits];
|
||||
|
||||
result = Integer.toString(otp);
|
||||
while (result.length() < codeDigits) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Integer.toString(otp);
|
||||
while (result.length() < codeDigits) {
|
||||
result = "0" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Administrator
|
||||
*
|
||||
*/
|
||||
package org.maxkey.crypto.password.opt.algorithm;
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Chip Authentication Program
|
||||
* EMV stands for Europay, MasterCard and Visa,
|
||||
* a global standard for inter-operation of integrated circuit cards (IC cards or "chip cards")
|
||||
* and IC card capable point of sale (POS) terminals and automated teller machines (ATMs),
|
||||
* for authenticating credit and debit card transactions.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class CAPOTPAuthn extends AbstractOTPAuthn {
|
||||
|
||||
public CAPOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Chip Authentication Program EMV stands for Europay, MasterCard and Visa, a
|
||||
* global standard for inter-operation of integrated circuit cards (IC cards or
|
||||
* "chip cards") and IC card capable point of sale (POS) terminals and automated
|
||||
* teller machines (ATMs), for authenticating credit and debit card
|
||||
* transactions.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class CapOtpAuthn extends AbstractOptAuthn {
|
||||
|
||||
public CapOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.crypto.password.opt.algorithm.TimeBasedOTP;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
|
||||
public class CounterBasedOTPAuthn extends AbstractOTPAuthn {
|
||||
private final static Logger _logger = LoggerFactory.getLogger(CounterBasedOTPAuthn.class);
|
||||
|
||||
public CounterBasedOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
_logger.debug("SharedCounter : "+userInfo.getSharedCounter());
|
||||
byte[]byteSharedSecret= Base32Utils.decode(userInfo.getSharedSecret());
|
||||
String hexSharedSecret=Hex.encodeHexString(byteSharedSecret);
|
||||
String counterBasedToken="";
|
||||
if(crypto.equalsIgnoreCase("HmacSHA1")){
|
||||
counterBasedToken=TimeBasedOTP.genOTP(hexSharedSecret,userInfo.getSharedCounter(),""+digits);
|
||||
}else if(crypto.equalsIgnoreCase("HmacSHA256")){
|
||||
counterBasedToken=TimeBasedOTP.genOTPHmacSHA256(hexSharedSecret,userInfo.getSharedCounter(),""+digits);
|
||||
}else if(crypto.equalsIgnoreCase("HmacSHA512")){
|
||||
counterBasedToken=TimeBasedOTP.genOTPHmacSHA512(hexSharedSecret,userInfo.getSharedCounter(),""+digits);
|
||||
}
|
||||
|
||||
_logger.debug("token : "+token);
|
||||
_logger.debug("counterBasedToken : "+counterBasedToken);
|
||||
if(token.equalsIgnoreCase(counterBasedToken)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.crypto.password.opt.algorithm.TimeBasedOTP;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class CounterBasedOtpAuthn extends AbstractOptAuthn {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(CounterBasedOtpAuthn.class);
|
||||
|
||||
public CounterBasedOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
_logger.debug("SharedCounter : " + userInfo.getSharedCounter());
|
||||
byte[] byteSharedSecret = Base32Utils.decode(userInfo.getSharedSecret());
|
||||
String hexSharedSecret = Hex.encodeHexString(byteSharedSecret);
|
||||
String counterBasedToken = "";
|
||||
if (crypto.equalsIgnoreCase("HmacSHA1")) {
|
||||
counterBasedToken = TimeBasedOTP.genOTP(
|
||||
hexSharedSecret,
|
||||
userInfo.getSharedCounter(),
|
||||
"" + digits
|
||||
);
|
||||
} else if (crypto.equalsIgnoreCase("HmacSHA256")) {
|
||||
counterBasedToken = TimeBasedOTP.genOTPHmacSHA256(
|
||||
hexSharedSecret,
|
||||
userInfo.getSharedCounter(),
|
||||
"" + digits
|
||||
);
|
||||
} else if (crypto.equalsIgnoreCase("HmacSHA512")) {
|
||||
counterBasedToken = TimeBasedOTP.genOTPHmacSHA512(
|
||||
hexSharedSecret,
|
||||
userInfo.getSharedCounter(),
|
||||
"" + digits
|
||||
);
|
||||
}
|
||||
|
||||
_logger.debug("token : " + token);
|
||||
_logger.debug("counterBasedToken : " + counterBasedToken);
|
||||
if (token.equalsIgnoreCase(counterBasedToken)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.crypto.password.opt.algorithm.HOTP;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
|
||||
public class HOTPOTPAuthn extends AbstractOTPAuthn {
|
||||
private final static Logger _logger = LoggerFactory.getLogger(HOTPOTPAuthn.class);
|
||||
|
||||
boolean addChecksum;
|
||||
int truncation=-1;
|
||||
|
||||
public HOTPOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
_logger.debug("SharedCounter : "+userInfo.getSharedCounter());
|
||||
byte[]byteSharedSecret= Base32Utils.decode(userInfo.getSharedSecret());
|
||||
String hotpToken;
|
||||
try {
|
||||
hotpToken = HOTP.generateOTP(byteSharedSecret, Long.parseLong(userInfo.getSharedCounter()), digits, addChecksum, truncation);
|
||||
_logger.debug("token : "+token);
|
||||
_logger.debug("hotpToken : "+hotpToken);
|
||||
if(token.equalsIgnoreCase(hotpToken)){
|
||||
return true;
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the addChecksum
|
||||
*/
|
||||
public boolean isAddChecksum() {
|
||||
return addChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param addChecksum the addChecksum to set
|
||||
*/
|
||||
public void setAddChecksum(boolean addChecksum) {
|
||||
this.addChecksum = addChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the truncation
|
||||
*/
|
||||
public int getTruncation() {
|
||||
return truncation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param truncation the truncation to set
|
||||
*/
|
||||
public void setTruncation(int truncation) {
|
||||
this.truncation = truncation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.crypto.password.opt.algorithm.HOTP;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class HotpOtpAuthn extends AbstractOptAuthn {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(HotpOtpAuthn.class);
|
||||
|
||||
boolean addChecksum;
|
||||
int truncation = -1;
|
||||
|
||||
public HotpOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
_logger.debug("SharedCounter : " + userInfo.getSharedCounter());
|
||||
byte[] byteSharedSecret = Base32Utils.decode(userInfo.getSharedSecret());
|
||||
String hotpToken;
|
||||
try {
|
||||
hotpToken = HOTP.generateOTP(
|
||||
byteSharedSecret,
|
||||
Long.parseLong(userInfo.getSharedCounter()),
|
||||
digits,
|
||||
addChecksum, truncation
|
||||
);
|
||||
_logger.debug("token : " + token);
|
||||
_logger.debug("hotpToken : " + hotpToken);
|
||||
if (token.equalsIgnoreCase(hotpToken)) {
|
||||
return true;
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* the addChecksum.
|
||||
*/
|
||||
public boolean isAddChecksum() {
|
||||
return addChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* addChecksum the addChecksum to set.
|
||||
*/
|
||||
public void setAddChecksum(boolean addChecksum) {
|
||||
this.addChecksum = addChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* the truncation.
|
||||
*/
|
||||
public int getTruncation() {
|
||||
return truncation;
|
||||
}
|
||||
|
||||
/**
|
||||
* truncation the truncation to set.
|
||||
*/
|
||||
public void setTruncation(int truncation) {
|
||||
this.truncation = truncation;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.apache.commons.mail.DefaultAuthenticator;
|
||||
import org.apache.commons.mail.Email;
|
||||
import org.apache.commons.mail.SimpleEmail;
|
||||
import org.maxkey.config.EmailConfig;
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
|
||||
public class MailOTPAuthn extends AbstractOTPAuthn {
|
||||
private final static Logger _logger = LoggerFactory.getLogger(MailOTPAuthn.class);
|
||||
EmailConfig emailConfig;
|
||||
|
||||
public MailOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
try{
|
||||
String token=this.genToken(userInfo);
|
||||
Email email = new SimpleEmail();
|
||||
email.setHostName(emailConfig.getSmtpHost());
|
||||
email.setSmtpPort(emailConfig.getPort());
|
||||
email.setAuthenticator(new DefaultAuthenticator(emailConfig.getUsername(), emailConfig.getPassword()));
|
||||
email.setSSLOnConnect(emailConfig.isSsl());
|
||||
email.setFrom(emailConfig.getSenderMail());
|
||||
email.setSubject("One Time PassWord");
|
||||
email.setMsg("You Token is "+token+" , it validity in "+(interval/60) +" minutes");
|
||||
email.addTo(userInfo.getEmail());
|
||||
email.send();
|
||||
_logger.debug("token "+token+" send to user +"+userInfo.getUsername()+", email "+userInfo.getEmail());
|
||||
this.insertDataBase(userInfo, token, userInfo.getUsername(), OPT_TYPES.EMAIL);
|
||||
return true;
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
return this.validateDataBase(userInfo, token, OPT_TYPES.EMAIL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param emailConfig the emailConfig to set
|
||||
*/
|
||||
public void setEmailConfig(EmailConfig emailConfig) {
|
||||
this.emailConfig = emailConfig;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.apache.commons.mail.DefaultAuthenticator;
|
||||
import org.apache.commons.mail.Email;
|
||||
import org.apache.commons.mail.SimpleEmail;
|
||||
import org.maxkey.config.EmailConfig;
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class MailOtpAuthn extends AbstractOptAuthn {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(MailOtpAuthn.class);
|
||||
EmailConfig emailConfig;
|
||||
|
||||
public MailOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
try {
|
||||
String token = this.genToken(userInfo);
|
||||
Email email = new SimpleEmail();
|
||||
email.setHostName(emailConfig.getSmtpHost());
|
||||
email.setSmtpPort(emailConfig.getPort());
|
||||
email.setAuthenticator(
|
||||
new DefaultAuthenticator(emailConfig.getUsername(), emailConfig.getPassword()));
|
||||
email.setSSLOnConnect(emailConfig.isSsl());
|
||||
email.setFrom(emailConfig.getSenderMail());
|
||||
email.setSubject("One Time PassWord");
|
||||
email.setMsg("You Token is " + token
|
||||
+ " , it validity in " + (interval / 60) + " minutes");
|
||||
email.addTo(userInfo.getEmail());
|
||||
email.send();
|
||||
_logger.debug(
|
||||
"token " + token + " send to user +" + userInfo.getUsername()
|
||||
+ ", email " + userInfo.getEmail());
|
||||
this.insertDataBase(userInfo, token, userInfo.getUsername(), OPT_TYPES.EMAIL);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
return this.validateDataBase(userInfo, token, OPT_TYPES.EMAIL);
|
||||
}
|
||||
|
||||
public void setEmailConfig(EmailConfig emailConfig) {
|
||||
this.emailConfig = emailConfig;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
|
||||
public class MobileOTPAuthn extends AbstractOTPAuthn {
|
||||
|
||||
public MobileOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class MobileOtpAuthn extends AbstractOptAuthn {
|
||||
|
||||
public MobileOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Chip Authentication Program
|
||||
* EMV stands for Europay, MasterCard and Visa,
|
||||
* a global standard for inter-operation of integrated circuit cards (IC cards or "chip cards")
|
||||
* and IC card capable point of sale (POS) terminals and automated teller machines (ATMs),
|
||||
* for authenticating credit and debit card transactions.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class RSAOTPAuthn extends AbstractOTPAuthn {
|
||||
|
||||
public RSAOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Chip Authentication Program EMV stands for Europay, MasterCard and Visa, a
|
||||
* global standard for inter-operation of integrated circuit cards (IC cards or
|
||||
* "chip cards") and IC card capable point of sale (POS) terminals and automated
|
||||
* teller machines (ATMs), for authenticating credit and debit card
|
||||
* transactions.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class RsaOtpAuthn extends AbstractOptAuthn {
|
||||
|
||||
public RsaOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
|
||||
public class SmsOTPAuthn extends AbstractOTPAuthn {
|
||||
|
||||
public SmsOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
String token=this.genToken(userInfo);
|
||||
//TODO:You must add send sms code here
|
||||
|
||||
this.insertDataBase(userInfo, token, userInfo.getUsername(), OPT_TYPES.SMS);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
return this.validateDataBase(userInfo, token, OPT_TYPES.SMS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class SmsOtpAuthn extends AbstractOptAuthn {
|
||||
|
||||
public SmsOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
String token = this.genToken(userInfo);
|
||||
// TODO:You must add send sms code here
|
||||
|
||||
this.insertDataBase(userInfo, token, userInfo.getUsername(), OPT_TYPES.SMS);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
return this.validateDataBase(userInfo, token, OPT_TYPES.SMS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.opt.AbstractOTPAuthn;
|
||||
import org.maxkey.crypto.password.opt.algorithm.TimeBasedOTP;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
|
||||
public class TimeBasedOTPAuthn extends AbstractOTPAuthn {
|
||||
private final static Logger _logger = LoggerFactory.getLogger(TimeBasedOTPAuthn.class);
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public TimeBasedOTPAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo,String token) {
|
||||
_logger.debug("utcTime : "+dateFormat.format(new Date()));
|
||||
long currentTimeSeconds =System.currentTimeMillis() / 1000;
|
||||
byte[]byteSharedSecret= Base32Utils.decode(userInfo.getSharedSecret());
|
||||
String hexSharedSecret=Hex.encodeHexString(byteSharedSecret);
|
||||
String timeBasedToken="";
|
||||
if(crypto.equalsIgnoreCase("HmacSHA1")){
|
||||
timeBasedToken=TimeBasedOTP.genOTP(
|
||||
hexSharedSecret,
|
||||
Long.toHexString(currentTimeSeconds/interval).toUpperCase()+"",
|
||||
digits+"");
|
||||
}else if(crypto.equalsIgnoreCase("HmacSHA256")){
|
||||
timeBasedToken=TimeBasedOTP.genOTPHmacSHA256(
|
||||
hexSharedSecret,
|
||||
Long.toHexString(currentTimeSeconds/interval).toUpperCase()+"",
|
||||
digits+"");
|
||||
}else if(crypto.equalsIgnoreCase("HmacSHA512")){
|
||||
timeBasedToken=TimeBasedOTP.genOTPHmacSHA512(
|
||||
hexSharedSecret,
|
||||
Long.toHexString(currentTimeSeconds/interval).toUpperCase()+"",
|
||||
digits+"");
|
||||
}
|
||||
_logger.debug("token : "+token);
|
||||
_logger.debug("timeBasedToken : "+timeBasedToken);
|
||||
if(token.equalsIgnoreCase(timeBasedToken)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.opt.AbstractOptAuthn;
|
||||
import org.maxkey.crypto.password.opt.algorithm.TimeBasedOTP;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class TimeBasedOtpAuthn extends AbstractOptAuthn {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(TimeBasedOtpAuthn.class);
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public TimeBasedOtpAuthn(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean produce(UserInfo userInfo) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(UserInfo userInfo, String token) {
|
||||
_logger.debug("utcTime : " + dateFormat.format(new Date()));
|
||||
long currentTimeSeconds = System.currentTimeMillis() / 1000;
|
||||
byte[] byteSharedSecret = Base32Utils.decode(userInfo.getSharedSecret());
|
||||
String hexSharedSecret = Hex.encodeHexString(byteSharedSecret);
|
||||
String timeBasedToken = "";
|
||||
if (crypto.equalsIgnoreCase("HmacSHA1")) {
|
||||
timeBasedToken = TimeBasedOTP.genOTP(
|
||||
hexSharedSecret,
|
||||
Long.toHexString(currentTimeSeconds / interval).toUpperCase() + "",
|
||||
digits + "");
|
||||
} else if (crypto.equalsIgnoreCase("HmacSHA256")) {
|
||||
timeBasedToken = TimeBasedOTP.genOTPHmacSHA256(
|
||||
hexSharedSecret,
|
||||
Long.toHexString(currentTimeSeconds / interval).toUpperCase() + "",
|
||||
digits + "");
|
||||
} else if (crypto.equalsIgnoreCase("HmacSHA512")) {
|
||||
timeBasedToken = TimeBasedOTP.genOTPHmacSHA512(
|
||||
hexSharedSecret,
|
||||
Long.toHexString(currentTimeSeconds / interval).toUpperCase() + "",
|
||||
digits + "");
|
||||
}
|
||||
_logger.debug("token : " + token);
|
||||
_logger.debug("timeBasedToken : " + timeBasedToken);
|
||||
if (token.equalsIgnoreCase(timeBasedToken)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Administrator
|
||||
*
|
||||
*/
|
||||
package org.maxkey.crypto.password.opt.impl;
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.maxkey.crypto.password.opt.impl.sms;
|
||||
|
||||
public interface SendSms {
|
||||
|
||||
public String sendSms();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.maxkey.crypto.password.opt.impl.sms.netease;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.maxkey.crypto.password.opt.impl.sms.SendSms;
|
||||
|
||||
/**
|
||||
* 网易云信的短信验证.
|
||||
* @author shimingxy
|
||||
*
|
||||
*/
|
||||
|
||||
public class SendSmsYunxin implements SendSms {
|
||||
//发送验证码的请求路径URL
|
||||
private static final String
|
||||
SERVER_URL = "https://api.netease.im/sms/sendcode.action";
|
||||
//网易云信分配的账号,请替换你在管理后台应用下申请的Appkey
|
||||
private static final String
|
||||
APP_KEY = "94395d754eb55693043f5d6a2b772ef3";
|
||||
//网易云信分配的密钥,请替换你在管理后台应用下申请的appSecret
|
||||
private static final String APP_SECRET = "05d5485357bc";
|
||||
// 随机数
|
||||
private static final String NONCE = "123456";
|
||||
// 短信模板ID
|
||||
private static final String TEMPLATEID = "14850150";
|
||||
// 手机号
|
||||
private static final String MOBILE = "15618726256";
|
||||
// 验证码长度,范围4~10,默认为4
|
||||
private static final String CODELEN = "6";
|
||||
|
||||
/**
|
||||
* .
|
||||
* @param args String
|
||||
* @throws Exception e
|
||||
*/
|
||||
public static void sendSms(String[] args) throws Exception {
|
||||
|
||||
HttpPost httpPost = new HttpPost(SERVER_URL);
|
||||
String curTime = String.valueOf((new Date()).getTime() / 1000L);
|
||||
/*
|
||||
* 参考计算CheckSum的java代码,在上述文档的参数列表中,有CheckSum的计算文档示例
|
||||
*/
|
||||
String checkSum = SendSmsYunxinCheckSumBuilder
|
||||
.getCheckSum(APP_SECRET, NONCE, curTime);
|
||||
|
||||
// 设置请求的header
|
||||
httpPost.addHeader("AppKey", APP_KEY);
|
||||
httpPost.addHeader("Nonce", NONCE);
|
||||
httpPost.addHeader("CurTime", curTime);
|
||||
httpPost.addHeader("CheckSum", checkSum);
|
||||
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
|
||||
|
||||
// 设置请求的的参数,requestBody参数
|
||||
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
|
||||
/*
|
||||
* 1.如果是模板短信,请注意参数mobile是有s的,详细参数配置请参考“发送模板短信文档”
|
||||
* 2.参数格式是jsonArray的格式,例如 "['13888888888','13666666666']"
|
||||
* 3.params是根据你模板里面有几个参数,那里面的参数也是jsonArray格式
|
||||
*/
|
||||
//https://api.netease.im/sms/sendcode.action
|
||||
nvps.add(new BasicNameValuePair("templateid", TEMPLATEID));
|
||||
nvps.add(new BasicNameValuePair("mobile", MOBILE));
|
||||
nvps.add(new BasicNameValuePair("codeLen", CODELEN));
|
||||
//authCode 用户自定义验证码
|
||||
//nvps.add(new BasicNameValuePair("authCode", ""));
|
||||
//https://api.netease.im/sms/verifycode.action
|
||||
//nvps.add(new BasicNameValuePair("code", "123456"));
|
||||
|
||||
|
||||
|
||||
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
// 执行请求
|
||||
HttpResponse response = httpClient.execute(httpPost);
|
||||
/*
|
||||
* 1.打印执行结果,打印结果一般会200、315、403、404、413、414、500
|
||||
* 2.具体的code有问题的可以参考官网的Code状态表
|
||||
*/
|
||||
System.out.println(EntityUtils.toString(response.getEntity(), "utf-8"));
|
||||
//{"code":200,"msg":"1","obj":"740673"}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
sendSms(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sendSms() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.maxkey.crypto.password.opt.impl.sms.netease;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class SendSmsYunxinCheckSumBuilder {
|
||||
// 计算并获取CheckSum
|
||||
public static String getCheckSum(String appSecret, String nonce, String curTime) {
|
||||
return encode("sha1", appSecret + nonce + curTime);
|
||||
}
|
||||
|
||||
// 计算并获取md5值
|
||||
public static String getMD5(String requestBody) {
|
||||
return encode("md5", requestBody);
|
||||
}
|
||||
|
||||
private static String encode(String algorithm, String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
|
||||
messageDigest.update(value.getBytes());
|
||||
return getFormattedText(messageDigest.digest());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFormattedText(byte[] bytes) {
|
||||
int len = bytes.length;
|
||||
StringBuilder buf = new StringBuilder(len * 2);
|
||||
for (int j = 0; j < len; j++) {
|
||||
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
|
||||
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static final char[] HEX_DIGITS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd','e', 'f' };
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package org.maxkey.crypto.password.opt.impl.sms;
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Administrator
|
||||
*
|
||||
*/
|
||||
package org.maxkey.crypto.password.opt;
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Administrator
|
||||
*
|
||||
*/
|
||||
package org.maxkey.crypto.password;
|
||||
@@ -13,121 +13,105 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class OpenHTTPPostDecoder extends HTTPPostDecoder {
|
||||
private final Logger log = LoggerFactory.getLogger(OpenHTTPPostDecoder.class);
|
||||
private final Logger log = LoggerFactory.getLogger(OpenHTTPPostDecoder.class);
|
||||
|
||||
private String receiverEndpoint;
|
||||
private String receiverEndpoint;
|
||||
|
||||
public OpenHTTPPostDecoder() {
|
||||
super();
|
||||
}
|
||||
public OpenHTTPPostDecoder() {
|
||||
super();
|
||||
}
|
||||
|
||||
public OpenHTTPPostDecoder(ParserPool pool) {
|
||||
super(pool);
|
||||
}
|
||||
public OpenHTTPPostDecoder(ParserPool pool) {
|
||||
super(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the validity of the SAML protocol message receiver endpoint against
|
||||
* requirements indicated in the message.
|
||||
*
|
||||
* @param messageContext
|
||||
* current message context
|
||||
*
|
||||
* @throws SecurityException
|
||||
* thrown if the message Destination attribute is invalid with
|
||||
* respect to the receiver's endpoint
|
||||
* @throws MessageDecodingException
|
||||
* thrown if there is a problem decoding and processing the
|
||||
* message Destination or receiver endpoint information
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
protected void checkEndpointURI(SAMLMessageContext messageContext)
|
||||
throws SecurityException, MessageDecodingException {
|
||||
/**
|
||||
* Check the validity of the SAML protocol message receiver endpoint against
|
||||
* requirements indicated in the message.
|
||||
*
|
||||
* @param messageContext current message context
|
||||
*
|
||||
* @throws SecurityException thrown if the message Destination attribute
|
||||
* is invalid with respect to the receiver's
|
||||
* endpoint
|
||||
* @throws MessageDecodingException thrown if there is a problem decoding and
|
||||
* processing the message Destination or
|
||||
* receiver endpoint information
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
protected void checkEndpointURI(SAMLMessageContext messageContext)
|
||||
throws SecurityException, MessageDecodingException {
|
||||
|
||||
log.debug("Checking SAML message intended destination endpoint against receiver endpoint");
|
||||
log.debug("Checking SAML message intended destination endpoint against receiver endpoint");
|
||||
|
||||
String messageDestination = DatatypeHelper
|
||||
.safeTrimOrNullString(getIntendedDestinationEndpointURI(messageContext));
|
||||
String messageDestination = DatatypeHelper
|
||||
.safeTrimOrNullString(getIntendedDestinationEndpointURI(messageContext));
|
||||
|
||||
boolean bindingRequires = isIntendedDestinationEndpointURIRequired(messageContext);
|
||||
boolean bindingRequires = isIntendedDestinationEndpointURIRequired(messageContext);
|
||||
|
||||
if (messageDestination == null) {
|
||||
if (bindingRequires) {
|
||||
log.error("SAML message intended destination endpoint URI required by binding was empty");
|
||||
throw new SecurityException(
|
||||
"SAML message intended destination (required by binding) was not present");
|
||||
} else {
|
||||
log.debug("SAML message intended destination endpoint in message was empty, not required by binding, skipping");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (messageDestination == null) {
|
||||
if (bindingRequires) {
|
||||
log.error("SAML message intended destination endpoint URI required by binding was empty");
|
||||
throw new SecurityException("SAML message intended destination (required by binding) was not present");
|
||||
} else {
|
||||
log.debug(
|
||||
"SAML message intended destination endpoint in message was empty, not required by binding, skipping");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String receiverEndpoint = DatatypeHelper
|
||||
.safeTrimOrNullString(getActualReceiverEndpointURI(messageContext));
|
||||
String receiverEndpoint = DatatypeHelper.safeTrimOrNullString(getActualReceiverEndpointURI(messageContext));
|
||||
|
||||
log.debug("Intended message destination endpoint: {}",
|
||||
messageDestination);
|
||||
log.debug("Actual message receiver endpoint: {}", receiverEndpoint);
|
||||
log.debug("Intended message destination endpoint: {}", messageDestination);
|
||||
log.debug("Actual message receiver endpoint: {}", receiverEndpoint);
|
||||
|
||||
// 协议头统一(http或https,需要和destination统一)
|
||||
if (messageDestination.indexOf("/") != -1
|
||||
&& receiverEndpoint.indexOf("/") != -1) {
|
||||
if (!messageDestination.substring(0,
|
||||
messageDestination.indexOf("/"))
|
||||
.equalsIgnoreCase(
|
||||
receiverEndpoint.substring(0,
|
||||
receiverEndpoint.indexOf("/")))) {
|
||||
receiverEndpoint = messageDestination.substring(0,
|
||||
messageDestination.indexOf("/"))
|
||||
+ receiverEndpoint.substring(receiverEndpoint
|
||||
.indexOf("/"));
|
||||
}
|
||||
}
|
||||
boolean matched = compareEndpointURIs(messageDestination,
|
||||
receiverEndpoint);
|
||||
if (!matched) {
|
||||
log.error(
|
||||
"SAML message intended destination endpoint '{}' did not match the recipient endpoint '{}'",
|
||||
messageDestination, receiverEndpoint);
|
||||
throw new SecurityException(
|
||||
"SAML message intended destination endpoint did not match recipient endpoint");
|
||||
} else {
|
||||
log.debug("SAML message intended destination endpoint matched recipient endpoint");
|
||||
}
|
||||
}
|
||||
// 协议头统一(http或https,需要和destination统一)
|
||||
if (messageDestination.indexOf("/") != -1 && receiverEndpoint.indexOf("/") != -1) {
|
||||
if (!messageDestination.substring(0, messageDestination.indexOf("/"))
|
||||
.equalsIgnoreCase(receiverEndpoint.substring(0, receiverEndpoint.indexOf("/")))) {
|
||||
receiverEndpoint = messageDestination.substring(0, messageDestination.indexOf("/"))
|
||||
+ receiverEndpoint.substring(receiverEndpoint.indexOf("/"));
|
||||
}
|
||||
}
|
||||
boolean matched = compareEndpointURIs(messageDestination, receiverEndpoint);
|
||||
if (!matched) {
|
||||
log.error("SAML message intended destination endpoint '{}' did not match the recipient endpoint '{}'",
|
||||
messageDestination, receiverEndpoint);
|
||||
throw new SecurityException("SAML message intended destination endpoint did not match recipient endpoint");
|
||||
} else {
|
||||
log.debug("SAML message intended destination endpoint matched recipient endpoint");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected String getActualReceiverEndpointURI(
|
||||
SAMLMessageContext messageContext) throws MessageDecodingException {
|
||||
InTransport inTransport = messageContext.getInboundMessageTransport();
|
||||
if (!(inTransport instanceof HttpServletRequestAdapter)) {
|
||||
throw new MessageDecodingException(
|
||||
"Message context InTransport instance was an unsupported type");
|
||||
}
|
||||
HttpServletRequest httpRequest = ((HttpServletRequestAdapter) inTransport)
|
||||
.getWrappedRequest();
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected String getActualReceiverEndpointURI(SAMLMessageContext messageContext) throws MessageDecodingException {
|
||||
InTransport inTransport = messageContext.getInboundMessageTransport();
|
||||
if (!(inTransport instanceof HttpServletRequestAdapter)) {
|
||||
throw new MessageDecodingException("Message context InTransport instance was an unsupported type");
|
||||
}
|
||||
HttpServletRequest httpRequest = ((HttpServletRequestAdapter) inTransport).getWrappedRequest();
|
||||
|
||||
StringBuffer urlBuilder = httpRequest.getRequestURL();
|
||||
StringBuffer urlBuilder = httpRequest.getRequestURL();
|
||||
|
||||
String tempUrl = urlBuilder.toString();
|
||||
// 从http协议头开始,跳过前面两个斜杠
|
||||
tempUrl = tempUrl.substring(tempUrl.indexOf("/", 8) + 1);
|
||||
return receiverEndpoint + tempUrl;
|
||||
}
|
||||
String tempUrl = urlBuilder.toString();
|
||||
// 从http协议头开始,跳过前面两个斜杠
|
||||
tempUrl = tempUrl.substring(tempUrl.indexOf("/", 8) + 1);
|
||||
return receiverEndpoint + tempUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param receiverEndpoint
|
||||
* the receiverEndpoint to set
|
||||
*/
|
||||
public void setReceiverEndpoint(String receiverEndpoint) {
|
||||
this.receiverEndpoint = receiverEndpoint;
|
||||
}
|
||||
/**
|
||||
* @param receiverEndpoint the receiverEndpoint to set
|
||||
*/
|
||||
public void setReceiverEndpoint(String receiverEndpoint) {
|
||||
this.receiverEndpoint = receiverEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the receiverEndpoint
|
||||
*/
|
||||
public String getReceiverEndpoint() {
|
||||
return receiverEndpoint;
|
||||
}
|
||||
/**
|
||||
* @return the receiverEndpoint
|
||||
*/
|
||||
public String getReceiverEndpoint() {
|
||||
return receiverEndpoint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
<ref bean="localeChangeInterceptor" />
|
||||
</mvc:interceptors>
|
||||
|
||||
<bean id="remeberMeService" class="org.maxkey.authn.support.rememberme.JdbcRemeberMeService">
|
||||
<bean id="remeberMeService" class="org.maxkey.authn.support.rememberme.JdbcRemeberMeService">
|
||||
<constructor-arg ref="jdbcTemplate"/>
|
||||
<property name="validity" value="${config.login.remeberme.validity}"/>
|
||||
</bean>
|
||||
@@ -104,24 +104,7 @@
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="counterBasedKeyUriFormat" class="org.maxkey.crypto.password.opt.algorithm.KeyUriFormat">
|
||||
<property name="type" value="hotp" />
|
||||
<property name="digits" value="6" />
|
||||
<property name="issuer" value="maxkey" />
|
||||
<property name="domain" value="maxkey.org" />
|
||||
<property name="counter" value="0" />
|
||||
</bean>
|
||||
|
||||
<bean id="hotpKeyUriFormat" class="org.maxkey.crypto.password.opt.algorithm.KeyUriFormat">
|
||||
<property name="type" value="hotp" />
|
||||
<property name="digits" value="6" />
|
||||
<property name="issuer" value="maxkey" />
|
||||
<property name="domain" value="maxkey.org" />
|
||||
<property name="counter" value="0" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="tfaOTPAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOTPAuthn">
|
||||
<bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn">
|
||||
<constructor-arg ref="jdbcTemplate" />
|
||||
</bean>
|
||||
|
||||
@@ -151,41 +134,9 @@
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Follow is config for Spring security -->
|
||||
<!--<csrf disabled="true"/>-->
|
||||
<!-- Login
|
||||
<http use-expressions="false" disable-url-rewriting="false" xmlns="http://www.springframework.org/schema/security" >
|
||||
|
||||
<headers>
|
||||
<frame-options policy="SAMEORIGIN" />
|
||||
</headers>
|
||||
<access-denied-handler error-page="/login"/>
|
||||
<intercept-url pattern="/index" access="ROLE_USER" />
|
||||
<intercept-url pattern="/forwardindex" access="ROLE_USER" />
|
||||
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY,ROLE_USER" />
|
||||
<form-login authentication-failure-url="/login"
|
||||
default-target-url="/forwardindex"
|
||||
login-page="/login"
|
||||
login-processing-url="/logon.do"
|
||||
username-parameter="j_username"
|
||||
password-parameter="j_password"
|
||||
authentication-success-handler-ref="savedRequestSuccessHandler"/>
|
||||
|
||||
<logout logout-url="/logout.do" logout-success-url="/logout" invalidate-session="true" delete-cookies="JSESSIONID" />
|
||||
|
||||
<session-management invalid-session-url="/login" />
|
||||
|
||||
<anonymous />
|
||||
</http>
|
||||
-->
|
||||
|
||||
<bean id="savedRequestSuccessHandler" class="org.maxkey.authn.SavedRequestAwareAuthenticationSuccessHandler"> </bean>
|
||||
|
||||
<!-- spring authentication provider
|
||||
<authentication-manager alias="authenticationProvider" xmlns="http://www.springframework.org/schema/security"/>
|
||||
-->
|
||||
|
||||
<!-- LDAP Realm
|
||||
<bean id="authenticationRealm" class="org.maxkey.web.authentication.realm.ldap.LdapAuthenticationRealm">
|
||||
<constructor-arg ref="jdbcTemplate"/>
|
||||
@@ -225,34 +176,16 @@
|
||||
</property>
|
||||
</bean> -->
|
||||
|
||||
<!-- Radius Server Realm
|
||||
<bean id="authenticationRealm" class="org.maxkey.web.authentication.realm.radius.RadiusServerAuthenticationRealm">
|
||||
<constructor-arg ref="jdbcTemplate"/>
|
||||
<property name="jradiusServers">
|
||||
<list>
|
||||
<bean id="radiusServer1" class="org.maxkey.web.authentication.realm.radius.RadiusServer">
|
||||
<property name="inetAddress" value="localhost"/>
|
||||
<property name="secret" value="test1234"/>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>-->
|
||||
|
||||
<!-- Default Realm-->
|
||||
<!-- realm use jdbc -->
|
||||
<bean id="authenticationRealm" class="org.maxkey.authn.realm.jdbc.JdbcAuthenticationRealm">
|
||||
<constructor-arg ref="jdbcTemplate"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Authentication providers -->
|
||||
<bean id="authenticationProvider" class="org.maxkey.authn.RealmAuthenticationProvider" >
|
||||
</bean>
|
||||
<!--
|
||||
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
|
||||
<authentication-provider ref= "realmAuthenticationProvider"/>
|
||||
</authentication-manager>
|
||||
-->
|
||||
|
||||
<mvc:annotation-driven />
|
||||
|
||||
<mvc:default-servlet-handler />
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.apache.commons.codec.binary.Hex;
|
||||
import org.maxkey.crypto.Base32Utils;
|
||||
import org.maxkey.crypto.password.PasswordReciprocal;
|
||||
import org.maxkey.crypto.password.opt.algorithm.KeyUriFormat;
|
||||
import org.maxkey.crypto.password.opt.algorithm.OTPSecret;
|
||||
import org.maxkey.crypto.password.opt.algorithm.OtpSecret;
|
||||
import org.maxkey.dao.service.UserInfoService;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.util.RQCodeUtils;
|
||||
@@ -63,7 +63,7 @@ public class OneTimePasswordController {
|
||||
@RequestMapping(value = {"gen/timebased"})
|
||||
public ModelAndView gentimebased() {
|
||||
UserInfo userInfo = WebContext.getUserInfo();
|
||||
byte[] byteSharedSecret = OTPSecret.generate(keyUriFormat.getCrypto());
|
||||
byte[] byteSharedSecret = OtpSecret.generate(keyUriFormat.getCrypto());
|
||||
String sharedSecret = Base32Utils.encode(byteSharedSecret);
|
||||
sharedSecret = passwordReciprocal.encode(sharedSecret);
|
||||
userInfo.setSharedSecret(sharedSecret);
|
||||
@@ -96,7 +96,7 @@ public class OneTimePasswordController {
|
||||
@RequestMapping(value = {"gen/counterbased"})
|
||||
public ModelAndView gencounterbased() {
|
||||
UserInfo userInfo = WebContext.getUserInfo();
|
||||
byte[] byteSharedSecret = OTPSecret.generate(keyUriFormat.getCrypto());
|
||||
byte[] byteSharedSecret = OtpSecret.generate(keyUriFormat.getCrypto());
|
||||
String sharedSecret = Base32Utils.encode(byteSharedSecret);
|
||||
sharedSecret = passwordReciprocal.encode(sharedSecret);
|
||||
userInfo.setSharedSecret(sharedSecret);
|
||||
@@ -128,7 +128,7 @@ public class OneTimePasswordController {
|
||||
@RequestMapping(value = {"gen/hotp"})
|
||||
public ModelAndView genhotp() {
|
||||
UserInfo userInfo = WebContext.getUserInfo();
|
||||
byte[] byteSharedSecret = OTPSecret.generate(keyUriFormat.getCrypto());
|
||||
byte[] byteSharedSecret = OtpSecret.generate(keyUriFormat.getCrypto());
|
||||
String sharedSecret = Base32Utils.encode(byteSharedSecret);
|
||||
sharedSecret = passwordReciprocal.encode(sharedSecret);
|
||||
userInfo.setSharedSecret(sharedSecret);
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="tfaOTPAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOTPAuthn">
|
||||
<bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn">
|
||||
<constructor-arg ref="jdbcTemplate" />
|
||||
</bean>
|
||||
|
||||
@@ -179,19 +179,6 @@
|
||||
</property>
|
||||
</bean> -->
|
||||
|
||||
<!-- Radius Server Realm
|
||||
<bean id="authenticationRealm" class="org.maxkey.web.authentication.realm.radius.RadiusServerAuthenticationRealm">
|
||||
<constructor-arg ref="jdbcTemplate"/>
|
||||
<property name="jradiusServers">
|
||||
<list>
|
||||
<bean id="radiusServer1" class="org.maxkey.web.authentication.realm.radius.RadiusServer">
|
||||
<property name="inetAddress" value="localhost"/>
|
||||
<property name="secret" value="test1234"/>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>-->
|
||||
|
||||
<!-- Default Realm-->
|
||||
<!-- realm use jdbc -->
|
||||
<bean id="authenticationRealm" class="org.maxkey.authn.realm.jdbc.JdbcAuthenticationRealm">
|
||||
|
||||
Reference in New Issue
Block a user