1 Star 0 Fork 0

lqinggang/psiphon-tunnel-core

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
ClientLibrary
ConsoleClient
MobileLibrary
Server
contributors
psiphon
common
memory_test
server
testdata
transferstats
upstreamproxy
go-ntlm
README.md
auth_basic.go
auth_digest.go
auth_ntlm.go
http_authenticator.go
proxy_http.go
proxy_socks4.go
transport_proxy_auth.go
upstreamproxy.go
LookupIP.go
LookupIP_nobind.go
TCPConn.go
TCPConn_bind.go
TCPConn_nobind.go
UDPConn.go
UDPConn_bind.go
UDPConn_nobind.go
config.go
config_test.go
controller.go
controller_test.config.enc
controller_test.go
dataStore.go
dataStore_badger.go
dataStore_bolt.go
dataStore_files.go
dialParameters.go
dialParameters_test.go
feedback.go
feedback_test.config.enc
feedback_test.go
httpProxy.go
httpProxy_test.go
interrupt_dials_test.go
limitProtocols_test.go
meekConn.go
net.go
net_darwin.go
net_other.go
net_windows.go
notice.go
packetTunnelTransport.go
pprof.go
pprof_disabled.go
remoteServerList.go
remoteServerList_test.go
serverApi.go
socksProxy.go
splitTunnel.go
sshClientVersionPicker.go
tlsDialer.go
tunnel.go
upgradeDownload.go
userAgentPicker.go
userAgent_test.go
utils.go
vendor
.gitignore
.travis.yml
CLA-entity.md
CLA-individual.md
CONTRIBUTING.md
LICENSE
README.md
克隆/下载
auth_digest.go 5.47 KB
一键复制 编辑 原始数据 按行查看 历史
/*
* Copyright (c) 2015, Psiphon Inc.
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package upstreamproxy
import (
"crypto/md5"
"crypto/rand"
"encoding/base64"
"fmt"
"net/http"
"strings"
)
type DigestHttpAuthState int
const (
DIGEST_HTTP_AUTH_STATE_CHALLENGE_RECEIVED DigestHttpAuthState = iota
DIGEST_HTTP_AUTH_STATE_RESPONSE_GENERATED
)
type DigestHttpAuthenticator struct {
state DigestHttpAuthState
username string
password string
digestHeaders *DigestHeaders
}
func newDigestAuthenticator(username, password string) *DigestHttpAuthenticator {
return &DigestHttpAuthenticator{
state: DIGEST_HTTP_AUTH_STATE_CHALLENGE_RECEIVED,
username: username,
password: password,
}
}
/* Adapted from https://github.com/ryanjdew/http-digest-auth-client */
type DigestHeaders struct {
Realm string
Qop string
Method string
Nonce string
Opaque string
Algorithm string
HA1 string
HA2 string
Cnonce string
Uri string
Nc int16
Username string
Password string
}
// ApplyAuth adds proper auth header to the passed request
func (d *DigestHeaders) ApplyAuth(req *http.Request) {
d.Nc += 0x1
d.Method = req.Method
d.digestChecksum()
response := h(strings.Join([]string{d.HA1, d.Nonce, fmt.Sprintf("%08x", d.Nc),
d.Cnonce, d.Qop, d.HA2}, ":"))
AuthHeader := fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s", qop=%s, nc=%08x, cnonce="%s", algorithm=%s`,
d.Username, d.Realm, d.Nonce, d.Uri, response, d.Qop, d.Nc, d.Cnonce, d.Algorithm)
if d.Opaque != "" {
AuthHeader = fmt.Sprintf(`%s, opaque="%s"`, AuthHeader, d.Opaque)
}
req.Header.Set("Proxy-Authorization", AuthHeader)
}
func (d *DigestHeaders) digestChecksum() {
var A1 string
switch d.Algorithm {
case "MD5":
//HA1=MD5(username:realm:password)
A1 = fmt.Sprintf("%s:%s:%s", d.Username, d.Realm, d.Password)
case "MD5-sess":
// HA1=MD5(MD5(username:realm:password):nonce:cnonce)
str := fmt.Sprintf("%s:%s:%s", d.Username, d.Realm, d.Password)
A1 = fmt.Sprintf("%s:%s:%s", h(str), d.Nonce, d.Cnonce)
default:
//token
}
if A1 == "" {
return
}
//HA1
d.HA1 = h(A1)
// HA2
A2 := fmt.Sprintf("%s:%s", d.Method, d.Uri)
d.HA2 = h(A2)
}
func randomKey() string {
k := make([]byte, 12)
for bytes := 0; bytes < len(k); {
n, err := rand.Read(k[bytes:])
if err != nil {
panic("rand.Read() failed")
}
k[bytes] = byte(bytes)
bytes += n
}
return base64.StdEncoding.EncodeToString(k)
}
/*
H function for MD5 algorithm (returns a lower-case hex MD5 digest)
*/
func h(data string) string {
digest := md5.New()
digest.Write([]byte(data))
return fmt.Sprintf("%x", digest.Sum(nil))
}
func (a *DigestHttpAuthenticator) Authenticate(req *http.Request, resp *http.Response) error {
if a.state != DIGEST_HTTP_AUTH_STATE_CHALLENGE_RECEIVED {
return proxyError(fmt.Errorf("Authorization is not accepted by the proxy server"))
}
challenges, err := parseAuthChallenge(resp)
if err != nil {
//already wrapped in proxyError
return err
}
challenge := challenges["Digest"]
if len(challenge) == 0 {
return proxyError(fmt.Errorf("Digest authentication challenge is empty"))
}
//parse challenge
digestParams := map[string]string{}
for _, keyval := range strings.Split(challenge, ",") {
param := strings.SplitN(keyval, "=", 2)
if len(param) != 2 {
continue
}
digestParams[strings.Trim(param[0], "\" ")] = strings.Trim(param[1], "\" ")
}
if len(digestParams) == 0 {
return proxyError(fmt.Errorf("Digest authentication challenge is malformed"))
}
algorithm := digestParams["algorithm"]
if stale, ok := digestParams["stale"]; ok && stale == "true" {
// Server indicated that the nonce is stale
// Reset auth cache and state
a.digestHeaders = nil
a.state = DIGEST_HTTP_AUTH_STATE_CHALLENGE_RECEIVED
return nil
}
if a.digestHeaders == nil {
d := &DigestHeaders{}
if req.Method == "CONNECT" {
d.Uri = req.URL.Host
} else {
d.Uri = req.URL.Scheme + "://" + req.URL.Host + req.URL.RequestURI()
}
d.Realm = digestParams["realm"]
d.Qop = digestParams["qop"]
d.Nonce = digestParams["nonce"]
d.Opaque = digestParams["opaque"]
if algorithm == "" {
d.Algorithm = "MD5"
} else {
d.Algorithm = digestParams["algorithm"]
}
d.Nc = 0x0
d.Cnonce = randomKey()
d.Username = a.username
d.Password = a.password
a.digestHeaders = d
}
a.digestHeaders.ApplyAuth(req)
a.state = DIGEST_HTTP_AUTH_STATE_RESPONSE_GENERATED
return nil
}
func (a *DigestHttpAuthenticator) IsConnectionBased() bool {
return false
}
func (a *DigestHttpAuthenticator) IsComplete() bool {
return a.state == DIGEST_HTTP_AUTH_STATE_RESPONSE_GENERATED
}
func (a *DigestHttpAuthenticator) Reset() {
a.state = DIGEST_HTTP_AUTH_STATE_CHALLENGE_RECEIVED
}
func (a *DigestHttpAuthenticator) PreAuthenticate(req *http.Request) error {
if a.digestHeaders != nil {
a.digestHeaders.ApplyAuth(req)
}
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/lqinggang/psiphon-tunnel-core.git
git@gitee.com:lqinggang/psiphon-tunnel-core.git
lqinggang
psiphon-tunnel-core
psiphon-tunnel-core
v2.0.0

搜索帮助