1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
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"
|