Skip to content

RUST-2245 Implement GSSAPI auth support for Windows #1444

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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

mattChiaravalloti
Copy link
Collaborator

This PR implements GSSAPI auth support for Windows as described by the spec. Similar to the Linux and Mac implementation in #1413, this one took longer than expected. In the end, it turned out that the sspi crate was not as amenable to this task as initially thought at scope time. I decided to attempt to implement this using the native Windows api (via windows-sys) and modeling it exactly off of libmongoc since I know the C implementation works. Of course, that results in a bit more C-style code than Rust-style code, but after several weeks of investigating and implementing, this is finally working.

I updated the GSSAPI codepath to share common code between Linux/Mac and Windows as much as possible. I only separated out the platform-specific implementations and guarded each with the relevant cfg attributes.

This PR also updates the e2e tests to run on Windows. I observed this implementation passing my local testing on a Windows host, and the e2e tests passing on this patch. I anticipate the evergreen patch associated with this PR to succeed off the bat, as well.

Copy link

Assigned rishitb-mongodb for team dbx-rust because abr-egn is out of office.

@mattChiaravalloti mattChiaravalloti requested review from isabelatkinson and removed request for rishitb-mongodb August 6, 2025 19:40
@mattChiaravalloti
Copy link
Collaborator Author

Is it possible to make exceptions to the semgrep policy to allow for the use of these unsafe blocks, or will we need to get rid of them?

@mattChiaravalloti
Copy link
Collaborator Author

Is it possible to make exceptions to the semgrep policy to allow for the use of these unsafe blocks, or will we need to get rid of them?

I investigated further and am not confident SSPI support can be implemented the way our drivers require if we do not use these unsafe blocks.

There are limited crate options for kerberos auth. We've ruled out libgssapi-sys/libgssapi/cross-krb5 since they rely on MIT KRB5. I discovered sspi is insufficient for our needs (it is incapable of producing the token types needed for MongoDB's SASL auth flow when using GSSAPI). Looking through crates.io, there are not any other viable candidates for this, so the windows crate is likely our best option.

Using the native Windows API inherently requires unsafe code. Hopefully we can make an exception for this. I know in the ODBC driver, we have some required unsafe code that is permitted.

@abr-egn
Copy link
Contributor

abr-egn commented Aug 7, 2025

Is it possible to make exceptions to the semgrep policy to allow for the use of these unsafe blocks, or will we need to get rid of them?

I investigated further and am not confident SSPI support can be implemented the way our drivers require if we do not use these unsafe blocks.

There are limited crate options for kerberos auth. We've ruled out libgssapi-sys/libgssapi/cross-krb5 since they rely on MIT KRB5. I discovered sspi is insufficient for our needs (it is incapable of producing the token types needed for MongoDB's SASL auth flow when using GSSAPI). Looking through crates.io, there are not any other viable candidates for this, so the windows crate is likely our best option.

Using the native Windows API inherently requires unsafe code. Hopefully we can make an exception for this. I know in the ODBC driver, we have some required unsafe code that is permitted.

I haven't had the chance to look into this PR in detail, but it should work to use a nosemgrep comment, we've had to do that in a couple other places in the code base (example). My recollection of the policy (I'll verify later) is that as long as we've investigated and have manually validated that the thing semgrep would complain about is not, in fact, a problem it's fine.

@abr-egn abr-egn requested a review from kevinAlbs August 8, 2025 14:54
error::{Error, Result},
};

pub(super) struct GssapiAuthenticator {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not changed in this PR, but this being a fresh file made me realize - this is only ever either

GssapiAuthenticator { pending_ctx: Some(...), established_ctx: None, is_complete: false, ... }

or

GssapiAuthenticator { pending_ctx: None, established_ctx: Some(...), is_complete: true, ... }

right? That seems like it would be better modeled via a state enum, e.g.

enum CtxState {
  Pending(PendingClientCtx),
  Established(ClientCtx),
}

pub(super) struct GssapiAuthenticator {
  ctx: CtxState,
  user_principal: String,
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah that's a nice refactor. I'll make this change.

}

fn acquire_credentials_and_init(&mut self, password: Option<String>) -> Result<Vec<u8>> {
unsafe {
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the only unsafe portion of this is calling AcquireCredentialsHandleW, right? I'd rather see the unsafe blocks as narrowly scoped as possible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point! I started broad to allow for whatever had to be done, but I'll narrow these down now like you suggested 👍


// Perform the final step of Kerberos authentication by gss_unwrap-ing the
// final server challenge, then wrapping the protocol bytes + user principal.
// The resulting token must be sent to the server.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is like a monad transformer 😂

@mattChiaravalloti mattChiaravalloti removed the request for review from isabelatkinson August 8, 2025 20:12
Copy link
Contributor

@isabelatkinson isabelatkinson left a comment

Choose a reason for hiding this comment

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

one tiny comment, I did a pass over the C-style code but will similarly defer to @kevinAlbs on the details

Copy link
Contributor

Choose a reason for hiding this comment

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

This filename should be able to stay the same - we stopped using mod.rs files a while ago (https://doc.rust-lang.org/reference/items/modules.html#module-source-filenames)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thank you for pointing this out, I updated this to use the appropriate naming conventions.

Copy link
Contributor

@kevinAlbs kevinAlbs left a comment

Choose a reason for hiding this comment

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

The contribution is much appreciated! I have mostly minor comments and questions.

@mattChiaravalloti
Copy link
Collaborator Author

I suspect the "project fails validation: sync with base branch & run evergreen validate -p <project>" error is related to the ongoing Github problems. When I ran evergreen validate locally just now after merging main, it said the config was valid 👍 We should be able to run this patch whenever Github service is resolved and the evergreen team gives the green light for things to run as expected again.

Copy link
Contributor

@kevinAlbs kevinAlbs left a comment

Choose a reason for hiding this comment

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

LGTM!

@mattChiaravalloti
Copy link
Collaborator Author

I retagged everyone, but feel free to just take a look at the parts you commented on previously. I know this is a big and confusing PR. Plus, with 4 reviewers on this it could get hectic having too many cooks. Kevin's LGTM on the core functionality will be the primary indicator this is ready to merge 👍 Thanks for all the review and guidance on this one.

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.

5 participants