Skip to content

Commit

Permalink
🌱 Add auth token refresh to Binding (#592)
Browse files Browse the repository at this point in the history
There is an issue with long-time running tests e.g. for analysis on
Konveyor with enabled Auth feature. Keycloak allows to refresh auth
token, however the token for refresh was not stored in `binding.Client`
and `binding.RichClient.Login` method didn't return the Login struct
with Refresh and Expiry fields.

Main changes in this PR
- binding.client keeps api.Login struct instead of string token to allow
use Refresh token to get a new one
- binding.client.send method can catch 401 and try refresh auth token
after each API call

For visibility @mguetta1 

Fixes konveyor/go-konveyor-tests#71

---------

Signed-off-by: Marek Aufart <[email protected]>
Signed-off-by: Marek Aufart <[email protected]>
  • Loading branch information
aufi authored Feb 12, 2024
1 parent fbf748f commit ae2295a
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 8 deletions.
3 changes: 2 additions & 1 deletion addon/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

logapi "github.com/go-logr/logr"
"github.com/jortel/go-utils/logr"
"github.com/konveyor/tackle2-hub/api"
"github.com/konveyor/tackle2-hub/binding"
"github.com/konveyor/tackle2-hub/settings"
"github.com/konveyor/tackle2-hub/task"
Expand Down Expand Up @@ -131,7 +132,7 @@ func (h *Adapter) Run(addon func() error) {
// newAdapter builds a new Addon Adapter object.
func newAdapter() (adapter *Adapter) {
richClient := binding.New(Settings.Addon.Hub.URL)
richClient.Client.SetToken(Settings.Addon.Hub.Token)
richClient.Client.SetToken(api.Login{Token: Settings.Addon.Hub.Token})
adapter = &Adapter{
client: richClient.Client,
Task: Task{
Expand Down
38 changes: 34 additions & 4 deletions binding/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (s Path) Inject(p Params) (out string) {
}

// NewClient Constructs a new client
func NewClient(url, token string) (client *Client) {
func NewClient(url string, token api.Login) (client *Client) {
client = &Client{
baseURL: url,
token: token,
Expand All @@ -83,7 +83,7 @@ type Client struct {
// baseURL for the nub.
baseURL string
// addon API token
token string
token api.Login
// transport
transport http.RoundTripper
// Retry limit.
Expand All @@ -93,7 +93,7 @@ type Client struct {
}

// SetToken sets hub token on client
func (r *Client) SetToken(token string) {
func (r *Client) SetToken(token api.Login) {
r.token = token
}

Expand Down Expand Up @@ -636,7 +636,7 @@ func (r *Client) send(rb func() (*http.Request, error)) (response *http.Response
if err != nil {
return
}
request.Header.Set(api.Authorization, r.token)
request.Header.Set(api.Authorization, r.token.Token)
client := http.Client{Transport: r.transport}
response, err = client.Do(request)
if err != nil {
Expand All @@ -662,6 +662,17 @@ func (r *Client) send(rb func() (*http.Request, error)) (response *http.Response
response.StatusCode,
request.Method,
request.URL.Path))
if response.StatusCode == http.StatusUnauthorized {
refreshed, nErr := r.refreshToken(request)
if nErr != nil {
r.Error = liberr.Wrap(nErr)
err = r.Error
return
}
if refreshed {
continue
}
}
break
}
}
Expand Down Expand Up @@ -765,3 +776,22 @@ func (f *Field) disposition() (d string) {
d = fmt.Sprintf(`form-data; name="%s"; filename="%s"`, f.Name, pathlib.Base(f.Path))
return
}

// refreshToken refreshes the token.
func (r *Client) refreshToken(request *http.Request) (refreshed bool, err error) {
if r.token.Token == "" ||
strings.HasSuffix(request.URL.Path, api.AuthRefreshRoot) {
return
}
login := &api.Login{Refresh: r.token.Refresh}
err = r.Post(api.AuthRefreshRoot, login)
if err == nil {
r.token.Token = login.Token
refreshed = true
return
}
if errors.Is(err, &RestError{}) {
err = nil
}
return
}
4 changes: 2 additions & 2 deletions binding/richclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type RichClient struct {
func New(baseUrl string) (r *RichClient) {
//
// Build REST client.
client := NewClient(baseUrl, "")
client := NewClient(baseUrl, api.Login{})

//
// Build RichClient.
Expand Down Expand Up @@ -142,6 +142,6 @@ func (r *RichClient) Login(user, password string) (err error) {
if err != nil {
return
}
r.Client.SetToken(login.Token)
r.Client.SetToken(login)
return
}
2 changes: 1 addition & 1 deletion test/api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func PrepareRichClient() (richClient *binding.RichClient) {
}

// Disable HTTP requests retry for network-related errors to fail quickly.
richClient.Client.Retry = 0
richClient.Client.Retry = 1

return
}

0 comments on commit ae2295a

Please sign in to comment.