@@ -5,11 +5,12 @@ package bearertokenauthextension // import "github.com/open-telemetry/openteleme
5
5
6
6
import (
7
7
"context"
8
+ "crypto/subtle"
8
9
"errors"
9
10
"fmt"
10
11
"net/http"
11
12
"os"
12
- "sync"
13
+ "sync/atomic "
13
14
14
15
"github.com/fsnotify/fsnotify"
15
16
"go.opentelemetry.io/collector/component"
42
43
43
44
// BearerTokenAuth is an implementation of auth.Client. It embeds a static authorization "bearer" token in every rpc call.
44
45
type BearerTokenAuth struct {
45
- muTokenString sync.RWMutex
46
- scheme string
47
- tokenString string
46
+ scheme string
47
+ authorizationValueAtomic atomic.Value
48
48
49
49
shutdownCH chan struct {}
50
50
@@ -58,12 +58,13 @@ func newBearerTokenAuth(cfg *Config, logger *zap.Logger) *BearerTokenAuth {
58
58
if cfg .Filename != "" && cfg .BearerToken != "" {
59
59
logger .Warn ("a filename is specified. Configured token is ignored!" )
60
60
}
61
- return & BearerTokenAuth {
62
- scheme : cfg .Scheme ,
63
- tokenString : string (cfg .BearerToken ),
64
- filename : cfg .Filename ,
65
- logger : logger ,
61
+ a := & BearerTokenAuth {
62
+ scheme : cfg .Scheme ,
63
+ filename : cfg .Filename ,
64
+ logger : logger ,
66
65
}
66
+ a .setAuthorizationValue (string (cfg .BearerToken ))
67
+ return a
67
68
}
68
69
69
70
// Start of BearerTokenAuth does nothing and returns nil if no filename
@@ -135,9 +136,21 @@ func (b *BearerTokenAuth) refreshToken() {
135
136
b .logger .Error (err .Error ())
136
137
return
137
138
}
138
- b .muTokenString .Lock ()
139
- b .tokenString = string (token )
140
- b .muTokenString .Unlock ()
139
+ b .setAuthorizationValue (string (token ))
140
+ }
141
+
142
+ func (b * BearerTokenAuth ) setAuthorizationValue (token string ) {
143
+ value := token
144
+ if b .scheme != "" {
145
+ value = b .scheme + " " + value
146
+ }
147
+ b .authorizationValueAtomic .Store (value )
148
+ }
149
+
150
+ // authorizationValue returns the Authorization header/metadata value
151
+ // to set for client auth, and expected value for server auth.
152
+ func (b * BearerTokenAuth ) authorizationValue () string {
153
+ return b .authorizationValueAtomic .Load ().(string )
141
154
}
142
155
143
156
// Shutdown of BearerTokenAuth does nothing and returns nil
@@ -158,22 +171,15 @@ func (b *BearerTokenAuth) Shutdown(_ context.Context) error {
158
171
// PerRPCCredentials returns PerRPCAuth an implementation of credentials.PerRPCCredentials that
159
172
func (b * BearerTokenAuth ) PerRPCCredentials () (credentials.PerRPCCredentials , error ) {
160
173
return & PerRPCAuth {
161
- metadata : map [string ]string {"authorization" : b .bearerToken ()},
174
+ metadata : map [string ]string {"authorization" : b .authorizationValue ()},
162
175
}, nil
163
176
}
164
177
165
- func (b * BearerTokenAuth ) bearerToken () string {
166
- b .muTokenString .RLock ()
167
- token := fmt .Sprintf ("%s %s" , b .scheme , b .tokenString )
168
- b .muTokenString .RUnlock ()
169
- return token
170
- }
171
-
172
178
// RoundTripper is not implemented by BearerTokenAuth
173
179
func (b * BearerTokenAuth ) RoundTripper (base http.RoundTripper ) (http.RoundTripper , error ) {
174
180
return & BearerAuthRoundTripper {
175
- baseTransport : base ,
176
- bearerTokenFunc : b . bearerToken ,
181
+ baseTransport : base ,
182
+ auth : b ,
177
183
}, nil
178
184
}
179
185
@@ -184,23 +190,20 @@ func (b *BearerTokenAuth) Authenticate(ctx context.Context, headers map[string][
184
190
auth , ok = headers ["Authorization" ]
185
191
}
186
192
if ! ok || len (auth ) == 0 {
187
- return ctx , errors .New ("authentication didn't succeed " )
193
+ return ctx , errors .New ("missing or empty authorization header " )
188
194
}
189
195
token := auth [0 ]
190
- expect := b .tokenString
191
- if len (b .scheme ) != 0 {
192
- expect = fmt .Sprintf ("%s %s" , b .scheme , expect )
193
- }
194
- if expect != token {
196
+ expect := b .authorizationValue ()
197
+ if subtle .ConstantTimeCompare ([]byte (expect ), []byte (token )) == 0 {
195
198
return ctx , fmt .Errorf ("scheme or token does not match: %s" , token )
196
199
}
197
200
return ctx , nil
198
201
}
199
202
200
203
// BearerAuthRoundTripper intercepts and adds Bearer token Authorization headers to each http request.
201
204
type BearerAuthRoundTripper struct {
202
- baseTransport http.RoundTripper
203
- bearerTokenFunc func () string
205
+ baseTransport http.RoundTripper
206
+ auth * BearerTokenAuth
204
207
}
205
208
206
209
// RoundTrip modifies the original request and adds Bearer token Authorization headers.
@@ -209,6 +212,6 @@ func (interceptor *BearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.R
209
212
if req2 .Header == nil {
210
213
req2 .Header = make (http.Header )
211
214
}
212
- req2 .Header .Set ("Authorization" , interceptor .bearerTokenFunc ())
215
+ req2 .Header .Set ("Authorization" , interceptor .auth . authorizationValue ())
213
216
return interceptor .baseTransport .RoundTrip (req2 )
214
217
}
0 commit comments