Skip to content

Commit

Permalink
gracefully handle expired auth sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
iximiuz committed Sep 27, 2024
1 parent ff7d6b0 commit 69acfff
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 5 deletions.
22 changes: 19 additions & 3 deletions cmd/auth/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package auth
import (
"context"
"fmt"
"log/slog"
"time"

"github.com/briandowns/spinner"
Expand Down Expand Up @@ -67,9 +68,24 @@ func newLoginCommand(cli labcli.CLI) *cobra.Command {

func runLogin(ctx context.Context, cli labcli.CLI, opts loginOptions) error {
if cli.Config().SessionID != "" && cli.Config().AccessToken != "" {
return labcli.NewStatusError(1,
"Already logged in. Use 'labctl auth logout' first if you want to log in as a different user.",
)
if _, err := cli.Client().GetMe(ctx); err == nil {
return labcli.NewStatusError(1,
"Already logged in. Use 'labctl auth logout' first if you want to log in as a different user.",
)
}

// Cleaning the expired session.
if err := ssh.RemoveIdentity(cli.Config().SSHDir); err != nil {
slog.Debug("Could not remove SSH identity file", "error", err.Error())
}

cli.Config().SessionID = ""
cli.Config().AccessToken = ""
if err := cli.Config().Dump(); err != nil {
return err
}

cli.Client().SetCredentials("", "")
}

if opts.sessionID != "" && opts.accessToken != "" {
Expand Down
8 changes: 6 additions & 2 deletions cmd/auth/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package auth

import (
"context"
"errors"
"log/slog"

"github.com/spf13/cobra"

"github.com/iximiuz/labctl/internal/api"
"github.com/iximiuz/labctl/internal/labcli"
"github.com/iximiuz/labctl/internal/ssh"
)
Expand All @@ -28,9 +30,11 @@ func runLogout(ctx context.Context, cli labcli.CLI) error {
return nil
}

// TODO: Check HTTP 404 explicitly to handle the case when the session is already deleted.
if err := cli.Client().DeleteSession(ctx, cli.Config().SessionID); err != nil {
return err
if !errors.Is(err, api.ErrAuthenticationRequired) {
slog.Warn("Failed to delete session", "error", err.Error())
return err
}
}

if err := ssh.RemoveIdentity(cli.Config().SSHDir); err != nil {
Expand Down
7 changes: 7 additions & 0 deletions cmd/auth/whoami.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package auth

import (
"context"
"errors"

"github.com/iximiuz/labctl/internal/api"
"github.com/iximiuz/labctl/internal/labcli"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
Expand All @@ -29,6 +31,11 @@ func runWhoAmI(ctx context.Context, cli labcli.CLI) error {

me, err := cli.Client().GetMe(ctx)
if err != nil {
if errors.Is(err, api.ErrAuthenticationRequired) {
cli.PrintErr("Authentication session expired. Please log in again: labctl auth login\n")
return nil
}

return err
}

Expand Down
12 changes: 12 additions & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
Expand All @@ -13,6 +14,12 @@ import (
"strings"
)

var ErrAuthenticationRequired = errors.New("authentication required")

func isAuthenticationRequiredResponse(resp *http.Response) bool {
return resp.StatusCode == http.StatusUnauthorized
}

type Client struct {
baseURL string
apiBaseURL string
Expand Down Expand Up @@ -345,6 +352,11 @@ func (c *Client) doRequest(req *http.Request) (*http.Response, error) {
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()

if isAuthenticationRequiredResponse(resp) {
return nil, ErrAuthenticationRequired
}

return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, body)
}

Expand Down
1 change: 1 addition & 0 deletions internal/api/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ func (c *Client) DeleteSession(ctx context.Context, id string) error {
if err != nil {
return err
}

return resp.Body.Close()
}

0 comments on commit 69acfff

Please sign in to comment.