Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
符节科技
Jap
提交
3e578642
Jap
项目概览
符节科技
/
Jap
10 个月 前同步成功
通知
91
Star
3
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Jap
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
3e578642
编写于
2月 06, 2021
作者:
智布道
👁
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
⚡
jap-mfa, Time based one-time password (TOTP)
上级
85bcc926
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
498 addition
and
0 deletion
+498
-0
jap-mfa/pom.xml
jap-mfa/pom.xml
+32
-0
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfa.java
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfa.java
+174
-0
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfaAlgorithm.java
...fa/src/main/java/com/fujieid/jap/sso/JapMfaAlgorithm.java
+25
-0
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfaConfig.java
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfaConfig.java
+113
-0
jap-mfa/src/main/java/com/fujieid/jap/sso/package-info.java
jap-mfa/src/main/java/com/fujieid/jap/sso/package-info.java
+23
-0
jap-mfa/src/test/java/com/fujieid/jap/sso/CredentialRepositoryImpl.java
...st/java/com/fujieid/jap/sso/CredentialRepositoryImpl.java
+40
-0
jap-mfa/src/test/java/com/fujieid/jap/sso/JapMfaTest.java
jap-mfa/src/test/java/com/fujieid/jap/sso/JapMfaTest.java
+90
-0
pom.xml
pom.xml
+1
-0
未找到文件。
jap-mfa/pom.xml
0 → 100644
浏览文件 @
3e578642
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns=
"http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<artifactId>
jap
</artifactId>
<groupId>
com.fujieid
</groupId>
<version>
1.0.0-alpha.1
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
jap-mfa
</artifactId>
<name>
jap-mfa
</name>
<description>
Time based one-time password (TOTP), which is suitable for Google authenticator and TOTP authenticator of binary
boot
</description>
<dependencies>
<dependency>
<groupId>
com.google.zxing
</groupId>
<artifactId>
core
</artifactId>
<version>
3.3.3
</version>
</dependency>
<dependency>
<groupId>
com.warrenstrange
</groupId>
<artifactId>
googleauth
</artifactId>
<version>
1.4.0
</version>
</dependency>
</dependencies>
</project>
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfa.java
0 → 100644
浏览文件 @
3e578642
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.fujieid.jap.sso
;
import
cn.hutool.core.img.ImgUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.extra.qrcode.QrCodeUtil
;
import
cn.hutool.log.Log
;
import
cn.hutool.log.LogFactory
;
import
com.warrenstrange.googleauth.*
;
import
javax.servlet.http.HttpServletResponse
;
import
java.awt.*
;
import
java.io.File
;
import
java.io.IOException
;
/**
* Jap Multi-Factor Authenticator
* <p>
* Time based one-time password (TOTP)
* <p>
* https://tools.ietf.org/html/rfc6238
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.0.0
*/
public
class
JapMfa
{
private
static
final
Log
log
=
LogFactory
.
get
();
private
final
GoogleAuthenticator
authenticator
;
private
final
JapMfaConfig
mfaConfig
;
public
JapMfa
(
ICredentialRepository
credentialRepository
,
JapMfaConfig
mfaConfig
)
{
this
.
mfaConfig
=
mfaConfig
;
this
.
authenticator
=
new
GoogleAuthenticator
(
new
GoogleAuthenticatorConfig
.
GoogleAuthenticatorConfigBuilder
()
.
setCodeDigits
(
mfaConfig
.
getDigits
())
.
setTimeStepSizeInMillis
(
mfaConfig
.
getPeriod
())
.
setHmacHashFunction
(
HmacHashFunction
.
valueOf
(
mfaConfig
.
getAlgorithm
().
name
()))
.
build
());
authenticator
.
setCredentialRepository
(
credentialRepository
);
}
public
JapMfa
(
ICredentialRepository
credentialRepository
)
{
this
(
credentialRepository
,
new
JapMfaConfig
());
}
public
GoogleAuthenticator
getAuthenticator
()
{
return
authenticator
;
}
public
String
getSecretKey
(
String
username
)
{
return
authenticator
.
getCredentialRepository
().
getSecretKey
(
username
);
}
/**
* Returns the URL of totp
*
* @param username The user name
* @param issuer The issuer name. This parameter cannot contain the colon (:) character.
* @return {@code String}
*/
public
String
getTotpUrl
(
String
username
,
String
issuer
)
{
final
GoogleAuthenticatorKey
key
=
authenticator
.
createCredentials
(
username
);
return
GoogleAuthenticatorQRGenerator
.
getOtpAuthTotpURL
(
issuer
,
username
,
key
);
}
/**
* Returns the URL of a Google Chart API call to generate a QR barcode to be loaded into the Google Authenticator application.
* <p>
* The user scans this bar code with the application on their smart phones or enters the secret manually.
*
* @param username The user name
* @param issuer The issuer name. This parameter cannot contain the colon (:) character.
* @return {@code String}
*/
public
String
getOtpQrCodeUrl
(
String
username
,
String
issuer
)
{
final
GoogleAuthenticatorKey
key
=
authenticator
.
createCredentials
(
username
);
return
GoogleAuthenticatorQRGenerator
.
getOtpAuthURL
(
issuer
,
username
,
key
);
}
/**
* One time password verification by user name
*
* @param username The user name
* @param otpCode The totp code
* @return {@code bool}
*/
public
boolean
verifyByUsername
(
String
username
,
int
otpCode
)
{
return
authenticator
.
authorizeUser
(
username
,
otpCode
);
}
/**
* One time password verification by OTP secret key
*
* @param secret The totp secret Key.
* @param otpCode The totp code
* @return {@code bool}
*/
public
boolean
verifyBySecret
(
String
secret
,
int
otpCode
)
{
return
authenticator
.
authorize
(
secret
,
otpCode
);
}
/**
* Create OTP QR code and write it to browser through {@code HttpServletResponse}
*
* @param username The user name
* @param issuer The issuer name. This parameter cannot contain the colon (:) character.
* @param response HttpServletResponse
*/
public
void
createOtpQrcode
(
String
username
,
String
issuer
,
HttpServletResponse
response
)
{
try
{
QrCodeUtil
.
generate
(
getTotpUrl
(
username
,
issuer
),
mfaConfig
.
getQrcodeWidth
(),
mfaConfig
.
getQrcodeHeight
(),
mfaConfig
.
getQrcodeImgType
(),
response
.
getOutputStream
());
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Create and return the QR code file of OTP
*
* @param username The user name
* @param issuer The issuer name. This parameter cannot contain the colon (:) character.
*/
public
File
getOtpQrcodeFile
(
String
username
,
String
issuer
)
{
String
tempFilePath
=
mfaConfig
.
getQrcodeTempPath
();
String
tempFileFullPath
=
tempFilePath
.
concat
(
username
)
.
concat
(
String
.
valueOf
(
System
.
currentTimeMillis
()))
.
concat
(
"."
)
.
concat
(
mfaConfig
.
getQrcodeImgType
());
log
.
debug
(
"Create QR code: {}"
,
tempFileFullPath
);
File
file
=
FileUtil
.
newFile
(
tempFileFullPath
);
if
(
FileUtil
.
exist
(
file
))
{
FileUtil
.
del
(
file
);
}
else
{
FileUtil
.
mkParentDirs
(
file
);
}
return
QrCodeUtil
.
generate
(
getTotpUrl
(
username
,
issuer
),
mfaConfig
.
getQrcodeWidth
(),
mfaConfig
.
getQrcodeHeight
(),
file
);
}
/**
* Create and return the base64 string of OTP QR code
*
* @param username The user name
* @param issuer The issuer name. This parameter cannot contain the colon (:) character.
* @param deleteFile Delete temporary QR code file
*/
public
String
getOtpQrcodeFileBase64
(
String
username
,
String
issuer
,
boolean
deleteFile
)
{
File
imgFile
=
this
.
getOtpQrcodeFile
(
username
,
issuer
);
Image
image
=
ImgUtil
.
read
(
imgFile
);
String
base64Str
=
ImgUtil
.
toBase64DataUri
(
image
,
mfaConfig
.
getQrcodeImgType
());
if
(
deleteFile
)
{
FileUtil
.
del
(
imgFile
);
}
return
base64Str
;
}
}
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfaAlgorithm.java
0 → 100644
浏览文件 @
3e578642
package
com.fujieid.jap.sso
;
/**
* The cryptographic hash function used to calculate the HMAC (Hash-based Message Authentication Code).
* <p>
* This implementation uses the SHA1 hash function by default.
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.0.0
*/
public
enum
JapMfaAlgorithm
{
/**
* SHA1
*/
HmacSHA1
,
/**
* SHA256
*/
HmacSHA256
,
/**
* SHA512
*/
HmacSHA512
}
jap-mfa/src/main/java/com/fujieid/jap/sso/JapMfaConfig.java
0 → 100644
浏览文件 @
3e578642
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.fujieid.jap.sso
;
import
java.io.File
;
/**
* Multi-Factor Authenticator Configuration
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.0.0
*/
public
class
JapMfaConfig
{
/**
* the number of digits in the generated code.
*/
private
int
digits
=
6
;
/**
* the time step size, in milliseconds, as specified by RFC 6238. The default value is 30.000s.
*
* @see <a href="https://tools.ietf.org/html/rfc6238#section-5.2" target="_blank">5.2. Validation and Time-Step Size</a>
*/
private
long
period
=
30000
;
/**
* the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512)
*/
private
JapMfaAlgorithm
algorithm
=
JapMfaAlgorithm
.
HmacSHA1
;
private
String
qrcodeTempPath
=
System
.
getProperties
().
getProperty
(
"user.home"
)
+
File
.
separator
+
"jap"
+
File
.
separator
+
"temp"
;
private
int
qrcodeWidth
=
200
;
private
int
qrcodeHeight
=
200
;
private
String
qrcodeImgType
=
"gif"
;
public
int
getDigits
()
{
return
digits
;
}
public
JapMfaConfig
setDigits
(
int
digits
)
{
this
.
digits
=
digits
;
return
this
;
}
public
long
getPeriod
()
{
return
period
;
}
public
JapMfaConfig
setPeriod
(
long
period
)
{
this
.
period
=
period
;
return
this
;
}
public
JapMfaAlgorithm
getAlgorithm
()
{
return
algorithm
;
}
public
JapMfaConfig
setAlgorithm
(
JapMfaAlgorithm
algorithm
)
{
this
.
algorithm
=
algorithm
;
return
this
;
}
public
String
getQrcodeTempPath
()
{
return
qrcodeTempPath
;
}
public
JapMfaConfig
setQrcodeTempPath
(
String
qrcodeTempPath
)
{
this
.
qrcodeTempPath
=
qrcodeTempPath
;
return
this
;
}
public
int
getQrcodeWidth
()
{
return
qrcodeWidth
;
}
public
JapMfaConfig
setQrcodeWidth
(
int
qrcodeWidth
)
{
this
.
qrcodeWidth
=
qrcodeWidth
;
return
this
;
}
public
int
getQrcodeHeight
()
{
return
qrcodeHeight
;
}
public
JapMfaConfig
setQrcodeHeight
(
int
qrcodeHeight
)
{
this
.
qrcodeHeight
=
qrcodeHeight
;
return
this
;
}
public
String
getQrcodeImgType
()
{
return
qrcodeImgType
;
}
public
JapMfaConfig
setQrcodeImgType
(
String
qrcodeImgType
)
{
this
.
qrcodeImgType
=
qrcodeImgType
;
return
this
;
}
}
jap-mfa/src/main/java/com/fujieid/jap/sso/package-info.java
0 → 100644
浏览文件 @
3e578642
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Time based one-time password (TOTP), which is suitable for Google authenticator and TOTP authenticator of binary boot
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.0.0
*/
package
com.fujieid.jap.sso
;
jap-mfa/src/test/java/com/fujieid/jap/sso/CredentialRepositoryImpl.java
0 → 100644
浏览文件 @
3e578642
package
com.fujieid.jap.sso
;
import
com.warrenstrange.googleauth.ICredentialRepository
;
import
java.util.List
;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.0.0
*/
public
class
CredentialRepositoryImpl
implements
ICredentialRepository
{
public
CredentialRepositoryImpl
(){
}
/**
* This method retrieves the Base32-encoded private key of the given user.
*
* @param userName the user whose private key shall be retrieved.
* @return the private key of the specified user.
*/
@Override
public
String
getSecretKey
(
String
userName
)
{
return
null
;
}
/**
* This method saves the user credentials.
*
* @param userName the user whose data shall be saved.
* @param secretKey the generated key.
* @param validationCode the validation code.
* @param scratchCodes the list of scratch codes.
*/
@Override
public
void
saveUserCredentials
(
String
userName
,
String
secretKey
,
int
validationCode
,
List
<
Integer
>
scratchCodes
)
{
}
}
jap-mfa/src/test/java/com/fujieid/jap/sso/JapMfaTest.java
0 → 100644
浏览文件 @
3e578642
/*
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.fujieid.jap.sso
;
import
com.warrenstrange.googleauth.ICredentialRepository
;
import
java.io.File
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Scanner
;
public
class
JapMfaTest
{
public
static
final
String
username
=
"japname"
;
public
static
final
String
issuer
=
"japissue"
;
public
static
void
main
(
String
[]
args
)
{
JapMfa
japMfa
=
new
JapMfa
(
new
CredentialRepositoryImpl
());
// 以下三种方式,任选一个测试
// 1. 生成 file
// File file = japMfa.createOtpQrcodeFile(username, issuer);
// System.out.println(file);
// 生成 base64 字符串
// String base64 = japMfa.createOtpQrcodeFileBase64(username, issuer, "qrcode.png", true);
// System.out.println(base64);
// 生成 url 链接
String
otpQrCodeUrl
=
japMfa
.
getOtpQrCodeUrl
(
username
,
issuer
);
System
.
out
.
println
(
otpQrCodeUrl
);
varifyCode
(
japMfa
);
}
private
static
void
varifyCode
(
JapMfa
japMfa
)
{
String
secretKey
=
japMfa
.
getSecretKey
(
username
);
System
.
out
.
println
(
"1. 你需要打开生成的文件(或者将 Base64 字符串直接粘贴到浏览器地址会回车)"
);
System
.
out
.
println
(
"2. 然后使用 OTP 工具扫描二维码"
);
System
.
out
.
println
(
"3. 在控制台输入 code"
);
Scanner
scanner
=
new
Scanner
(
System
.
in
);
Integer
consoleInput
=
null
;
while
(!(
consoleInput
=
scanner
.
nextInt
()).
equals
(-
1
))
{
System
.
out
.
println
(
japMfa
.
getAuthenticator
().
getTotpPassword
(
secretKey
));
System
.
out
.
println
(
japMfa
.
getAuthenticator
().
getTotpPasswordOfUser
(
username
));
boolean
verifyByUsernameResult
=
japMfa
.
verifyByUsername
(
username
,
consoleInput
);
System
.
out
.
println
(
new
Date
()
+
" 通过用户名检验 code 的结果:"
+
(
verifyByUsernameResult
?
"通过"
:
"code 错误"
));
boolean
verifyBySecretResult
=
japMfa
.
verifyBySecret
(
secretKey
,
consoleInput
);
System
.
out
.
println
(
new
Date
()
+
" 通过 secretKey 检验 code 的结果:"
+
(
verifyBySecretResult
?
"通过"
:
"code 错误"
));
}
System
.
out
.
println
(
"结束..."
);
}
public
static
class
CredentialRepositoryImpl
implements
ICredentialRepository
{
public
static
String
secret
=
""
;
@Override
public
String
getSecretKey
(
String
userName
)
{
//根据帐号查询secretKey
return
secret
;
}
@Override
public
void
saveUserCredentials
(
String
userName
,
String
secretKey
,
int
validationCode
,
List
<
Integer
>
scratchCodes
)
{
// secretKey要保存在数据库中
System
.
out
.
println
(
"[saveUserCredentials] userName:"
+
userName
);
System
.
out
.
println
(
"[saveUserCredentials] secretKey:"
+
secretKey
);
System
.
out
.
println
(
"[saveUserCredentials] validationCode:"
+
validationCode
);
secret
=
secretKey
;
}
}
}
pom.xml
浏览文件 @
3e578642
...
...
@@ -45,6 +45,7 @@
<module>
jap-oauth2
</module>
<module>
jap-sso
</module>
<module>
jap-oidc
</module>
<module>
jap-mfa
</module>
</modules>
<properties>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录