-
Notifications
You must be signed in to change notification settings - Fork 407
/
csrfclient.go
100 lines (77 loc) · 3.09 KB
/
csrfclient.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
package client
import (
"context"
"net/http"
"strings"
"time"
"github.com/kyma-project/kyma/components/application-gateway/internal/csrf"
"github.com/kyma-project/kyma/components/application-gateway/pkg/apperrors"
"github.com/kyma-project/kyma/components/application-gateway/pkg/authorization"
"github.com/kyma-project/kyma/components/application-gateway/pkg/httpconsts"
log "github.com/sirupsen/logrus"
)
func New(timeoutDuration int, tokenCache TokenCache, httpClient *http.Client) csrf.Client {
return &client{
timeoutDuration: timeoutDuration,
tokenCache: tokenCache,
httpClient: httpClient,
}
}
type client struct {
timeoutDuration int
tokenCache TokenCache
httpClient *http.Client
}
func (c *client) GetTokenEndpointResponse(tokenEndpointURL string, strategy authorization.Strategy) (*csrf.Response, apperrors.AppError) {
resp, found := c.tokenCache.Get(tokenEndpointURL)
if found {
return resp, nil
}
log.Infof("CSRF Token not found in cache, fetching (Endpoint: %s)", tokenEndpointURL)
tokenResponse, err := c.requestToken(tokenEndpointURL, strategy, c.timeoutDuration)
if err != nil {
return nil, err
}
c.tokenCache.Add(tokenEndpointURL, tokenResponse)
return tokenResponse, nil
}
func (c *client) InvalidateTokenCache(tokenEndpointURL string) {
log.Infof("Invalidating token for endpoint: %s", tokenEndpointURL)
c.tokenCache.Remove(tokenEndpointURL)
}
func (c *client) requestToken(csrfEndpointURL string, strategy authorization.Strategy, timeoutDuration int) (*csrf.Response, apperrors.AppError) {
tokenRequest, err := http.NewRequest(http.MethodGet, csrfEndpointURL, strings.NewReader(""))
if err != nil {
return nil, apperrors.Internal("failed to create token request: %s", err.Error())
}
err = addAuthorization(tokenRequest, c.httpClient, strategy)
if err != nil {
return nil, apperrors.Internal("failed to create token request: %s", err.Error())
}
setCSRFSpecificHeaders(tokenRequest)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutDuration)*time.Second)
defer cancel()
requestWithContext := tokenRequest.WithContext(ctx)
resp, err := c.httpClient.Do(requestWithContext)
if err != nil {
return nil, apperrors.UpstreamServerCallFailed("failed to make a request to '%s': %s", csrfEndpointURL, err.Error())
}
if resp.StatusCode != http.StatusOK {
return nil, apperrors.UpstreamServerCallFailed("incorrect response code '%d' while getting token from %s", resp.StatusCode, csrfEndpointURL)
}
tokenRes := &csrf.Response{
CSRFToken: resp.Header.Get(httpconsts.HeaderCSRFToken),
Cookies: resp.Cookies(),
}
return tokenRes, nil
}
func addAuthorization(r *http.Request, client *http.Client, strategy authorization.Strategy) apperrors.AppError {
return strategy.AddAuthorization(r, func(transport *http.Transport) {
client.Transport = transport
})
}
func setCSRFSpecificHeaders(r *http.Request) {
r.Header.Add(httpconsts.HeaderCSRFToken, httpconsts.HeaderCSRFTokenVal)
r.Header.Add(httpconsts.HeaderAccept, httpconsts.HeaderAcceptVal)
r.Header.Add(httpconsts.HeaderCacheControl, httpconsts.HeaderCacheControlVal)
}