// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 package localdb import ( "context" "errors" "fmt" "net/http" "strings" "git.arvados.org/arvados.git/sdk/go/arvados" "git.arvados.org/arvados.git/sdk/go/httpserver" "golang.org/x/crypto/ssh" ) // AuthorizedKeyCreate checks that the provided public key is valid, // then proxies to railsproxy. func (conn *Conn) AuthorizedKeyCreate(ctx context.Context, opts arvados.CreateOptions) (arvados.AuthorizedKey, error) { if err := validateKey(opts.Attrs); err != nil { return arvados.AuthorizedKey{}, httpserver.ErrorWithStatus(err, http.StatusBadRequest) } return conn.railsProxy.AuthorizedKeyCreate(ctx, opts) } // AuthorizedKeyUpdate checks that the provided public key is valid, // then proxies to railsproxy. func (conn *Conn) AuthorizedKeyUpdate(ctx context.Context, opts arvados.UpdateOptions) (arvados.AuthorizedKey, error) { if err := validateKey(opts.Attrs); err != nil { return arvados.AuthorizedKey{}, httpserver.ErrorWithStatus(err, http.StatusBadRequest) } return conn.railsProxy.AuthorizedKeyUpdate(ctx, opts) } func validateKey(attrs map[string]interface{}) error { in, _ := attrs["public_key"].(string) if in == "" { return nil } in = strings.TrimSpace(in) if strings.IndexAny(in, "\r\n") >= 0 { return errors.New("Public key does not appear to be valid: extra data after key") } pubkey, _, _, rest, err := ssh.ParseAuthorizedKey([]byte(in)) if err != nil { return fmt.Errorf("Public key does not appear to be valid: %w", err) } if len(rest) > 0 { return errors.New("Public key does not appear to be valid: extra data after key") } if i := strings.Index(in, " "); i < 0 { return errors.New("Public key does not appear to be valid: no leading type field") } else if in[:i] != pubkey.Type() { return fmt.Errorf("Public key does not appear to be valid: leading type field %q does not match actual key type %q", in[:i], pubkey.Type()) } return nil }