Skip to content

Commit 7efacff

Browse files
committed
Cache CredentialConfig's not tokens.
1 parent aabfb6a commit 7efacff

File tree

6 files changed

+105
-96
lines changed

6 files changed

+105
-96
lines changed

src/cargo/ops/registry.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::util::auth;
4040
/// Registry settings loaded from config files.
4141
///
4242
/// This is loaded based on the `--registry` flag and the config settings.
43-
#[derive(Debug, PartialEq)]
43+
#[derive(Debug, PartialEq, Clone)]
4444
pub enum RegistryCredentialConfig {
4545
None,
4646
/// The authentication token.
@@ -211,12 +211,14 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
211211
};
212212

213213
if !opts.dry_run {
214-
registry.set_token(Some(auth::auth_token(
215-
&opts.config,
216-
&reg_id_no_replacement,
217-
None,
218-
Some(mutation),
219-
)?));
214+
registry.set_token(Some(
215+
auth::auth_token(&opts.config, &reg_id_no_replacement)?.as_header(
216+
&opts.config,
217+
&reg_id_no_replacement,
218+
None,
219+
Some(&mutation),
220+
)?,
221+
));
220222
}
221223

222224
opts.config
@@ -513,11 +515,11 @@ fn registry(
513515
Use the --token command-line flag to remove this warning.",
514516
)?;
515517
}
516-
Some(auth::auth_token(
518+
Some(auth::auth_token(config, &sid_no_replacement)?.as_header(
517519
config,
518520
&sid_no_replacement,
519521
None,
520-
token_required,
522+
token_required.as_ref(),
521523
)?)
522524
} else {
523525
None

src/cargo/sources/registry/download.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ pub(super) fn download(
7171
}
7272

7373
let authorization = if registry_config.auth_required {
74-
Some(auth::auth_token(config, &pkg.source_id(), None, None)?)
74+
Some(auth::auth_token(config, &pkg.source_id())?.as_header(
75+
config,
76+
&pkg.source_id(),
77+
None,
78+
None,
79+
)?)
7580
} else {
7681
None
7782
};

src/cargo/sources/registry/http_remote.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,13 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
541541
"authenticated registries require `-Z registry-auth`"
542542
)));
543543
}
544-
let authorization =
545-
auth::auth_token(self.config, &self.source_id, self.login_url.as_ref(), None)?;
544+
let credential = auth::auth_token(self.config, &self.source_id)?;
545+
let authorization = credential.as_header(
546+
self.config,
547+
&self.source_id,
548+
self.login_url.as_ref(),
549+
None,
550+
)?;
546551
headers.append(&format!("authorization: {}", authorization))?;
547552
trace!("including authorization for {}", full_url);
548553
}

src/cargo/util/auth.rs

Lines changed: 75 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::error::Error;
1212
use std::io::{Read, Write};
1313
use std::path::PathBuf;
1414
use std::process::{Command, Stdio};
15+
use std::rc::Rc;
1516
use time::format_description::well_known::Rfc3339;
1617
use time::OffsetDateTime;
1718
use url::Url;
@@ -269,98 +270,91 @@ my-registry = {{ index = "{}" }}
269270
// Store a token in the cache for future calls.
270271
pub fn cache_token(config: &Config, sid: &SourceId, token: &str) {
271272
let url = sid.canonical_url();
272-
config
273-
.credential_cache()
274-
.insert(url.clone(), token.to_string());
273+
config.credential_cache().insert(
274+
url.clone(),
275+
Rc::new(RegistryCredentialConfig::Token(token.to_string())),
276+
);
275277
}
276278

277279
/// Returns the token to use for the given registry.
278-
/// If a `login_url` is provided and a token is not available, the
279-
/// login_url will be included in the returned error.
280-
pub fn auth_token(
281-
config: &Config,
282-
sid: &SourceId,
283-
login_url: Option<&Url>,
284-
mutation: Option<Mutation<'_>>,
285-
) -> CargoResult<String> {
286-
match auth_token_optional(config, sid, mutation.as_ref())? {
287-
Some(token) => Ok(token),
288-
None => Err(AuthorizationError {
289-
sid: sid.clone(),
290-
login_url: login_url.cloned(),
291-
reason: AuthorizationErrorReason::TokenMissing,
292-
}
293-
.into()),
294-
}
295-
}
296-
297-
/// Returns the token to use for the given registry.
298-
fn auth_token_optional(
299-
config: &Config,
300-
sid: &SourceId,
301-
mutation: Option<&'_ Mutation<'_>>,
302-
) -> CargoResult<Option<String>> {
280+
pub fn auth_token(config: &Config, sid: &SourceId) -> CargoResult<Rc<RegistryCredentialConfig>> {
303281
let mut cache = config.credential_cache();
304282
let url = sid.canonical_url();
305283

306-
if mutation.is_none() {
307-
if let Some(token) = cache.get(url) {
308-
return Ok(Some(token.clone()));
309-
}
284+
if let Some(token) = cache.get(url) {
285+
return Ok(Rc::clone(token));
310286
}
311287

312-
let credential = registry_credential_config(config, sid)?;
313-
let token = match credential {
314-
RegistryCredentialConfig::None => return Ok(None),
315-
RegistryCredentialConfig::Token(config_token) => config_token.to_string(),
316-
RegistryCredentialConfig::Process(process) => {
317-
// todo: PASETO with process
318-
run_command(config, &process, sid, Action::Get)?.unwrap()
319-
}
320-
RegistryCredentialConfig::Key((private_key, private_key_subject)) => {
321-
let secret: AsymmetricSecretKey<pasetors::version3::V3> =
322-
private_key.as_str().try_into()?;
323-
let public: AsymmetricPublicKey<pasetors::version3::V3> = (&secret).try_into()?;
324-
let public_key_id: pasetors::paserk::Id = (&public).into();
325-
let mut kip = String::new();
326-
FormatAsPaserk::fmt(&public_key_id, &mut kip).unwrap();
327-
let iat = OffsetDateTime::now_utc();
328-
329-
let message = Message {
330-
iat: &iat.format(&Rfc3339)?,
331-
sub: private_key_subject.as_deref(),
332-
mutation: mutation.and_then(|m| m.mutation),
333-
name: mutation.and_then(|m| m.name),
334-
vers: mutation.and_then(|m| m.vers),
335-
cksum: mutation.and_then(|m| m.cksum),
336-
challenge: None, // todo: PASETO with challenges,
337-
v: None,
338-
};
339-
let footer = Footer {
340-
url: &sid.url().to_string(),
341-
kip: &kip,
342-
};
343-
344-
pasetors::version3::PublicToken::sign(
345-
&secret,
346-
&public,
347-
serde_json::to_string(&message)
348-
.expect("cannot serialize")
349-
.as_bytes(),
350-
Some(
351-
serde_json::to_string(&footer)
288+
let credential = Rc::new(registry_credential_config(config, sid)?);
289+
290+
cache.insert(url.clone(), Rc::clone(&credential));
291+
Ok(credential)
292+
}
293+
294+
impl RegistryCredentialConfig {
295+
/// If a `login_url` is provided and a token is not available, the
296+
/// login_url will be included in the returned error.
297+
pub fn as_header(
298+
self: &Rc<RegistryCredentialConfig>,
299+
config: &Config,
300+
sid: &SourceId,
301+
login_url: Option<&Url>,
302+
mutation: Option<&'_ Mutation<'_>>,
303+
) -> CargoResult<String> {
304+
Ok(match &**self {
305+
RegistryCredentialConfig::None => {
306+
return Err(AuthorizationError {
307+
sid: sid.clone(),
308+
login_url: login_url.cloned(),
309+
reason: AuthorizationErrorReason::TokenMissing,
310+
}
311+
.into())
312+
}
313+
RegistryCredentialConfig::Token(config_token) => config_token.to_string(),
314+
RegistryCredentialConfig::Process(process) => {
315+
// todo: PASETO with process
316+
run_command(config, &process, sid, Action::Get)?.unwrap()
317+
}
318+
RegistryCredentialConfig::Key((private_key, private_key_subject)) => {
319+
let secret: AsymmetricSecretKey<pasetors::version3::V3> =
320+
private_key.as_str().try_into()?;
321+
let public: AsymmetricPublicKey<pasetors::version3::V3> = (&secret).try_into()?;
322+
let public_key_id: pasetors::paserk::Id = (&public).into();
323+
let mut kip = String::new();
324+
FormatAsPaserk::fmt(&public_key_id, &mut kip).unwrap();
325+
let iat = OffsetDateTime::now_utc();
326+
327+
let message = Message {
328+
iat: &iat.format(&Rfc3339)?,
329+
sub: private_key_subject.as_deref(),
330+
mutation: mutation.and_then(|m| m.mutation),
331+
name: mutation.and_then(|m| m.name),
332+
vers: mutation.and_then(|m| m.vers),
333+
cksum: mutation.and_then(|m| m.cksum),
334+
challenge: None, // todo: PASETO with challenges,
335+
v: None,
336+
};
337+
let footer = Footer {
338+
url: &sid.url().to_string(),
339+
kip: &kip,
340+
};
341+
342+
pasetors::version3::PublicToken::sign(
343+
&secret,
344+
&public,
345+
serde_json::to_string(&message)
352346
.expect("cannot serialize")
353347
.as_bytes(),
354-
),
355-
None,
356-
)?
357-
}
358-
};
359-
360-
if mutation.is_none() {
361-
cache.insert(url.clone(), token.clone());
348+
Some(
349+
serde_json::to_string(&footer)
350+
.expect("cannot serialize")
351+
.as_bytes(),
352+
),
353+
None,
354+
)?
355+
}
356+
})
362357
}
363-
Ok(Some(token))
364358
}
365359

366360
pub struct Mutation<'a> {

src/cargo/util/config/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use std::io::prelude::*;
6161
use std::io::{self, SeekFrom};
6262
use std::mem;
6363
use std::path::{Path, PathBuf};
64+
use std::rc::Rc;
6465
use std::str::FromStr;
6566
use std::sync::Once;
6667
use std::time::Instant;
@@ -179,7 +180,7 @@ pub struct Config {
179180
updated_sources: LazyCell<RefCell<HashSet<SourceId>>>,
180181
/// Cache of credentials from configuration or credential providers.
181182
/// Maps from url to credential value.
182-
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, String>>>,
183+
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, Rc<RegistryCredentialConfig>>>>,
183184
/// Lock, if held, of the global package cache along with the number of
184185
/// acquisitions so far.
185186
package_cache_lock: RefCell<Option<(Option<FileLock>, usize)>>,
@@ -438,7 +439,9 @@ impl Config {
438439
}
439440

440441
/// Cached credentials from credential providers or configuration.
441-
pub fn credential_cache(&self) -> RefMut<'_, HashMap<CanonicalUrl, String>> {
442+
pub fn credential_cache(
443+
&self,
444+
) -> RefMut<'_, HashMap<CanonicalUrl, Rc<RegistryCredentialConfig>>> {
442445
self.credential_cache
443446
.borrow_with(|| RefCell::new(HashMap::new()))
444447
.borrow_mut()

tests/testsuite/registry_auth.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use cargo_test_support::{project, Execs, Project};
66
fn cargo(p: &Project, s: &str) -> Execs {
77
let mut e = p.cargo(s);
88
e.masquerade_as_nightly_cargo()
9-
.arg("-Zhttp-registry")
9+
.arg("-Zsparse-registry")
1010
.arg("-Zregistry-auth")
1111
.arg("-Zasymmetric-tokens");
1212
e

0 commit comments

Comments
 (0)