/
token.go
112 lines (99 loc) · 2.57 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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//
// token.go
//
// Copyright (c) 2019 Markku Rossi
//
// All rights reserved.
//
package auth
import (
"crypto/ed25519"
"encoding/base64"
"fmt"
"net/http"
"strings"
"github.com/markkurossi/go-libs/tlv"
)
func VerifyToken(token []byte, pub ed25519.PublicKey) bool {
return false
}
func Authorize(w http.ResponseWriter, r *http.Request, realm string,
signatureVerifier func(message, sig []byte) bool,
tenant *Tenant) tlv.Values {
var tokenB64 string
auth := r.Header.Get("Authorization")
if len(auth) > 0 {
parts := strings.Split(auth, " ")
if len(parts) != 2 {
Error401f(w, realm, "invalid_authorization",
"Invalid HTTP Authorization header")
return nil
}
if parts[0] != "Bearer" {
Error401f(w, realm, "invalid_authorization",
"Bearer authorization required")
return nil
}
tokenB64 = parts[1]
} else {
tokens, ok := r.URL.Query()["token"]
if ok && len(tokens) > 0 {
tokenB64 = tokens[0]
} else {
Error401(w, realm)
return nil
}
}
data, err := base64.RawURLEncoding.DecodeString(tokenB64)
if err != nil {
Error401f(w, realm, "invalid_token", "Base64 decoding failed: %s", err)
return nil
}
token, err := tlv.Unmarshal(data)
if err != nil {
Error401f(w, realm, "invalid_token", "TLV decoding failed: %s", err)
return nil
}
values, ok := token[TOKEN_VALUES].(tlv.Values)
if !ok {
Error401f(w, realm, "invalid_token", "No token values")
return nil
}
signature, ok := token[TOKEN_SIGNATURE].([]byte)
if !ok {
Error401f(w, realm, "invalid_token", "No token signature")
return nil
}
valuesData, err := values.Marshal()
if err != nil {
Error401f(w, realm, "invalid_token", "Values marshal failed: %s", err)
return nil
}
if !signatureVerifier(valuesData, signature) {
Error401f(w, realm, "invalid_token", "Signature verification failed")
return nil
}
tenantID, ok := values[T_TENANT_ID].(string)
if !ok {
Error401f(w, realm, "invalid_token", "No tenant ID")
return nil
}
if tenant != nil && tenantID != tenant.ID {
Error401f(w, realm, "invalid_token", "Wrong authentication tenant")
return nil
}
// XXX expiration
return values
}
func Error401(w http.ResponseWriter, realm string) {
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer realm="%s"`, realm))
w.WriteHeader(http.StatusUnauthorized)
}
func Error401f(w http.ResponseWriter, realm, error, desc string,
a ...interface{}) {
description := fmt.Sprintf(desc, a...)
w.Header().Set("WWW-Authenticate",
fmt.Sprintf(`Bearer realm="%s", error="%s", error_description="%s"`,
realm, error, description))
w.WriteHeader(http.StatusUnauthorized)
}