Skip to content

Commit

Permalink
chore(oauth): Replace deprecated check_token usage with introspect
Browse files Browse the repository at this point in the history
# Issue

UAA has deprecated the `check_token` endpoint and recommends using the
`introspect` endpoint:
https://docs.cloudfoundry.org/api/uaa/version/77.19.0/index.html#check-token
  • Loading branch information
silvestre committed Nov 29, 2024
1 parent 7ac946f commit 95699a3
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 66 deletions.
37 changes: 23 additions & 14 deletions src/autoscaler/cf/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ type (
}

IntrospectionResponse struct {
Active bool `json:"active"`
Email string `json:"email"`
ClientId string `json:"client_id"`
Active bool `json:"active"`
Email string `json:"email"`
ClientId string `json:"client_id"`
Scopes []string `json:"scope"`
}

AuthClient interface {
Expand Down Expand Up @@ -297,42 +298,50 @@ func (c *Client) IsTokenAuthorized(token, clientId string) (bool, error) {
return c.CtxClient.IsTokenAuthorized(context.Background(), token, clientId)
}
func (c *CtxClient) IsTokenAuthorized(ctx context.Context, token, clientId string) (bool, error) {
endpoints, err := c.GetEndpoints(ctx)
introspectionResponse, err := c.introspectToken(ctx, token)
if err != nil {
return false, err
}
if introspectionResponse.Active && introspectionResponse.ClientId == clientId {
return true, nil
}

return false, nil
}

func (c *CtxClient) introspectToken(ctx context.Context, token string) (*IntrospectionResponse, error) {
endpoints, err := c.GetEndpoints(ctx)
if err != nil {
return nil, err
}
formData := url.Values{"token": {token}}
tokenURL := endpoints.Uaa.Url + PathIntrospectToken
request, err := http.NewRequestWithContext(ctx, "POST", tokenURL, strings.NewReader(formData.Encode()))
if err != nil {
return false, err
return nil, err
}
request.SetBasicAuth(c.conf.ClientID, c.conf.Secret)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")

resp, err := c.Client.Do(request)
if err != nil {
return false, err
return nil, err
}
if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("received status code %v while calling /introspect endpoint", resp.Status)
return nil, fmt.Errorf("received status code %v while calling /introspect endpoint", resp.Status)
}
defer func() { _ = resp.Body.Close() }()

responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
return nil, err
}

introspectionResponse := &IntrospectionResponse{}
err = json.Unmarshal(responseBody, introspectionResponse)
if err != nil {
return false, err
return nil, err
}

if introspectionResponse.Active && introspectionResponse.ClientId == clientId {
return true, nil
}

return false, nil
return introspectionResponse, nil
}
54 changes: 2 additions & 52 deletions src/autoscaler/cf/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"

"code.cloudfoundry.org/lager/v3"
)
Expand Down Expand Up @@ -60,12 +58,12 @@ func (c *Client) IsUserAdmin(userToken string) (bool, error) {
return c.CtxClient.IsUserAdmin(context.Background(), userToken)
}
func (c *CtxClient) IsUserAdmin(ctx context.Context, userToken string) (bool, error) {
scopes, err := c.getUserScope(ctx, userToken)
introspectionResponse, err := c.introspectToken(ctx, userToken)
if err != nil {
return false, err
}

for _, scope := range scopes {
for _, scope := range introspectionResponse.Scopes {
if scope == CCAdminScope {
c.logger.Info("user is cc admin")
return true, nil
Expand All @@ -75,42 +73,6 @@ func (c *CtxClient) IsUserAdmin(ctx context.Context, userToken string) (bool, er
return false, nil
}

func (c *CtxClient) getUserScope(ctx context.Context, userToken string) ([]string, error) {
userScopeEndpoint, err := c.getUserScopeEndpoint(ctx, userToken)
if err != nil {
return nil, err
}

req, err := http.NewRequestWithContext(ctx, "POST", userScopeEndpoint, nil)
if err != nil {
c.logger.Error("Failed to create getuserscope request", err, lager.Data{"userScopeEndpoint": userScopeEndpoint})
return nil, err
}
req.SetBasicAuth(c.conf.ClientID, c.conf.Secret)

resp, err := c.Client.Do(req)
if err != nil {
c.logger.Error("Failed to getuserscope, request failed", err, lager.Data{"userScopeEndpoint": userScopeEndpoint})
return nil, err
}

defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
c.logger.Error("Failed to get user scope", nil, lager.Data{"userScopeEndpoint": userScopeEndpoint, "statusCode": resp.StatusCode})
return nil, fmt.Errorf("Failed to get user scope, statusCode : %v", resp.StatusCode)
}

userScope := struct {
Scope []string `json:"scope"`
}{}
err = json.NewDecoder(resp.Body).Decode(&userScope)
if err != nil {
c.logger.Error("Failed to parse user scope response body", err, lager.Data{"userScopeEndpoint": userScopeEndpoint})
return nil, err
}
return userScope.Scope, nil
}

func (c *CtxClient) getUserId(ctx context.Context, userToken string) (UserId, error) {
endpoints, err := c.GetEndpoints(ctx)
if err != nil {
Expand Down Expand Up @@ -167,15 +129,3 @@ func (c *CtxClient) getSpaceId(ctx context.Context, appId Guid) (SpaceId, error)

return spaceId, nil
}

func (c *CtxClient) getUserScopeEndpoint(ctx context.Context, userToken string) (string, error) {
parameters := url.Values{}
parameters.Add("token", strings.Split(userToken, " ")[1])

endpoints, err := c.GetEndpoints(ctx)
if err != nil {
return "", err
}
userScopeEndpoint := endpoints.Uaa.Url + "/check_token?" + parameters.Encode()
return userScopeEndpoint, nil
}

0 comments on commit 95699a3

Please sign in to comment.