Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error msg if API Token is expired #1634

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions cmd/cloud/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ import (
)

var (
authLogin = auth.Login
defaultDomain = "astronomer.io"
client = httputil.NewHTTPClient()
isDeploymentFile = false
parseAPIToken = util.ParseAPIToken
errNotAPIToken = errors.New("the API token given does not appear to be an Astro API Token")
authLogin = auth.Login
defaultDomain = "astronomer.io"
client = httputil.NewHTTPClient()
isDeploymentFile = false
parseAPIToken = util.ParseAPIToken
errNotAPIToken = errors.New("the API token given does not appear to be an Astro API Token")
errExpiredAPIToken = errors.New("the API token given has expired")
)

const (
Expand Down Expand Up @@ -222,7 +223,6 @@ func refresh(refreshToken string, authConfig auth.Config) (TokenResponse, error)
var tokenRes TokenResponse

err = json.NewDecoder(res.Body).Decode(&tokenRes)

if err != nil {
return TokenResponse{}, fmt.Errorf("cannot decode response: %w", err)
}
Expand Down Expand Up @@ -307,7 +307,6 @@ func checkAPIKeys(platformCoreClient astroplatformcore.CoreClient, isDeploymentF
var tokenRes TokenResponse

err = json.NewDecoder(res.Body).Decode(&tokenRes)

if err != nil {
return false, fmt.Errorf("cannot decode response: %w", err)
}
Expand Down Expand Up @@ -407,6 +406,10 @@ func checkAPIToken(isDeploymentFile bool, platformCoreClient astroplatformcore.C
if len(claims.Permissions) == 0 {
return false, errNotAPIToken
}
if claims.ExpiresAt.Before(time.Now()) {
fmt.Printf("The given API Token %s has expired \n", claims.APITokenID)
return false, errExpiredAPIToken
}

var wsID, orgID string
for _, permission := range claims.Permissions {
Expand Down
80 changes: 71 additions & 9 deletions cmd/cloud/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
"io"
"net/http"
"testing"
"time"

"github.com/golang-jwt/jwt/v4"

astroplatformcore "github.com/astronomer/astro-cli/astro-client-platform-core"
"github.com/astronomer/astro-cli/config"
Expand Down Expand Up @@ -328,6 +331,8 @@ func TestCheckToken(t *testing.T) {
}

func TestCheckAPIToken(t *testing.T) {
var mockClaims util.CustomClaims
var permissions []string
testUtil.InitTestConfig(testUtil.LocalPlatform)
mockOrgsResponse := astroplatformcore.ListOrganizationsResponse{
HTTPResponse: &http.Response{
Expand All @@ -339,14 +344,59 @@ func TestCheckAPIToken(t *testing.T) {
},
},
}
permissions = []string{
"workspaceId:workspace-id",
"organizationId:org-ID",
}
mockClaims = util.CustomClaims{
Permissions: permissions,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "test-issuer",
Subject: "test-subject",
Audience: jwt.ClaimStrings{"audience1", "audience2"}, // Audience can be a single string or an array of strings
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // Set expiration date 24 hours from now
NotBefore: jwt.NewNumericDate(time.Now()), // Set not before to current time
IssuedAt: jwt.NewNumericDate(time.Now()), // Set issued at to current time
ID: "test-id",
},
}

t.Run("test context switch", func(t *testing.T) {
permissions := []string{
"workspaceId:workspace-id",
"organizationId:org-ID",
authLogin = func(domain, token string, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer, shouldDisplayLoginLink bool) error {
return nil
}
mockClaims := util.CustomClaims{

parseAPIToken = func(astroAPIToken string) (*util.CustomClaims, error) {
return &mockClaims, nil
}

mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOrgsResponse, nil).Once()

t.Setenv("ASTRO_API_TOKEN", "token")

// Switch context
domain := "astronomer-dev.io"
err := context.Switch(domain)
assert.NoError(t, err)

// run CheckAPIKeys
_, err = checkAPIToken(true, mockPlatformCoreClient)
assert.NoError(t, err)
})

t.Run("bad claims", func(t *testing.T) {
permissions = []string{}
mockClaims = util.CustomClaims{
Permissions: permissions,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "test-issuer",
Subject: "test-subject",
Audience: jwt.ClaimStrings{"audience1", "audience2"},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
NotBefore: jwt.NewNumericDate(time.Now()),
IssuedAt: jwt.NewNumericDate(time.Now()),
ID: "test-id",
},
}

authLogin = func(domain, token string, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer, shouldDisplayLoginLink bool) error {
Expand All @@ -368,13 +418,25 @@ func TestCheckAPIToken(t *testing.T) {

// run CheckAPIKeys
_, err = checkAPIToken(true, mockPlatformCoreClient)
assert.NoError(t, err)
assert.ErrorIs(t, err, errNotAPIToken)
})

t.Run("bad claims", func(t *testing.T) {
permissions := []string{}
mockClaims := util.CustomClaims{
t.Run("expired token", func(t *testing.T) {
permissions = []string{
"workspaceId:workspace-id",
"organizationId:org-ID",
}
mockClaims = util.CustomClaims{
Permissions: permissions,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "test-issuer",
Subject: "test-subject",
Audience: jwt.ClaimStrings{"audience1", "audience2"},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(-1 * time.Hour)),
NotBefore: jwt.NewNumericDate(time.Now()),
IssuedAt: jwt.NewNumericDate(time.Now()),
ID: "test-id",
},
}

authLogin = func(domain, token string, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer, shouldDisplayLoginLink bool) error {
Expand All @@ -396,6 +458,6 @@ func TestCheckAPIToken(t *testing.T) {

// run CheckAPIKeys
_, err = checkAPIToken(true, mockPlatformCoreClient)
assert.ErrorIs(t, err, errNotAPIToken)
assert.ErrorIs(t, err, errExpiredAPIToken)
})
}
3 changes: 3 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ Welcome to the Astro CLI, the modern command line interface for data orchestrati
if strings.Contains(err.Error(), "token is invalid or malformed") {
return errors.New("API Token is invalid or malformed") //nolint
}
if strings.Contains(err.Error(), "the API token given has expired") {
return errors.New("API Token is expired") //nolint
}
softwareCmd.InitDebugLogs = append(softwareCmd.InitDebugLogs, "Error during cmd setup: "+err.Error())
}
}
Expand Down