portainer/api/http/proxy/factory/azure/transport.go

105 lines
2.6 KiB
Go
Raw Normal View History

package azure
import (
"net/http"
"strconv"
"sync"
"time"
2021-03-29 21:58:56 +00:00
"path"
"github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/http/client"
)
type (
azureAPIToken struct {
value string
expirationTime time.Time
}
Transport struct {
credentials *portainer.AzureCredentials
client *client.HTTPClient
token *azureAPIToken
mutex sync.Mutex
2021-03-29 21:58:56 +00:00
dataStore portainer.DataStore
endpoint *portainer.Endpoint
}
azureRequestContext struct {
isAdmin bool
userID portainer.UserID
userTeamIDs []portainer.TeamID
resourceControls []portainer.ResourceControl
}
)
// NewTransport returns a pointer to a new instance of Transport that implements the HTTP Transport
// interface for proxying requests to the Azure API.
2021-03-29 21:58:56 +00:00
func NewTransport(credentials *portainer.AzureCredentials, dataStore portainer.DataStore, endpoint *portainer.Endpoint) *Transport {
return &Transport{
credentials: credentials,
client: client.NewHTTPClient(),
2021-03-29 21:58:56 +00:00
dataStore: dataStore,
endpoint: endpoint,
}
}
// RoundTrip is the implementation of the the http.RoundTripper interface
func (transport *Transport) RoundTrip(request *http.Request) (*http.Response, error) {
2021-03-29 21:58:56 +00:00
return transport.proxyAzureRequest(request)
}
func (transport *Transport) proxyAzureRequest(request *http.Request) (*http.Response, error) {
requestPath := request.URL.Path
err := transport.retrieveAuthenticationToken()
if err != nil {
return nil, err
}
request.Header.Set("Authorization", "Bearer "+transport.token.value)
2021-03-29 21:58:56 +00:00
if match, _ := path.Match(portainer.AzurePathContainerGroups, requestPath); match {
return transport.proxyContainerGroupsRequest(request)
} else if match, _ := path.Match(portainer.AzurePathContainerGroup, requestPath); match {
return transport.proxyContainerGroupRequest(request)
}
return http.DefaultTransport.RoundTrip(request)
}
func (transport *Transport) authenticate() error {
token, err := transport.client.ExecuteAzureAuthenticationRequest(transport.credentials)
if err != nil {
return err
}
expiresOn, err := strconv.ParseInt(token.ExpiresOn, 10, 64)
if err != nil {
return err
}
transport.token = &azureAPIToken{
value: token.AccessToken,
expirationTime: time.Unix(expiresOn, 0),
}
return nil
}
func (transport *Transport) retrieveAuthenticationToken() error {
transport.mutex.Lock()
defer transport.mutex.Unlock()
if transport.token == nil {
return transport.authenticate()
}
timeLimit := time.Now().Add(-5 * time.Minute)
if timeLimit.After(transport.token.expirationTime) {
return transport.authenticate()
}
return nil
}