mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-08 00:50:28 +08:00
feat: support Radius Challenge/Response for MFA (RFC2865) feature request (#3093)
* feat: support RFC2865 for radius server when user enable TOTP mfa * fix: fix linter err
This commit is contained in:
@ -18,6 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@ -27,6 +28,14 @@ import (
|
|||||||
"layeh.com/radius/rfc2866"
|
"layeh.com/radius/rfc2866"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var StateMap map[string]AccessStateContent
|
||||||
|
|
||||||
|
const StateExpiredTime = time.Second * 120
|
||||||
|
|
||||||
|
type AccessStateContent struct {
|
||||||
|
ExpiredAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
func StartRadiusServer() {
|
func StartRadiusServer() {
|
||||||
secret := conf.GetConfigString("radiusSecret")
|
secret := conf.GetConfigString("radiusSecret")
|
||||||
server := radius.PacketServer{
|
server := radius.PacketServer{
|
||||||
@ -55,6 +64,7 @@ func handleAccessRequest(w radius.ResponseWriter, r *radius.Request) {
|
|||||||
username := rfc2865.UserName_GetString(r.Packet)
|
username := rfc2865.UserName_GetString(r.Packet)
|
||||||
password := rfc2865.UserPassword_GetString(r.Packet)
|
password := rfc2865.UserPassword_GetString(r.Packet)
|
||||||
organization := rfc2865.Class_GetString(r.Packet)
|
organization := rfc2865.Class_GetString(r.Packet)
|
||||||
|
state := rfc2865.State_GetString(r.Packet)
|
||||||
log.Printf("handleAccessRequest() username=%v, org=%v, password=%v", username, organization, password)
|
log.Printf("handleAccessRequest() username=%v, org=%v, password=%v", username, organization, password)
|
||||||
|
|
||||||
if organization == "" {
|
if organization == "" {
|
||||||
@ -62,12 +72,75 @@ func handleAccessRequest(w radius.ResponseWriter, r *radius.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := object.CheckUserPassword(organization, username, password, "en")
|
var user *object.User
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if state == "" {
|
||||||
|
user, err = object.CheckUserPassword(organization, username, password, "en")
|
||||||
|
} else {
|
||||||
|
user, err = object.GetUser(fmt.Sprintf("%s/%s", organization, username))
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Write(r.Response(radius.CodeAccessReject))
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.IsMfaEnabled() {
|
||||||
|
mfaProp := user.GetMfaProps(object.TotpType, false)
|
||||||
|
if mfaProp == nil {
|
||||||
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if StateMap == nil {
|
||||||
|
StateMap = map[string]AccessStateContent{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if state != "" {
|
||||||
|
stateContent, ok := StateMap[state]
|
||||||
|
if !ok {
|
||||||
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(StateMap, state)
|
||||||
|
if stateContent.ExpiredAt.Before(time.Now()) {
|
||||||
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mfaUtil := object.GetMfaUtil(mfaProp.MfaType, mfaProp)
|
||||||
|
if mfaUtil.Verify(password) != nil {
|
||||||
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(r.Response(radius.CodeAccessAccept))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
responseState := util.GenerateId()
|
||||||
|
StateMap[responseState] = AccessStateContent{
|
||||||
|
time.Now().Add(StateExpiredTime),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rfc2865.State_Set(r.Packet, []byte(responseState))
|
||||||
|
if err != nil {
|
||||||
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rfc2865.ReplyMessage_Set(r.Packet, []byte("please enter OTP"))
|
||||||
|
if err != nil {
|
||||||
|
w.Write(r.Response(radius.CodeAccessReject))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Packet.Code = radius.CodeAccessChallenge
|
||||||
|
w.Write(r.Packet)
|
||||||
|
}
|
||||||
|
|
||||||
w.Write(r.Response(radius.CodeAccessAccept))
|
w.Write(r.Response(radius.CodeAccessAccept))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user