-
Notifications
You must be signed in to change notification settings - Fork 0
/
session_user_key.go
89 lines (71 loc) · 2.29 KB
/
session_user_key.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package cassh
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"golang.org/x/crypto/ssh"
"github.com/krostar/httpclient"
)
// Key allows the manipulation of the user key.
func (s *SessionUser) Key(key ssh.PublicKey) *SessionUserKey {
return &SessionUserKey{
api: s.api.Clone(),
key: key,
parentCreateRequestParameters: s.createRequestParameters,
}
}
// SessionUserKey stores attributes useful to make requests related to user's keys, to the CASSH server.
type SessionUserKey struct {
api *httpclient.API
key ssh.PublicKey
parentCreateRequestParameters func() url.Values
}
func (s *SessionUserKey) createRequestParameters() url.Values {
requestParameters := s.parentCreateRequestParameters()
requestParameters.Set("pubkey", string(ssh.MarshalAuthorizedKey(s.key)))
return requestParameters
}
// Set sets the user key.
func (s *SessionUserKey) Set(ctx context.Context) error {
return s.api.Execute(ctx, s.api.Put("/client").SendForm(s.createRequestParameters()))
}
// Sign returns a certificate signed by the CASSH server.
func (s *SessionUserKey) Sign(ctx context.Context, opts ...SessionUserKeySignOption) (*ssh.Certificate, error) {
o := sessionUserKeySignOptionsDefault()
for _, opt := range opts {
opt(o)
}
requestParameters := s.createRequestParameters()
if o.force {
requestParameters.Set("admin_force", strconv.FormatBool(true))
}
var certificate ssh.Certificate
if err := s.api.
Do(ctx, s.api.Post("/client").SendForm(requestParameters)).
OnStatus(http.StatusOK, s.signParseSuccessResponse(&certificate)).
Error(); err != nil {
return nil, err
}
return &certificate, nil
}
func (*SessionUserKey) signParseSuccessResponse(certificate *ssh.Certificate) httpclient.ResponseHandler {
return func(resp *http.Response) error {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("unable to read body: %v", err)
}
publicKey, _, _, _, err := ssh.ParseAuthorizedKey(body)
if err != nil {
return fmt.Errorf("unable to parse ssh certificate from raw openssh certificate: %v", err)
}
if responseCertificate, ok := publicKey.(*ssh.Certificate); ok {
*certificate = *responseCertificate
return nil
}
return errors.New("authorized key is not a certificate")
}
}