141 lines
3.6 KiB
Go
141 lines
3.6 KiB
Go
package auth
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/md5"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// RandomKey returns a random 16-byte base64 alphabet string
|
|
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")
|
|
}
|
|
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))
|
|
}
|
|
|
|
// ParseList parses a comma-separated list of values as described by
|
|
// RFC 2068 and returns list elements.
|
|
//
|
|
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
|
|
// which was ported from urllib2.parse_http_list, from the Python
|
|
// standard library.
|
|
func ParseList(value string) []string {
|
|
var list []string
|
|
var escape, quote bool
|
|
b := new(bytes.Buffer)
|
|
for _, r := range value {
|
|
switch {
|
|
case escape:
|
|
b.WriteRune(r)
|
|
escape = false
|
|
case quote:
|
|
if r == '\\' {
|
|
escape = true
|
|
} else {
|
|
if r == '"' {
|
|
quote = false
|
|
}
|
|
b.WriteRune(r)
|
|
}
|
|
case r == ',':
|
|
list = append(list, strings.TrimSpace(b.String()))
|
|
b.Reset()
|
|
case r == '"':
|
|
quote = true
|
|
b.WriteRune(r)
|
|
default:
|
|
b.WriteRune(r)
|
|
}
|
|
}
|
|
// Append last part.
|
|
if s := b.String(); s != "" {
|
|
list = append(list, strings.TrimSpace(s))
|
|
}
|
|
return list
|
|
}
|
|
|
|
// ParsePairs extracts key/value pairs from a comma-separated list of
|
|
// values as described by RFC 2068 and returns a map[key]value. The
|
|
// resulting values are unquoted. If a list element doesn't contain a
|
|
// "=", the key is the element itself and the value is an empty
|
|
// string.
|
|
//
|
|
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
|
|
func ParsePairs(value string) map[string]string {
|
|
m := make(map[string]string)
|
|
for _, pair := range ParseList(strings.TrimSpace(value)) {
|
|
if i := strings.Index(pair, "="); i < 0 {
|
|
m[pair] = ""
|
|
} else {
|
|
v := pair[i+1:]
|
|
if v[0] == '"' && v[len(v)-1] == '"' {
|
|
// Unquote it.
|
|
v = v[1 : len(v)-1]
|
|
}
|
|
m[pair[:i]] = v
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
|
|
// Headers contains header and error codes used by authenticator.
|
|
type Headers struct {
|
|
Authenticate string // WWW-Authenticate
|
|
Authorization string // Authorization
|
|
AuthInfo string // Authentication-Info
|
|
UnauthCode int // 401
|
|
UnauthContentType string // text/plain
|
|
UnauthResponse string // Unauthorized.
|
|
}
|
|
|
|
// V returns NormalHeaders when h is nil, or h otherwise. Allows to
|
|
// use uninitialized *Headers values in structs.
|
|
func (h *Headers) V() *Headers {
|
|
if h == nil {
|
|
return NormalHeaders
|
|
}
|
|
return h
|
|
}
|
|
|
|
var (
|
|
// NormalHeaders are the regular Headers used by an HTTP Server for
|
|
// request authentication.
|
|
NormalHeaders = &Headers{
|
|
Authenticate: "WWW-Authenticate",
|
|
Authorization: "Authorization",
|
|
AuthInfo: "Authentication-Info",
|
|
UnauthCode: http.StatusUnauthorized,
|
|
UnauthContentType: "text/plain",
|
|
UnauthResponse: fmt.Sprintf("%d %s\n", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)),
|
|
}
|
|
|
|
// ProxyHeaders are Headers used by an HTTP Proxy server for proxy
|
|
// access authentication.
|
|
ProxyHeaders = &Headers{
|
|
Authenticate: "Proxy-Authenticate",
|
|
Authorization: "Proxy-Authorization",
|
|
AuthInfo: "Proxy-Authentication-Info",
|
|
UnauthCode: http.StatusProxyAuthRequired,
|
|
UnauthContentType: "text/plain",
|
|
UnauthResponse: fmt.Sprintf("%d %s\n", http.StatusProxyAuthRequired, http.StatusText(http.StatusProxyAuthRequired)),
|
|
}
|
|
)
|
|
|
|
const contentType = "Content-Type"
|