Skip to content

Conversation

adombeck
Copy link
Contributor

If the context of the IsAuthenticated call from the PAM module to authd is cancelled, e.g. because the process of the PAM module exits, we want to automatically cancel the IsAuthenticated call to the broker, to avoid doing any further work towards authenticating the user (like sending requests to OAuth2 endpoints).

@adombeck
Copy link
Contributor Author

I manually tested the changes by running sudo login ... and then cancelling the login via Ctrl+C when prompted to scan the QR code. The IsAuthenticated call to the broker is correctly cancelled, no more requests are sent to the token endpoint.

However, this comment:

// We don’t want to cancel the context when the parent call is cancelled.

... indicates that the previous behavior was on purpose. I did some investigations to find out the reason.

The functionality to cancel IsAuthenticated calls from authd to the broker via a separate CancelIsAuthenticated method was introduced in #4 which closed UDENG-1107. That issue states "it was not possible to send a context through a dbus call". However, the godbus package does provide the CallWithContext method which automatically cancels the D-Bus call when the context is cancelled. I suspect that this was overlooked back then, and that there is not actually a good reason to not cancel the IsAuthenticated when the context is cancelled.

The first implementation actually used CallWithContext with the context, but that was changed in 53f1f92. The comment itself was added later in 4b312ca.

@denisonbarbosa, do you remember any more details? Am I missing something?

@adombeck
Copy link
Contributor Author

adombeck commented Apr 30, 2025

Ok, I figured out what I was missing. The Ctrl+C to the PAM module causes an EndSession request to be sent to the broker, which then calls CancelIsAuthenticated. So the IsAuthenticated call is not cancelled because the context was cancelled on the client side, but because the client called EndSession. The CallWithContext provided by the Go dbus module does not actually cause the call to be cancelled on the server side, it only cancels the request on the client side. I'll add a code comment which explains all that, so that we don't waste time on it again.

@3v1n0
Copy link
Collaborator

3v1n0 commented Apr 30, 2025

Yeah... Sorry for not mentioning it in the card, but I also did some experiments with that after I wrote the initial thing, login disconnecting doesn't bring anything new to us.

So I feel we'll have to do process monitoring or something instead.

The Go process started by the PAM module kept running even after the
process of the PAM module exited, causing authd to continue with the
authentication procedure.
This is needed to be able to check the underlying error with errors.Is
or errors.As.
@adombeck adombeck force-pushed the UDENG-6770-avoid-polling-after-login-request-cancelled branch from 631cd42 to afb8cea Compare April 30, 2025 11:14
@adombeck
Copy link
Contributor Author

With the new commits I pushed, cancellation also works when I run sudo login ... and let it time out.

D-Bus does not support cancelling ongoing method calls through context
cancellation, in contrast to gRPC. So if the context of the
IsAuthenticated call from the PAM module to authd is cancelled (e.g.
because the PAM module exited unexpectedly), we need propagate that to
the broker by calling the CancelIsAuthenticated method.

We used to do that by calling IsAuthenticated in a goroutine and
waiting for the context to be cancelled in the main goroutine, calling
CancelIsAuthenticated when the context is cancelled.

This commit simplifies that, by passing the context to BusObject.CallWithContext, and calling
when the returned error is context.Cancelled.

This is only done for the D-Bus broker, not the example broker. That's
not a problem, because the example broker already cancels the
IsAuthenticated call if the context is cancelled, without requiring a
separate CancelIsAuthenticated call.

This commit also returns auth.Cancelled if the context was cancelled,
which was actually never used with the actual D-Bus broker, but with the
example broker and the testutils.BrokerBusMock.
The first call was cancelled iff cancelFirstCall is false.
@adombeck adombeck force-pushed the UDENG-6770-avoid-polling-after-login-request-cancelled branch from afb8cea to e44b939 Compare April 30, 2025 11:47
Comment on lines +32 to +34
if err := unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(syscall.SIGTERM), 0, 0, 0); err != nil {
log.Errorf(context.Background(), "failed to set PDEATHSIG: %v", err)
os.Exit(1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was wondering to use the same too... But maybe we can handle it also client-side, on the dbus side... Let me check that too.

However this is fine.

The changes on broker instead I'd hold since I had some refactoring there for another branch, and that side is quite delicate sadly (as we may cancel too early).

Comment on lines +109 to +110
b.CancelIsAuthenticated(context.Background(), sessionID)
return auth.Cancelled, "", nil
Copy link
Member

@denisonbarbosa denisonbarbosa Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this create a race? CancelIsAuthenticated is not a blocking call, so (also considering that the "wait" was removed on the IsAuthenticated function) we can end up returning to PAM without the broker being "ready" to handle a new call, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CancelIsAuthenticated is not a blocking call

Really? It also uses BusObject.CallWithContext from the dbus package, which according to the documentation waits for a reply.

Copy link
Member

@denisonbarbosa denisonbarbosa Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the dbus call returns, but if you look at the CancelIsAuthenticated func on the broker side, it's not waiting for the cancellation to be done, it just requests a cancel and then the IsAuthenticated func that returns whether it was cancelled or not. Did it make sense? It's not easy to explain

@adombeck adombeck force-pushed the UDENG-6770-avoid-polling-after-login-request-cancelled branch from e44b939 to c576d00 Compare April 30, 2025 13:02
@codecov-commenter
Copy link

Codecov Report

Attention: Patch coverage is 76.47059% with 4 lines in your changes missing coverage. Please review.

Project coverage is 85.38%. Comparing base (5863e33) to head (c576d00).

Files with missing lines Patch % Lines
pam/main-exec.go 42.85% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #903      +/-   ##
==========================================
- Coverage   85.51%   85.38%   -0.14%     
==========================================
  Files          82       82              
  Lines        5703     5707       +4     
  Branches      109      109              
==========================================
- Hits         4877     4873       -4     
- Misses        771      779       +8     
  Partials       55       55              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants