-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathauth_requestor_auto.go
More file actions
102 lines (90 loc) · 3.48 KB
/
auth_requestor_auto.go
File metadata and controls
102 lines (90 loc) · 3.48 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2026 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package secboot
import (
"context"
"errors"
"fmt"
"io"
)
var (
newPlymouthAuthRequestor = NewPlymouthAuthRequestor
newSystemdAuthRequestor = NewSystemdAuthRequestor
)
type autoAuthRequestor struct {
requestors []AuthRequestor
lastUsed AuthRequestor
}
func (r *autoAuthRequestor) RequestUserCredential(ctx context.Context, name, path string, authTypes UserAuthType) (string, UserAuthType, error) {
for _, req := range r.requestors {
switch cred, credType, err := req.RequestUserCredential(ctx, name, path, authTypes); {
case err == nil:
r.lastUsed = req
fallthrough
case !errors.Is(err, ErrAuthRequestorNotAvailable):
return cred, credType, err
}
}
return "", 0, ErrAuthRequestorNotAvailable
}
func (r *autoAuthRequestor) NotifyUserAuthResult(ctx context.Context, result UserAuthResult, authTypes, exhaustedAuthTypes UserAuthType) error {
if r.lastUsed == nil {
return errors.New("no user credential requested yet")
}
return r.lastUsed.NotifyUserAuthResult(ctx, result, authTypes, exhaustedAuthTypes)
}
// NewAutoAuthRequestor creates an implementation of AuthRequestor that automatically
// selects the first available implementation in the following order:
// - Plymouth.
// - systemd-ask-password.
//
// The returned implementation selects the underlying implementation on each call to
// [AuthRequestor.RequestUserCredential] by skipping any that return
// [ErrAuthRequestorNotAvailable]. The selected implementation is used in the subsequent
// call to [AuthRequestor.NotifyUserAuthResult]. Note that if the selected implementation
// returns [ErrAuthRequestorNotAvailable] here, then this is returned directly.
//
// The caller supplies an implementation of AuthRequestorStringer that returns messages.
// The console argument is used by the systemd-ask-password implementation of
// [AuthRequestor.NotifyUserAuthResult] where result is not [UserAuthResultSuccess]. If not
// provided, it defaults to [os.Stderr].
func NewAutoAuthRequestor(stderr io.Writer, stringer AuthRequestorStringer) (AuthRequestor, error) {
var requestors []AuthRequestor
switch ply, err := newPlymouthAuthRequestor(stringer); {
case errors.Is(err, ErrAuthRequestorNotAvailable):
// ignore
case err != nil:
return nil, fmt.Errorf("cannot create Plymouth AuthRequestor: %w", err)
default:
requestors = append(requestors, ply)
}
switch sd, err := newSystemdAuthRequestor(stderr, func(name, path string, authTypes UserAuthType) (string, error) {
return stringer.RequestUserCredentialString(name, path, authTypes)
}); {
case errors.Is(err, ErrAuthRequestorNotAvailable):
// ignore
case err != nil:
return nil, fmt.Errorf("cannot create systemd AuthRequestor: %w", err)
default:
requestors = append(requestors, sd)
}
if len(requestors) == 0 {
return nil, ErrAuthRequestorNotAvailable
}
return &autoAuthRequestor{requestors: requestors}, nil
}