...
1 package ociauth
2
3 import (
4 "net/http"
5 "strings"
6 )
7
8
9 type octetType byte
10
11 var octetTypes [256]octetType
12
13 const (
14 isToken octetType = 1 << iota
15 isSpace
16 )
17
18 func init() {
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 for c := 0; c < 256; c++ {
36 var t octetType
37 isCtl := c <= 31 || c == 127
38 isChar := 0 <= c && c <= 127
39 isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
40 if strings.ContainsRune(" \t\r\n", rune(c)) {
41 t |= isSpace
42 }
43 if isChar && !isCtl && !isSeparator {
44 t |= isToken
45 }
46 octetTypes[c] = t
47 }
48 }
49
50
51 type authHeader struct {
52 scheme string
53 params map[string]string
54 }
55
56 func challengeFromResponse(resp *http.Response) *authHeader {
57 var h *authHeader
58 for _, chalStr := range resp.Header["Www-Authenticate"] {
59 h1 := parseWWWAuthenticate(chalStr)
60 if h1 == nil {
61 continue
62 }
63 if h1.scheme != "basic" && h1.scheme != "bearer" {
64 continue
65 }
66 if h == nil {
67 h = h1
68 } else if h1.scheme == "basic" && h.scheme == "bearer" {
69
70 h = h1
71 }
72 }
73 return h
74 }
75
76
77
78 func parseWWWAuthenticate(header string) *authHeader {
79 var h authHeader
80 h.params = make(map[string]string)
81
82 scheme, s := expectToken(header)
83 if scheme == "" {
84 return nil
85 }
86 h.scheme = strings.ToLower(scheme)
87 s = skipSpace(s)
88 for len(s) > 0 {
89 var pkey, pvalue string
90 pkey, s = expectToken(skipSpace(s))
91 if pkey == "" {
92 return nil
93 }
94 if !strings.HasPrefix(s, "=") {
95 return nil
96 }
97 pvalue, s = expectTokenOrQuoted(s[1:])
98 if pvalue == "" {
99 return nil
100 }
101 h.params[strings.ToLower(pkey)] = pvalue
102 s = skipSpace(s)
103 if !strings.HasPrefix(s, ",") {
104 break
105 }
106 s = s[1:]
107 }
108 if len(s) > 0 {
109 return nil
110 }
111 return &h
112 }
113
114 func skipSpace(s string) (rest string) {
115 i := 0
116 for ; i < len(s); i++ {
117 if octetTypes[s[i]]&isSpace == 0 {
118 break
119 }
120 }
121 return s[i:]
122 }
123
124 func expectToken(s string) (token, rest string) {
125 i := 0
126 for ; i < len(s); i++ {
127 if octetTypes[s[i]]&isToken == 0 {
128 break
129 }
130 }
131 return s[:i], s[i:]
132 }
133
134 func expectTokenOrQuoted(s string) (value string, rest string) {
135 if !strings.HasPrefix(s, "\"") {
136 return expectToken(s)
137 }
138 s = s[1:]
139 for i := 0; i < len(s); i++ {
140 switch s[i] {
141 case '"':
142 return s[:i], s[i+1:]
143 case '\\':
144 p := make([]byte, len(s)-1)
145 j := copy(p, s[:i])
146 escape := true
147 for i = i + 1; i < len(s); i++ {
148 b := s[i]
149 switch {
150 case escape:
151 escape = false
152 p[j] = b
153 j++
154 case b == '\\':
155 escape = true
156 case b == '"':
157 return string(p[:j]), s[i+1:]
158 default:
159 p[j] = b
160 j++
161 }
162 }
163 return "", ""
164 }
165 }
166 return "", ""
167 }
168
View as plain text