Merge branch 'main' into 18842-arv-mount-disk-config
[arvados.git] / lib / controller / localdb / logout.go
index e6b6f6c585c008c49eedd97f8ec5603db6d632e7..04e7681ad7bef728bb11e5c745c2b8391094b2d5 100644 (file)
@@ -9,17 +9,42 @@ import (
        "database/sql"
        "errors"
        "fmt"
+       "net/http"
        "strings"
 
        "git.arvados.org/arvados.git/lib/ctrlctx"
+       "git.arvados.org/arvados.git/sdk/go/arvados"
        "git.arvados.org/arvados.git/sdk/go/auth"
        "git.arvados.org/arvados.git/sdk/go/ctxlog"
+       "git.arvados.org/arvados.git/sdk/go/httpserver"
 )
 
-func (conn *Conn) expireAPIClientAuthorization(ctx context.Context) error {
+func logout(ctx context.Context, cluster *arvados.Cluster, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) {
+       err := expireAPIClientAuthorization(ctx)
+       if err != nil {
+               ctxlog.FromContext(ctx).Errorf("attempting to expire token on logout: %q", err)
+               return arvados.LogoutResponse{}, httpserver.ErrorWithStatus(errors.New("could not expire token on logout"), http.StatusInternalServerError)
+       }
+
+       target := opts.ReturnTo
+       if target == "" {
+               if cluster.Services.Workbench2.ExternalURL.Host != "" {
+                       target = cluster.Services.Workbench2.ExternalURL.String()
+               } else {
+                       target = cluster.Services.Workbench1.ExternalURL.String()
+               }
+       } else if err := validateLoginRedirectTarget(cluster, target); err != nil {
+               return arvados.LogoutResponse{}, httpserver.ErrorWithStatus(fmt.Errorf("invalid return_to parameter: %s", err), http.StatusBadRequest)
+       }
+       return arvados.LogoutResponse{RedirectLocation: target}, nil
+}
+
+func expireAPIClientAuthorization(ctx context.Context) error {
        creds, ok := auth.FromContext(ctx)
        if !ok {
-               return errors.New("credentials not found from context")
+               // Tests could be passing empty contexts
+               ctxlog.FromContext(ctx).Debugf("expireAPIClientAuthorization: credentials not found from context")
+               return nil
        }
 
        if len(creds.Tokens) == 0 {
@@ -52,13 +77,14 @@ func (conn *Conn) expireAPIClientAuthorization(ctx context.Context) error {
                ctxlog.FromContext(ctx).WithError(err).Debugf("expireAPIClientAuthorization(%s): database error", token)
                return err
        }
+
        if tokenUuid != "" && retrievedUuid != tokenUuid {
                // secret part matches, but UUID doesn't -- somewhat surprising
                ctxlog.FromContext(ctx).Debugf("expireAPIClientAuthorization(%s): secret part found, but with different UUID: %s", tokenSecret, retrievedUuid)
                return nil
        }
 
-       res, err := tx.ExecContext(ctx, "UPDATE api_client_authorizations SET expires_at=current_timestamp AT TIME ZONE 'UTC' WHERE api_token=$1 AND (expires_at IS NULL OR expires_at > current_timestamp AT TIME ZONE 'UTC')", tokenSecret)
+       res, err := tx.ExecContext(ctx, "UPDATE api_client_authorizations SET expires_at=current_timestamp AT TIME ZONE 'UTC' WHERE uuid=$1", retrievedUuid)
        if err != nil {
                return err
        }