Skip to content

Commit

Permalink
Merge pull request #23 from duplocloud/DUPLO-13529-better-duplo-token…
Browse files Browse the repository at this point in the history
…-ping-api

DUPLO-13529 Detect token invalidation from user logout
  • Loading branch information
joek-duplo authored Dec 21, 2023
2 parents ce42e2a + c6a1087 commit c0aa639
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 8 deletions.
13 changes: 13 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@
"--interactive"
],
},
{
"name": "Duplo",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/duplo-jit/main.go",
"args": [
"duplo",
"--host",
"https://test20.duplocloud.net",
"--interactive"
],
},
{
"name": "K8s Plan",
"type": "go",
Expand Down
4 changes: 2 additions & 2 deletions cmd/duplo-aws-credential-process/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func main() {
// Otherwise, get the credentials from Duplo.
if creds == nil {
client := mustDuploClient(*host, *token, *interactive, true)
result, err := client.AdminGetJITAwsCredentials()
result, err := client.AdminGetJitAwsCredentials()
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
}
Expand Down Expand Up @@ -143,7 +143,7 @@ func main() {
}

// Tenant: Get the JIT AWS credentials
result, err := client.TenantGetJITAwsCredentials(*tenantID)
result, err := client.TenantGetJitAwsCredentials(*tenantID)
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/duplo-jit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func main() {
// Otherwise, get the credentials from Duplo.
if creds == nil {
client, _ := internal.MustDuploClient(*host, *token, *interactive, true)
result, err := client.AdminGetJITAwsCredentials()
result, err := client.AdminGetJitAwsCredentials()
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
}
Expand Down Expand Up @@ -148,7 +148,7 @@ func main() {
// Otherwise, get the credentials from Duplo.
if creds == nil {
// Tenant: Get the JIT AWS credentials
result, err := client.TenantGetJITAwsCredentials(*tenantID)
result, err := client.TenantGetJitAwsCredentials(*tenantID)
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
}
Expand Down
27 changes: 24 additions & 3 deletions duplocloud/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ type DuploSystemFeatures struct {
TenantNameMaxLength int `json:"TenantNameMaxLength"`
}

// DuploTenantFeatures represents configured features for the tenant
type DuploTenantFeatures struct {
Region string `json:"Region,omitempty"`
IsKubernetesEnabled bool `json:"IsKubernetesEnabled"`
UseLbIndex bool `json:"UseLbIndex"`
}

// DuploPlanK8ClusterConfig represents a k8s system configuration
type DuploPlanK8ClusterConfig struct {
Name string `json:"Name,omitempty"`
Expand Down Expand Up @@ -94,15 +101,15 @@ func (c *Client) AdminGetK8sJitAccess(plan string) (*DuploPlanK8ClusterConfig, C
}

// AdminGetJITAwsCredentials retrieves just-in-time admin AWS credentials via the Duplo API.
func (c *Client) AdminGetJITAwsCredentials() (*AwsJitCredentials, ClientError) {
func (c *Client) AdminGetJitAwsCredentials() (*AwsJitCredentials, ClientError) {
return c.AdminAwsGetJitAccess("admin")
}

// TenantGetJITAwsCredentials retrieves just-in-time AWS credentials for a tenant via the Duplo API.
func (c *Client) TenantGetJITAwsCredentials(tenantID string) (*AwsJitCredentials, ClientError) {
func (c *Client) TenantGetJitAwsCredentials(tenantID string) (*AwsJitCredentials, ClientError) {
creds := AwsJitCredentials{}
err := c.getAPI(
fmt.Sprintf("TenantGetAwsCredentials(%s)", tenantID),
fmt.Sprintf("TenantGetJitAwsCredentials(%s)", tenantID),
fmt.Sprintf("subscriptions/%s/GetAwsConsoleTokenUrl", tenantID),
&creds,
)
Expand Down Expand Up @@ -136,6 +143,20 @@ func (c *Client) ListTenantsForUser() (*[]UserTenant, ClientError) {
return &list, nil
}

func (c *Client) GetTenantFeatures(tenantId string) (*DuploTenantFeatures, ClientError) {
features := DuploTenantFeatures{}
err := c.getAPI(
fmt.Sprintf("GetTenantFeatures(%s)", tenantId),
fmt.Sprintf("v3/features/tenant/%s", tenantId),
&features,
)
if err != nil {
return nil, err
}

return &features, nil
}

// GetTenantByNameForUser retrieves a single tenant by name for the current user via the Duplo API.
func (c *Client) GetTenantByNameForUser(name string) (*UserTenant, ClientError) {
// Get all tenants.
Expand Down
9 changes: 8 additions & 1 deletion internal/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func CacheGetDuploOutput(cacheKey string, host string) (creds *DuploCredsOutput)

// Check credentials for expiry - by trying to retrieve system features
if creds != nil {
// Retrieve system features. This also validates the creds.
// Retrieve system features.
client, err := duplocloud.NewClient(host, creds.DuploToken)
if err == nil {
var features *duplocloud.DuploSystemFeatures
Expand All @@ -158,6 +158,13 @@ func CacheGetDuploOutput(cacheKey string, host string) (creds *DuploCredsOutput)
}
}

// Validate creds by executing ping
if creds != nil {
if err := PingDuploCreds(creds, host); err != nil {
creds = nil
}
}

// Clear the cache if the creds expired.
if creds == nil {
cacheRemoveFile(cacheKey, file)
Expand Down
25 changes: 25 additions & 0 deletions internal/duplo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

import (
"encoding/json"
"errors"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -128,3 +129,27 @@ func OutputDuploCreds(creds *DuploCredsOutput) {
os.Stdout.Write(json)
os.Stdout.WriteString("\n")
}

func PingDuploCreds(creds *DuploCredsOutput, host string) error {
client, err := duplocloud.NewClient(host, creds.DuploToken)
if err != nil {
return err
}

tenants, terr := client.ListTenantsForUser()
if terr != nil {
return terr
}

if len(*tenants) == 0 {
return errors.New("PingDuploCreds: user has no tenants")
}

tenant := (*tenants)[0]
_, ferr := client.GetTenantFeatures(tenant.TenantID)
if ferr != nil {
return ferr
}

return nil
}

0 comments on commit c0aa639

Please sign in to comment.