Using credential providers [for custom registries]

(Continuing from this thread)

Thanks to @shepmaster I got authentication working; as suggested in the other thread, "token" shouldn't be taken too literally. When accessing http resources cargo will first attempt to use an unauthenticated access. If it receives a 401 it will treat the "token" as a http Authorization header value. The "token" value should be the same format as the http header value, using the Basic scheme.

However, I'd like to understand how to use the platform-specific credential storage to store secrets, which cargo appears to support.

These can (allegedly) be enabled by adding cargo:macos-keychain (on macos) as a credential provider. This can either be done globally, or to a specific registry. I did this:

[registries.my-reg]
index = "sparse+http://127.0.0.1:8000/"
credential-provider = ["cargo:macos-keychain"]

.. is this correct? It feels a little odd to have a list when the key is singular (the global setting is plural).

As far as I can tell, looking at the code, the idea is that the "password" is simply the "token value". I.e. it should contain the Basic <base64 blob>. The code says that "account" isn't used and is empty. I don't know what the exact implications of this are. It looks up the password by the service set to let service_name = registry(reg.index_url);. The registry() function simply adds a cargo-registry: in front of whatever is passed to reg.index_url.

I tried to open up my keychain and simply add a new item. In the "Keychain Item Name" I filled in cargo-registry:sparse+http://127.0.0.1:8000/. The "Account Name" needs to be set to something, so I set it to some random value. For the "Password" I set the token blob that worked when I put it in ~/.cargo/config.toml.

Once this has been added, I get an entry which is broken in interesting ways. the "Name" is <unknown>, "Kind" is "Internet password", "Account" is foo and "Where" is ¯:// (yes..). (Anyone who wants to go hunt for a CVE due to unvalidated input in Apple's Keychain application .. you're welcome).

I think it's the : and + that throws the keychain app off, because if I just put in a plain ol' http://127.0.0.1 it doesn't explode.

Anyway -- all this is to ask the simple question: How does one format a Keychain item so that cargo can pick it up for a custom registry?

I set up cargo:macos-keychain as my global credential provider and then used cargo login to store my token. The keychain entry looks like:

Name: cargo-registry:https://github.com/rust-lang/crates.io-index
Kind: application password
Where: cargo-registry:https://github.com/rust-lang/crates.io-index

Account and Comments are blank, and the password contains the token.

Perhaps substituting your registry URL for the crates-io one would work?

Just to get a reference, I tried to use a credential provider on Windows, using cargo-wincred. I had basically the same initial issue -- I wasn't 100% certain that I understood how to format the credential, but I looked at what the code did and it seemed to do much the same as macos-keychain, so I assumed it wanted the "location" to be cargo-registry:sparse+http://127.0.0.1:8000/, and the password to be the same "token" as on macos.

This had a measurable effect, unfortunately cargo just ended up saying error: [75] Unknown error. However, this isn't necessarily bad news, because that means I can see that cargo is picking up the credential item (a point I never really reached on macos).

It looks like:

  • macos-keychain can't be used, because the Keychain app is broken (it generates garbage if you try to mix in some : and + int the name). (Perhaps if one uses an alternative means of adding a credential item, it may work -- but the Keychain app is currently unhelpful).
  • wincred seems to be broken; may be an actual issue in cargo.

Should probably test it on Linux as well, while I'm on a roll. It would be nice to see it work on some system, just so I can verify that I have done everything correctly.

This worked for me:

% cargo build
    Updating `my-awesome-registry` index
    Updating crates.io index
     Locking 8 packages to latest compatible versions

(I had other issues because this is my junk test registry and the URL in config.json didn't match the actual URL, but it successfully authenticated).

1 Like

Well I'll be -- that worked. I tried to create it in Local Items rather than login (because I read somewhere that login is "legacy"). I really should have tried login as well.

Thank you!

1 Like

It is singular because you can only specify one provider for a specific registry. It is an array to give you the option to pass arguments to the provider. It can also just be a plain string if it doesn't have any arguments.

registry.global-credential-providers supports multiple providers, but does not support arguments directly. There is a separate alias table for that.

Ah, right -- yeah, that makes sense. It didn't occur to me that providers may need multiple arguments. I've been so focused on macos-keychain and wincred, but I see now that the 1password provider takes arguments.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.