浏览代码

MFA Enhance

MFA  Enhance
shimingxy 5 年之前
父节点
当前提交
4b197b9c33

+ 39 - 43
docs/authn/fgpwd.md

@@ -27,10 +27,17 @@
 2、电子邮件 
 
 
-<h2>短信验证码</h2>
+<h2>短信认证</h2>
+
+配置maxkey中maxkey.properties
+
+<pre><code class="ini hljs">
+#SmsOtpAuthnYunxin SmsOtpAuthnAliyun SmsOtpAuthnTencentCloud
+config.otp.sms=SmsOtpAuthnYunxin
+</code></pre>
 
 <h3>腾讯云短信</h3>
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中maxkey.properties
 secretId 账号Appkey
 
 secretKey 密钥appSecret
@@ -41,19 +48,15 @@ templateId 短信模板ID
 
 sign 签名
 
-<pre><code class="xml hljs">
-&lt;bean id="tfaMobileOptAuthn" class="org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnTencentCloud"&gt;
-	&lt;property name="secretId" value="94395d754eb55693043f5d6a2b772ef4" /&gt;
-	&lt;property name="secretKey" value="05d5485357bc" /&gt;
-	&lt;property name="smsSdkAppid" value="1486220095" /&gt;
-	&lt;property name="templateId" value="14860095" /&gt;
-	&lt;property name="sign" value="1486009522" /&gt;
-&lt;/bean&gt;
-
+<pre><code class="ini hljs">
+config.otp.sms.aliyun.accesskeyid=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.aliyun.accesssecret=05d5485357bc
+config.otp.sms.aliyun.templatecode=14860095
+config.otp.sms.aliyun.signname=maxkey
 </code></pre>
 
 <h3>阿里云短信</h3>
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中maxkey.properties
 
 accessKeyId 账号Appkey
 
@@ -63,18 +66,16 @@ templateCode 短信模板ID
 
 signName 签名
 
-<pre><code class="xml hljs">
-&lt;bean id="tfaMobileOptAuthn" class="org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnAliyun"&gt;
-	&lt;property name="accessKeyId" value="94395d754eb55693043f5d6a2b772ef3" /&gt;
-	&lt;property name="accessSecret" value="05d5485357bc" /&gt;
-	&lt;property name="templateCode" value="SMS_187590021" /&gt;
-	&lt;property name="signName" value="MaxKey" /&gt;
-&lt;/bean&gt;
-
+<pre><code class="ini hljs">
+config.otp.sms.tencentcloud.secretid=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.tencentcloud.secretkey=05d5485357bc
+config.otp.sms.tencentcloud.smssdkappid=1486220095
+config.otp.sms.tencentcloud.templateid=14860095
+config.otp.sms.tencentcloud.sign=1486009522
 </code></pre>
 
 <h3>网易云信</h3>
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中maxkey.properties
 
 appKey 网易云信分配的账号Appkey
 
@@ -82,13 +83,10 @@ appSecret 网易云信分配的密钥appSecret
 
 templateId 短信模板ID
 
-<pre><code class="xml hljs">
-&lt;bean id="tfaMobileOptAuthn" class="org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnYunxin"&gt;
-	&lt;property name="appKey" value="94395d754eb55693043f5d6a2b772ef4" /&gt;
-	&lt;property name="appSecret" value="05d5485357bc" /&gt;
-	&lt;property name="templateId" value="14860095" /&gt;
-&lt;/bean&gt;
-
+<pre><code class="ini hljs">
+config.otp.sms.yunxin.appkey=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.yunxin.appsecret=05d5485357bc
+config.otp.sms.yunxin.templateid=14860095
 </code></pre>
 
 <h2>电子邮件</h2>
@@ -96,28 +94,26 @@ templateId 短信模板ID
 配置邮箱地址
 
 文件
-maxkey/config/applicationConfig.properties
+maxkey/application.properties
 
 <pre><code class="ini hljs">
-#  EMAIL configuration
-config.email.username=maxkey@163.com
-config.email.password=password
-config.email.smtpHost=smtp.163.com
-config.email.port=465
-config.email.senderMail=maxkey@163.com
-config.email.ssl=true
+spring.mail.default-encoding=utf-8
+spring.mail.host=smtp.163.com
+spring.mail.port=465
+spring.mail.username=maxkey@163.com
+spring.mail.password=password
+spring.mail.protocol=smtp
+spring.mail.properties.ssl=true
+spring.mail.properties.sender=maxkey@163.com
 </code></pre>
 
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中application.properties
 
 subject 邮件主题
 
 messageTemplate 邮件内容模板,请勿修改参数{0}为用户名,{1}认证码,{2}有效间隔
 
-<pre><code class="xml hljs">
-
-&lt;bean id="tfaMailOptAuthn" class="org.maxkey.crypto.password.opt.impl.MailOtpAuthn"&gt;
-	&lt;property name="subject" value="MaxKey One Time PassWord" /&gt;
-	&lt;property name="messageTemplate" value="{0} You Token is {1} , it validity in {2}  minutes." /&gt;
-&lt;/bean&gt;
+<pre><code class="ini hljs">
+spring.mail.properties.mailotp.message.subject=MaxKey One Time PassWord
+spring.mail.properties.mailotp.message.template={0} You Token is {1} , it validity in {2}  minutes.
 </code></pre>

+ 39 - 56
docs/authn/mfa.md

@@ -14,8 +14,16 @@
 
 <h2>短信认证</h2>
 
+配置maxkey中maxkey.properties
+
+<pre><code class="ini hljs">
+config.login.mfa=true
+#TimeBasedOtpAuthn MailOtpAuthn SmsOtpAuthnYunxin SmsOtpAuthnAliyun SmsOtpAuthnTencentCloud
+config.login.mfa.type=TimeBasedOtpAuthn
+</code></pre>
+
 <h3>腾讯云短信</h3>
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中maxkey.properties
 secretId 账号Appkey
 
 secretKey 密钥appSecret
@@ -26,23 +34,15 @@ templateId 短信模板ID
 
 sign 签名
 
-<pre><code class="xml hljs">
-&lt;!--
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn"&gt;
-&lt;/bean&gt;
---&gt;	
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnTencentCloud"&gt;
-	&lt;property name="secretId" value="94395d754eb55693043f5d6a2b772ef4" /&gt;
-	&lt;property name="secretKey" value="05d5485357bc" /&gt;
-	&lt;property name="smsSdkAppid" value="1486220095" /&gt;
-	&lt;property name="templateId" value="14860095" /&gt;
-	&lt;property name="sign" value="1486009522" /&gt;
-&lt;/bean&gt;
-
+<pre><code class="ini hljs">
+config.otp.sms.aliyun.accesskeyid=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.aliyun.accesssecret=05d5485357bc
+config.otp.sms.aliyun.templatecode=14860095
+config.otp.sms.aliyun.signname=maxkey
 </code></pre>
 
 <h3>阿里云短信</h3>
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中maxkey.properties
 
 accessKeyId 账号Appkey
 
@@ -52,22 +52,16 @@ templateCode 短信模板ID
 
 signName 签名
 
-<pre><code class="xml hljs">
-&lt;!--
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn"&gt;
-&lt;/bean&gt;
---&gt;	
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnAliyun"&gt;
-	&lt;property name="accessKeyId" value="94395d754eb55693043f5d6a2b772ef3" /&gt;
-	&lt;property name="accessSecret" value="05d5485357bc" /&gt;
-	&lt;property name="templateCode" value="SMS_187590021" /&gt;
-	&lt;property name="signName" value="MaxKey" /&gt;
-&lt;/bean&gt;
-
+<pre><code class="ini hljs">
+config.otp.sms.tencentcloud.secretid=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.tencentcloud.secretkey=05d5485357bc
+config.otp.sms.tencentcloud.smssdkappid=1486220095
+config.otp.sms.tencentcloud.templateid=14860095
+config.otp.sms.tencentcloud.sign=1486009522
 </code></pre>
 
 <h3>网易云信</h3>
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中maxkey.properties
 
 appKey 网易云信分配的账号Appkey
 
@@ -75,17 +69,10 @@ appSecret 网易云信分配的密钥appSecret
 
 templateId 短信模板ID
 
-<pre><code class="xml hljs">
-&lt;!--
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn"&gt;
-&lt;/bean&gt;
---&gt;	
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnYunxin"&gt;
-	&lt;property name="appKey" value="94395d754eb55693043f5d6a2b772ef4" /&gt;
-	&lt;property name="appSecret" value="05d5485357bc" /&gt;
-	&lt;property name="templateId" value="14860095" /&gt;
-&lt;/bean&gt;
-
+<pre><code class="ini hljs">
+config.otp.sms.yunxin.appkey=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.yunxin.appsecret=05d5485357bc
+config.otp.sms.yunxin.templateid=14860095
 </code></pre>
 
 <h2>电子邮件</h2>
@@ -93,31 +80,27 @@ templateId 短信模板ID
 配置邮箱地址
 
 文件
-maxkey/config/applicationConfig.properties
+maxkey/application.properties
 
 <pre><code class="ini hljs">
 #  EMAIL configuration
-config.email.username=maxkey@163.com
-config.email.password=password
-config.email.smtpHost=smtp.163.com
-config.email.port=465
-config.email.senderMail=maxkey@163.com
-config.email.ssl=true
+spring.mail.default-encoding=utf-8
+spring.mail.host=smtp.163.com
+spring.mail.port=465
+spring.mail.username=maxkey@163.com
+spring.mail.password=password
+spring.mail.protocol=smtp
+spring.mail.properties.ssl=true
+spring.mail.properties.sender=maxkey@163.com
 </code></pre>
 
-配置maxkey中spring/maxkey-security.xml
+配置maxkey中application.properties
 
 subject 邮件主题
 
 messageTemplate 邮件内容模板,请勿修改参数{0}为用户名,{1}认证码,{2}有效间隔
 
-<pre><code class="xml hljs">
-&lt;!--
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn"&gt;
-&lt;/bean&gt;
---&gt;	
-&lt;bean id="tfaOptAuthn" class="org.maxkey.crypto.password.opt.impl.MailOtpAuthn"&gt;
-	&lt;property name="subject" value="MaxKey One Time PassWord" /&gt;
-	&lt;property name="messageTemplate" value="{0} You Token is {1} , it validity in {2}  minutes." /&gt;
-&lt;/bean&gt;
+<pre><code class="ini hljs">
+spring.mail.properties.mailotp.message.subject=MaxKey One Time PassWord
+spring.mail.properties.mailotp.message.template={0} You Token is {1} , it validity in {2}  minutes.
 </code></pre>

+ 1 - 1
maxkey-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java

@@ -188,7 +188,7 @@ public abstract class AbstractAuthenticationProvider {
      */
     protected void tftcaptchaValid(String otpCaptcha, String authType, UserInfo userInfo) {
         // for one time password 2 factor
-        if (applicationConfig.getLoginConfig().isOneTimePwd() && authType.equalsIgnoreCase("tfa")) {
+        if (applicationConfig.getLoginConfig().isMfa() && authType.equalsIgnoreCase("tfa")) {
             UserInfo validUserInfo = new UserInfo();
             validUserInfo.setUsername(userInfo.getUsername());
             String sharedSecret = 

+ 11 - 11
maxkey-core/src/main/java/org/maxkey/config/LoginConfig.java

@@ -15,8 +15,8 @@ public class LoginConfig {
     @Value("${config.login.captcha.type:text}")
     String captchaType;
     
-    @Value("${config.login.onetimepwd}")
-    boolean oneTimePwd;
+    @Value("${config.login.mfa}")
+    boolean mfa;
     
     @Value("${config.login.socialsignon}")
     boolean socialSignOn;
@@ -48,14 +48,6 @@ public class LoginConfig {
         this.captcha = captcha;
     }
 
-    public boolean isOneTimePwd() {
-        return oneTimePwd;
-    }
-
-    public void setOneTimePwd(boolean oneTimePwd) {
-        this.oneTimePwd = oneTimePwd;
-    }
-
     public boolean isSocialSignOn() {
         return socialSignOn;
     }
@@ -72,6 +64,14 @@ public class LoginConfig {
         this.kerberos = kerberos;
     }
 
+    public boolean isMfa() {
+        return mfa;
+    }
+
+    public void setMfa(boolean mfa) {
+        this.mfa = mfa;
+    }
+
     public String getDefaultUri() {
         return defaultUri;
     }
@@ -109,7 +109,7 @@ public class LoginConfig {
         StringBuilder builder = new StringBuilder();
         builder
             .append("LoginConfig [captcha=").append(captcha)
-            .append(", oneTimePwd=").append(oneTimePwd)
+            .append(", mfa=").append(mfa)
             .append(", socialSignOn=").append(socialSignOn)
             .append(", kerberos=").append(kerberos)
             .append(", remeberMe=").append(remeberMe)

+ 26 - 2
maxkey-core/src/main/java/org/maxkey/crypto/password/opt/impl/SmsOtpAuthn.java

@@ -1,15 +1,26 @@
 package org.maxkey.crypto.password.opt.impl;
 
+import java.io.IOException;
+import java.util.Properties;
+import org.maxkey.constants.ConstantsProperties;
 import org.maxkey.crypto.password.opt.AbstractOptAuthn;
 import org.maxkey.domain.UserInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
 
 public class SmsOtpAuthn extends AbstractOptAuthn {
-
+    private static final  Logger logger = LoggerFactory.getLogger(SmsOtpAuthn.class);
+    
+    protected Properties properties;
+    
+    
     @Override
     public boolean produce(UserInfo userInfo) {
         String token = this.genToken(userInfo);
         // TODO:You must add send sms code here
-
+        logger.debug("send sms code" + token);
         return true;
     }
 
@@ -17,5 +28,18 @@ public class SmsOtpAuthn extends AbstractOptAuthn {
     public boolean validate(UserInfo userInfo, String token) {
         return true;
     }
+    
+    protected void loadProperties() throws IOException {
+        Resource resource = new ClassPathResource(
+                ConstantsProperties.classPathResource(
+                        ConstantsProperties.classPathResource(
+                                ConstantsProperties.maxKeyPropertySource)));
+        properties = new Properties();
+        properties.load(resource.getInputStream());
+    }
+    
+    public void initPropertys() {
+        
+    }
 
 }

+ 17 - 0
maxkey-core/src/main/java/org/maxkey/crypto/password/opt/impl/sms/SmsOtpAuthnAliyun.java

@@ -6,6 +6,9 @@ import com.aliyuncs.DefaultAcsClient;
 import com.aliyuncs.IAcsClient;
 import com.aliyuncs.http.MethodType;
 import com.aliyuncs.profile.DefaultProfile;
+
+import java.io.IOException;
+
 import org.maxkey.crypto.password.opt.impl.SmsOtpAuthn;
 import org.maxkey.domain.UserInfo;
 import org.slf4j.Logger;
@@ -110,4 +113,18 @@ public class SmsOtpAuthnAliyun extends SmsOtpAuthn {
         this.signName = signName;
     }
     
+    @Override
+    public void initPropertys() {
+        try {
+            this.loadProperties();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+        this.accessKeyId = this.properties.getProperty("config.otp.sms.aliyun.accesskeyid");
+        this.accessSecret = this.properties.getProperty("config.otp.sms.aliyun.accesssecret");
+        this.templateCode = this.properties.getProperty("config.otp.sms.aliyun.templatecode");
+        this.signName = this.properties.getProperty("config.otp.sms.aliyun.signname");
+    }
+    
 }

+ 18 - 0
maxkey-core/src/main/java/org/maxkey/crypto/password/opt/impl/sms/SmsOtpAuthnTencentCloud.java

@@ -6,6 +6,9 @@ import com.tencentcloudapi.common.profile.HttpProfile;
 import com.tencentcloudapi.sms.v20190711.SmsClient;
 import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
 import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
+
+import java.io.IOException;
+
 import org.maxkey.crypto.password.opt.impl.SmsOtpAuthn;
 import org.maxkey.domain.UserInfo;
 import org.slf4j.Logger;
@@ -153,4 +156,19 @@ public class SmsOtpAuthnTencentCloud extends SmsOtpAuthn {
         this.sign = sign;
     }
     
+    @Override
+    public void initPropertys() {
+        try {
+            this.loadProperties();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+        this.secretId = this.properties.getProperty("config.otp.sms.tencentcloud.secretid");
+        this.secretKey = this.properties.getProperty("config.otp.sms.tencentcloud.secretkey");
+        this.smsSdkAppid = this.properties.getProperty("config.otp.sms.tencentcloud.smssdkappid");
+        this.templateId = this.properties.getProperty("config.otp.sms.tencentcloud.templateid");
+        this.sign = this.properties.getProperty("config.otp.sms.tencentcloud.sign");
+    }
+    
 }

+ 14 - 0
maxkey-core/src/main/java/org/maxkey/crypto/password/opt/impl/sms/SmsOtpAuthnYunxin.java

@@ -1,5 +1,6 @@
 package org.maxkey.crypto.password.opt.impl.sms;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -184,6 +185,19 @@ public class SmsOtpAuthnYunxin extends SmsOtpAuthn {
         
     }
     
+    @Override
+    public void initPropertys() {
+        try {
+            this.loadProperties();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+        this.appKey = this.properties.getProperty("config.otp.sms.yunxin.appkey");
+        this.appSecret = this.properties.getProperty("config.otp.sms.yunxin.appsecret");
+        this.templateId = this.properties.getProperty("config.otp.sms.yunxin.templateid");
+    }
+    
     /**
      * main.
      * @param args String

+ 48 - 7
maxkey-web-maxkey/src/main/java/org/maxkey/MaxKeyConfig.java

@@ -16,10 +16,13 @@ import org.maxkey.authn.support.kerberos.KerberosProxy;
 import org.maxkey.authn.support.kerberos.RemoteKerberosService;
 import org.maxkey.authz.oauth2.provider.endpoint.TokenEndpointAuthenticationFilter;
 import org.maxkey.constants.ConstantsProperties;
+import org.maxkey.crypto.password.opt.AbstractOptAuthn;
 import org.maxkey.crypto.password.opt.algorithm.KeyUriFormat;
 import org.maxkey.crypto.password.opt.impl.MailOtpAuthn;
 import org.maxkey.crypto.password.opt.impl.SmsOtpAuthn;
 import org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn;
+import org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnAliyun;
+import org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnTencentCloud;
 import org.maxkey.crypto.password.opt.impl.sms.SmsOtpAuthnYunxin;
 import org.maxkey.persistence.ldap.ActiveDirectoryUtils;
 import org.maxkey.persistence.ldap.LdapUtils;
@@ -180,27 +183,65 @@ public class MaxKeyConfig  implements InitializingBean {
         return authenticationRealm;
     }
     
+    //default tfaOptAuthn
     @Bean(name = "tfaOptAuthn")
-    public TimeBasedOtpAuthn tfaOptAuthn() {
-        TimeBasedOtpAuthn tfaOptAuthn = new TimeBasedOtpAuthn();
-        _logger.debug("TimeBasedOtpAuthn inited.");
-        return tfaOptAuthn;
+    public AbstractOptAuthn tfaOptAuthn(
+            @Value("${config.login.mfa.type}")String mfaType) {    
+        
+        if(mfaType.equalsIgnoreCase("SmsOtpAuthnAliyun")) {
+            SmsOtpAuthnAliyun tfaOptAuthn = new SmsOtpAuthnAliyun();
+            tfaOptAuthn.initPropertys();
+            _logger.debug("SmsOtpAuthnAliyun inited.");
+            return tfaOptAuthn;
+        }else if(mfaType.equalsIgnoreCase("SmsOtpAuthnTencentCloud")) {
+            SmsOtpAuthnTencentCloud tfaOptAuthn = new SmsOtpAuthnTencentCloud();
+            tfaOptAuthn.initPropertys();
+            _logger.debug("SmsOtpAuthnTencentCloud inited.");
+            return tfaOptAuthn;
+        }else if(mfaType.equalsIgnoreCase("SmsOtpAuthnYunxin")) {
+            SmsOtpAuthnYunxin tfaOptAuthn = new SmsOtpAuthnYunxin();
+            tfaOptAuthn.initPropertys();
+            _logger.debug("SmsOtpAuthnYunxin inited.");
+            return tfaOptAuthn;
+        }else {
+            TimeBasedOtpAuthn tfaOptAuthn = new TimeBasedOtpAuthn();
+            _logger.debug("TimeBasedOtpAuthn inited.");
+            return tfaOptAuthn;
+        }
     }
     
     @Bean(name = "tfaMailOptAuthn")
-    public MailOtpAuthn mailOtpAuthn() {
+    public MailOtpAuthn mailOtpAuthn(
+            @Value("${spring.mail.properties.mailotp.message.subject}")
+            String messageSubject,
+            @Value("${spring.mail.properties.mailotp.message.template}")
+            String messageTemplate
+            ) {
         MailOtpAuthn mailOtpAuthn = new MailOtpAuthn();
+        mailOtpAuthn.setSubject(messageSubject);
+        mailOtpAuthn.setMessageTemplate(messageTemplate);
         _logger.debug("tfaMailOptAuthn inited.");
         return mailOtpAuthn;
     }
     
     @Bean(name = "tfaMobileOptAuthn")
-    public SmsOtpAuthn smsOtpAuthn() {
-        SmsOtpAuthnYunxin smsOtpAuthn = new SmsOtpAuthnYunxin();
+    public SmsOtpAuthn smsOtpAuthn(@Value("${config.otp.sms}")String optSmsProvider) {
+        SmsOtpAuthn smsOtpAuthn = null;
+        
+        if(optSmsProvider.equalsIgnoreCase("SmsOtpAuthnAliyun")) {
+            smsOtpAuthn = new SmsOtpAuthnAliyun();
+        }else if(optSmsProvider.equalsIgnoreCase("SmsOtpAuthnTencentCloud")) {
+            smsOtpAuthn = new SmsOtpAuthnTencentCloud();
+        }else {
+            smsOtpAuthn = new SmsOtpAuthnYunxin();
+        }
+        smsOtpAuthn.initPropertys();
+        
         _logger.debug("SmsOtpAuthn inited.");
         return smsOtpAuthn;
     }
     
+    
     @Bean(name = "kerberosService")
     public RemoteKerberosService kerberosService(
             @Value("${config.support.kerberos.default.userdomain}")

+ 2 - 2
maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LoginEndpoint.java

@@ -128,8 +128,8 @@ public class LoginEndpoint {
 		if(!isAuthenticated){
 			modelAndView.addObject("isRemeberMe", applicationConfig.getLoginConfig().isRemeberMe());
 			modelAndView.addObject("isKerberos", applicationConfig.getLoginConfig().isKerberos());
-			modelAndView.addObject("isOneTimePwd", applicationConfig.getLoginConfig().isOneTimePwd());
-			if(applicationConfig.getLoginConfig().isOneTimePwd()) {
+			modelAndView.addObject("isMfa", applicationConfig.getLoginConfig().isMfa());
+			if(applicationConfig.getLoginConfig().isMfa()) {
 			    modelAndView.addObject("optType", tfaOptAuthn.getOptType());
 			    modelAndView.addObject("optInterval", tfaOptAuthn.getInterval());
 			}

+ 2 - 0
maxkey-web-maxkey/src/main/resources/application.properties

@@ -49,6 +49,8 @@ spring.mail.password=password
 spring.mail.protocol=smtp
 spring.mail.properties.ssl=true
 spring.mail.properties.sender=maxkey@163.com
+spring.mail.properties.mailotp.message.subject=MaxKey One Time PassWord
+spring.mail.properties.mailotp.message.template={0} You Token is {1} , it validity in {2}  minutes.
 #for freemarker
 spring.freemarker.template-loader-path=classpath:/templates/views
 spring.freemarker.cache=false

+ 21 - 1
maxkey-web-maxkey/src/main/resources/maxkey.properties

@@ -19,7 +19,9 @@ config.login.captcha=true
 #text or arithmetic
 config.login.captcha.type=text
 #enable two factor,use one time password
-config.login.onetimepwd=true
+config.login.mfa=true
+#TimeBasedOtpAuthn MailOtpAuthn SmsOtpAuthnYunxin SmsOtpAuthnAliyun SmsOtpAuthnTencentCloud
+config.login.mfa.type=TimeBasedOtpAuthn
 #enable social sign on
 config.login.socialsignon=true
 #social sign on providers
@@ -38,6 +40,24 @@ config.login.default.uri=appList
 
 config.ipaddress.whitelist=false
 
+#SmsOtpAuthnYunxin SmsOtpAuthnAliyun SmsOtpAuthnTencentCloud
+config.otp.sms=SmsOtpAuthnYunxin
+
+config.otp.sms.aliyun.accesskeyid=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.aliyun.accesssecret=05d5485357bc
+config.otp.sms.aliyun.templatecode=14860095
+config.otp.sms.aliyun.signname=maxkey
+
+config.otp.sms.yunxin.appkey=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.yunxin.appsecret=05d5485357bc
+config.otp.sms.yunxin.templateid=14860095
+
+config.otp.sms.tencentcloud.secretid=94395d754eb55693043f5d6a2b772ef4
+config.otp.sms.tencentcloud.secretkey=05d5485357bc
+config.otp.sms.tencentcloud.smssdkappid=1486220095
+config.otp.sms.tencentcloud.templateid=14860095
+config.otp.sms.tencentcloud.sign=1486009522
+
 config.otp.keyuri.format.type=totp
 config.otp.keyuri.format.digits=6
 config.otp.keyuri.format.issuer=MaxKey

+ 3 - 3
maxkey-web-maxkey/src/main/resources/templates/views/login.ftl

@@ -54,7 +54,7 @@ function formatTime(){
 	strTime+=(seconds<10?"0"+seconds:seconds);
 }
 
-<#if true==isOneTimePwd && "TOPT"==optType>
+<#if true==isMfa && "TOPT"==optType>
 function currentTime(){
 	seconds++;
 	if(seconds>59){
@@ -119,7 +119,7 @@ document.onkeydown=function(event){
 };
 	
 $(function(){
-	<#if true==isOneTimePwd && "TOPT"==optType>
+	<#if true==isMfa && "TOPT"==optType>
 	setInterval("currentTime()", 1000);
 	</#if>
 	<#--on captcha image click ,new a captcha code-->
@@ -261,7 +261,7 @@ $(function(){
 								<td><@locale code="login.text.password"/>:</td>
 								<td><input required="" class="form-control"  type='password' id='tfa_j_password'  name='password' value=""  tabindex="2" /></td>
 							</tr>
-							<#if true==isOneTimePwd >
+							<#if true==isMfa >
 							<#if "TOPT"==optType >
 							<tr>
 								<td><@locale code="login.text.currenttime"/>:</td>