/
token.go
92 lines (72 loc) · 2.09 KB
/
token.go
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
package auth
import (
"errors"
"net/http"
"strings"
log "github.com/sirupsen/logrus"
"github.com/ivanilves/lstags/api/v1/registry/client/auth/basic"
"github.com/ivanilves/lstags/api/v1/registry/client/auth/bearer"
"github.com/ivanilves/lstags/api/v1/registry/client/auth/none"
)
// Token is an abstraction for aggregated token-related information we get from authentication services
type Token interface {
Method() string
String() string
ExpiresIn() int
}
type authHeader string
func extractAuthHeader(hh []string) (authHeader, error) {
if len(hh) == 0 {
return "None realm=none", nil
}
h := hh[0]
if len(strings.SplitN(h, " ", 2)) != 2 {
return "", errors.New("Unexpected 'Www-Authenticate' header: " + h)
}
return authHeader(h), nil
}
func getAuthMethod(h authHeader) string {
return strings.SplitN(string(h), " ", 2)[0]
}
func getAuthParams(h authHeader) map[string]string {
params := make(map[string]string)
paramString := strings.SplitN(string(h), " ", 2)[1]
for _, keyValueString := range strings.Split(paramString, ",") {
kv := strings.Split(keyValueString, "=")
if len(kv) == 2 {
params[kv[0]] = strings.Trim(kv[1], "\"")
}
}
return params
}
// NewToken creates a new instance of Token in two steps:
// * detects authentication type ("Bearer", "Basic" or "None")
// * delegates actual authentication to the type-specific implementation
func NewToken(url, username, password, scope string) (Token, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
authHeader, err := extractAuthHeader(resp.Header["Www-Authenticate"])
if err != nil {
return nil, err
}
method := strings.ToLower(getAuthMethod(authHeader))
params := getAuthParams(authHeader)
switch method {
case "none":
return none.RequestToken()
case "basic":
t, err := basic.RequestToken(url, username, password)
if err != nil {
log.Debug(err.Error())
return none.RequestToken()
}
return t, nil
case "bearer":
params["scope"] = scope
return bearer.RequestToken(username, password, params)
default:
return nil, errors.New("Unknown authentication method: " + method)
}
}