From ff60f05a3100d86a5f910cd48c4585515aee595e Mon Sep 17 00:00:00 2001 From: JHong Date: Sat, 28 Jan 2023 15:29:19 +0800 Subject: [PATCH 1/2] Add Basic TOTP Authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 老哥你好,我是中山大学这边的,因为我们学校的easyconnect要求二步验证,所以我把手机2fa的功能简单的写了一下,交一个pull request给你w。我这边在中大sslvpn测试是正常的。 另外就是初次绑定的话我没做,需要用sxf自己的客户端绑定好验证器之后,才可以在这里用2fa登录。谢谢,祝好 --- core/EasyConnectClient.go | 13 +++++++++++ core/web_login.go | 45 +++++++++++++++++++++++++++++++++++++++ main.go | 8 ++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/core/EasyConnectClient.go b/core/EasyConnectClient.go index a20aced..275a556 100644 --- a/core/EasyConnectClient.go +++ b/core/EasyConnectClient.go @@ -56,6 +56,19 @@ func (client *EasyConnectClient) AuthSMSCode(code string) ([]byte, error) { return client.LoginByTwfId(twfId) } +func (client *EasyConnectClient) AuthTOTP(code string) ([]byte, error) { + if client.twfId == "" { + return nil, errors.New("TOTP Auth not required") + } + + twfId, err := TOTPAuth(client.server, client.username, client.password, client.twfId, code) + if err != nil { + return nil, err + } + + return client.LoginByTwfId(twfId) +} + func (client *EasyConnectClient) LoginByTwfId(twfId string) ([]byte, error) { agentToken, err := ECAgentToken(client.server, twfId) if err != nil { diff --git a/core/web_login.go b/core/web_login.go index 98f8afa..a56205c 100644 --- a/core/web_login.go +++ b/core/web_login.go @@ -21,6 +21,7 @@ import ( ) var ERR_NEXT_AUTH_SMS = errors.New("SMS Code required.") +var ERR_NEXT_AUTH_TOTP = errors.New("Current usee's TOTP is binded.") func WebLogin(server string, username string, password string) (string, error) { server = "https://" + server @@ -138,6 +139,12 @@ func WebLogin(server string, username string, password string) (string, error) { return twfId, ERR_NEXT_AUTH_SMS } + // TOTP Authnication Process (Edited by JHong) + if strings.Contains(string(buf[:n]), "auth/token") || strings.Contains(string(buf[:n]), "totp") || strings.Contains(string(buf[:n]), "2") { + log.Print("TOTP Authnication required.") + return twfId, ERR_NEXT_AUTH_TOTP + } + if strings.Contains(string(buf[:n]), "-1") || !strings.Contains(string(buf[:n]), "") { log.Print("No NextAuth found.") } else { @@ -198,6 +205,44 @@ func AuthSms(server string, username string, password string, twfId string, smsC return twfId, nil } +// JHong Implementing....... +func TOTPAuth(server string, username string, password string, twfId string, TOTPCode string) (string, error) { + c := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }} + + buf := make([]byte, 40960) + + addr := "https://" + server + "/por/login_token.csp" + log.Printf("TOTP token Request: " + addr) + form := url.Values{ + "svpn_inputtoken": {TOTPCode}, + } + + req, err := http.NewRequest("POST", addr, strings.NewReader(form.Encode())) + req.Header.Set("Cookie", "TWFID="+twfId) + + resp, err := c.Do(req) + if err != nil { + debug.PrintStack() + return "", err + } + + n, _ := resp.Body.Read(buf) + defer resp.Body.Close() + + if !strings.Contains(string(buf[:n]), "suc") { + debug.PrintStack() + return "", errors.New("TOTP token verification FAILED: " + string(buf[:n])) + } + + twfId = string(regexp.MustCompile(`(.*)`).FindSubmatch(buf[:n])[1]) + log.Print("TOTP verification SUCCESS") + + return twfId, nil +} + func ECAgentToken(server string, twfId string) (string, error) { dialConn, err := net.Dial("tcp", server) defer dialConn.Close() diff --git a/main.go b/main.go index e9a76d3..fc5948d 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( func main() { // CLI args host, port, username, password, socksBind, twfId := "", 0, "", "", "", "" - flag.StringVar(&host, "server", "", "EasyConnect server address (e.g. vpn.nju.edu.cn)") + flag.StringVar(&host, "server", "", "EasyConnect server address (e.g. vpn.nju.edu.cn, sslvpn.sysu.edu.cn)") flag.StringVar(&username, "username", "", "Your username") flag.StringVar(&password, "password", "", "Your password") flag.StringVar(&socksBind, "socks-bind", ":1080", "The addr socks5 server listens on (e.g. 0.0.0.0:1080)") @@ -43,6 +43,12 @@ func main() { fmt.Scan(&smsCode) ip, err = client.AuthSMSCode(smsCode) + } else if err == core.ERR_NEXT_AUTH_TOTP { + fmt.Print(">>>Please enter your TOTP Auth code<<<:") + TOTPCode := "" + fmt.Scan(&TOTPCode) + + ip, err = client.AuthTOTP(TOTPCode) } } From 81319fde97262c548fcf430d0b6904f2a71348da Mon Sep 17 00:00:00 2001 From: lyc8503 <36782264+lyc8503@users.noreply.github.com> Date: Sat, 28 Jan 2023 17:19:38 +0800 Subject: [PATCH 2/2] Update web_login.go --- core/web_login.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/web_login.go b/core/web_login.go index a56205c..999c8d1 100644 --- a/core/web_login.go +++ b/core/web_login.go @@ -20,8 +20,8 @@ import ( utls "github.com/refraction-networking/utls" ) -var ERR_NEXT_AUTH_SMS = errors.New("SMS Code required.") -var ERR_NEXT_AUTH_TOTP = errors.New("Current usee's TOTP is binded.") +var ERR_NEXT_AUTH_SMS = errors.New("SMS Code required") +var ERR_NEXT_AUTH_TOTP = errors.New("Current user's TOTP bound") func WebLogin(server string, username string, password string) (string, error) { server = "https://" + server @@ -140,7 +140,7 @@ func WebLogin(server string, username string, password string) (string, error) { } // TOTP Authnication Process (Edited by JHong) - if strings.Contains(string(buf[:n]), "auth/token") || strings.Contains(string(buf[:n]), "totp") || strings.Contains(string(buf[:n]), "2") { + if strings.Contains(string(buf[:n]), "auth/token") || strings.Contains(string(buf[:n]), "totp") { log.Print("TOTP Authnication required.") return twfId, ERR_NEXT_AUTH_TOTP }