-
Notifications
You must be signed in to change notification settings - Fork 21
AuthRequestor: Add NewAutoAuthRequestor #506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| // -*- 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems because of the ping in the plymouth implementation that this could return ErrAuthRequestorNotAvailable ? is that expected, should it be documented? what should the caller do in that case?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think if plymouth stops in the middle, it is a weird enough context that we should completely fail and just log that error.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the error just gets logged in this case. To be honest, the ping is probably a bit redundant (assuming that |
||
| } | ||
|
|
||
| // NewAutoAuthRequestor creates an implementation of AuthRequestor that automatically | ||
| // selects the first available implementation in the following order: | ||
| // - Plymouth. | ||
| // - systemd-ask-password. | ||
| // | ||
| // 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 | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we mention this where relevant in the doc comments for AuthRequestor interface or the Auto one?