...
1
2
3
4
5 package gin
6
7 import (
8 "crypto/subtle"
9 "encoding/base64"
10 "net/http"
11 "strconv"
12
13 "github.com/gin-gonic/gin/internal/bytesconv"
14 )
15
16
17 const AuthUserKey = "user"
18
19
20 type Accounts map[string]string
21
22 type authPair struct {
23 value string
24 user string
25 }
26
27 type authPairs []authPair
28
29 func (a authPairs) searchCredential(authValue string) (string, bool) {
30 if authValue == "" {
31 return "", false
32 }
33 for _, pair := range a {
34 if subtle.ConstantTimeCompare(bytesconv.StringToBytes(pair.value), bytesconv.StringToBytes(authValue)) == 1 {
35 return pair.user, true
36 }
37 }
38 return "", false
39 }
40
41
42
43
44
45 func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
46 if realm == "" {
47 realm = "Authorization Required"
48 }
49 realm = "Basic realm=" + strconv.Quote(realm)
50 pairs := processAccounts(accounts)
51 return func(c *Context) {
52
53 user, found := pairs.searchCredential(c.requestHeader("Authorization"))
54 if !found {
55
56 c.Header("WWW-Authenticate", realm)
57 c.AbortWithStatus(http.StatusUnauthorized)
58 return
59 }
60
61
62
63 c.Set(AuthUserKey, user)
64 }
65 }
66
67
68
69 func BasicAuth(accounts Accounts) HandlerFunc {
70 return BasicAuthForRealm(accounts, "")
71 }
72
73 func processAccounts(accounts Accounts) authPairs {
74 length := len(accounts)
75 assert1(length > 0, "Empty list of authorized credentials")
76 pairs := make(authPairs, 0, length)
77 for user, password := range accounts {
78 assert1(user != "", "User can not be empty")
79 value := authorizationHeader(user, password)
80 pairs = append(pairs, authPair{
81 value: value,
82 user: user,
83 })
84 }
85 return pairs
86 }
87
88 func authorizationHeader(user, password string) string {
89 base := user + ":" + password
90 return "Basic " + base64.StdEncoding.EncodeToString(bytesconv.StringToBytes(base))
91 }
92
View as plain text