21703: Merge branch 'main' into 21703-collection-update-lock
[arvados.git] / lib / controller / localdb / authorized_key.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package localdb
6
7 import (
8         "context"
9         "errors"
10         "fmt"
11         "net/http"
12         "strings"
13
14         "git.arvados.org/arvados.git/sdk/go/arvados"
15         "git.arvados.org/arvados.git/sdk/go/httpserver"
16         "golang.org/x/crypto/ssh"
17 )
18
19 // AuthorizedKeyCreate checks that the provided public key is valid,
20 // then proxies to railsproxy.
21 func (conn *Conn) AuthorizedKeyCreate(ctx context.Context, opts arvados.CreateOptions) (arvados.AuthorizedKey, error) {
22         if err := validateKey(opts.Attrs); err != nil {
23                 return arvados.AuthorizedKey{}, httpserver.ErrorWithStatus(err, http.StatusBadRequest)
24         }
25         return conn.railsProxy.AuthorizedKeyCreate(ctx, opts)
26 }
27
28 // AuthorizedKeyUpdate checks that the provided public key is valid,
29 // then proxies to railsproxy.
30 func (conn *Conn) AuthorizedKeyUpdate(ctx context.Context, opts arvados.UpdateOptions) (arvados.AuthorizedKey, error) {
31         if err := validateKey(opts.Attrs); err != nil {
32                 return arvados.AuthorizedKey{}, httpserver.ErrorWithStatus(err, http.StatusBadRequest)
33         }
34         return conn.railsProxy.AuthorizedKeyUpdate(ctx, opts)
35 }
36
37 func validateKey(attrs map[string]interface{}) error {
38         in, _ := attrs["public_key"].(string)
39         if in == "" {
40                 return nil
41         }
42         in = strings.TrimSpace(in)
43         if strings.IndexAny(in, "\r\n") >= 0 {
44                 return errors.New("Public key does not appear to be valid: extra data after key")
45         }
46         pubkey, _, _, rest, err := ssh.ParseAuthorizedKey([]byte(in))
47         if err != nil {
48                 return fmt.Errorf("Public key does not appear to be valid: %w", err)
49         }
50         if len(rest) > 0 {
51                 return errors.New("Public key does not appear to be valid: extra data after key")
52         }
53         if i := strings.Index(in, " "); i < 0 {
54                 return errors.New("Public key does not appear to be valid: no leading type field")
55         } else if in[:i] != pubkey.Type() {
56                 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())
57         }
58         return nil
59 }