/
creds_injector.go
87 lines (72 loc) · 2.5 KB
/
creds_injector.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
/*
Package grpcserver is a generic gRPC server manager
Copyright 2018 Portworx
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package grpcserver
import (
"context"
"fmt"
"sync"
"time"
"github.com/dgrijalva/jwt-go"
)
var minsBeforeExpiration = time.Minute * 5
// CredsInjector implements credentials.PerRPCCredentials interface
type CredsInjector struct {
tokenGenerator func() (string, error)
m sync.Mutex
currentToken string
currentTokenExp int64
tlsEnabled bool
}
// GetRequestMetadata checks JWT token expiration time and invokes token generator function to get new token if that is needed
func (i *CredsInjector) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
i.m.Lock()
defer i.m.Unlock()
inAFewMins := time.Now().Unix() + int64(minsBeforeExpiration.Seconds())
if i.currentToken == "" || i.currentTokenExp == 0 || inAFewMins >= i.currentTokenExp {
token, err := i.tokenGenerator()
if err != nil {
return nil, fmt.Errorf("cannot generate token, err: %s", err.Error())
}
i.currentToken = token
t, _, err := new(jwt.Parser).ParseUnverified(i.currentToken, &jwt.StandardClaims{})
if err != nil {
return nil, fmt.Errorf("failed to parse authorization token: %s", err.Error())
}
claims, ok := t.Claims.(*jwt.StandardClaims)
if !ok {
return nil, fmt.Errorf("failed to get token claims")
}
i.currentTokenExp = claims.ExpiresAt
}
return map[string]string{
"authorization": "Bearer " + i.currentToken,
}, nil
}
func (i *CredsInjector) RequireTransportSecurity() bool {
return i.tlsEnabled
}
// ResetToken makes CredsInjector to invoke token generation next time when GetRequestMetadata is invoked
func (i *CredsInjector) ResetToken() {
i.m.Lock()
i.currentToken = ""
i.currentTokenExp = 0
i.m.Unlock()
}
// NewCredsInjector creates gRPC interceptor to inject Authorization token in requests
func NewCredsInjector(generator func() (string, error), tlsEnabled bool) *CredsInjector {
return &CredsInjector{
tokenGenerator: generator,
tlsEnabled: tlsEnabled,
}
}