Skip to content

Commit 862c3c4

Browse files
committed
Cache CredentialConfig's not tokens.
1 parent 0d5156c commit 862c3c4

File tree

5 files changed

+109
-95
lines changed

5 files changed

+109
-95
lines changed

src/cargo/ops/registry.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::{drop_print, drop_println, version};
4141
/// Registry settings loaded from config files.
4242
///
4343
/// This is loaded based on the `--registry` flag and the config settings.
44-
#[derive(Debug, PartialEq)]
44+
#[derive(Debug, PartialEq, Clone)]
4545
pub enum RegistryCredentialConfig {
4646
None,
4747
/// The authentication token.
@@ -218,12 +218,14 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
218218
};
219219

220220
if !opts.dry_run {
221-
registry.set_token(Some(auth::auth_token(
222-
&opts.config,
223-
&reg_ids.original,
224-
None,
225-
Some(mutation),
226-
)?));
221+
registry.set_token(Some(
222+
auth::auth_token(&opts.config, &reg_ids.original)?.as_header(
223+
&opts.config,
224+
&reg_ids.original,
225+
None,
226+
Some(&mutation),
227+
)?,
228+
));
227229
}
228230

229231
opts.config
@@ -554,7 +556,12 @@ fn registry(
554556
.api
555557
.ok_or_else(|| format_err!("{} does not support API commands", source_ids.replacement))?;
556558
let token = if token_required.is_some() || cfg.auth_required {
557-
Some(auth::auth_token(config, &source_ids.original, None, token_required)?)
559+
Some(auth::auth_token(config, &source_ids.original)?.as_header(
560+
config,
561+
&source_ids.original,
562+
None,
563+
token_required.as_ref(),
564+
)?)
558565
} else {
559566
None
560567
};

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: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -591,9 +591,14 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
591591
}
592592
if self.auth_required {
593593
self.check_registry_auth_unstable()?;
594-
let authorization =
595-
auth::auth_token(self.config, &self.source_id, self.login_url.as_ref(), None)?;
596-
headers.append(&format!("Authorization: {}", authorization))?;
594+
let credential = auth::auth_token(self.config, &self.source_id)?;
595+
let authorization = credential.as_header(
596+
self.config,
597+
&self.source_id,
598+
self.login_url.as_ref(),
599+
None,
600+
)?;
601+
headers.append(&format!("authorization: {}", authorization))?;
597602
trace!("including authorization for {}", full_url);
598603
}
599604
handle.http_headers(headers)?;

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;
@@ -295,98 +296,91 @@ my-registry = {{ index = "{}" }}
295296
// Store a token in the cache for future calls.
296297
pub fn cache_token(config: &Config, sid: &SourceId, token: &str) {
297298
let url = sid.canonical_url();
298-
config
299-
.credential_cache()
300-
.insert(url.clone(), token.to_string());
299+
config.credential_cache().insert(
300+
url.clone(),
301+
Rc::new(RegistryCredentialConfig::Token(token.to_string())),
302+
);
301303
}
302304

303305
/// Returns the token to use for the given registry.
304-
/// If a `login_url` is provided and a token is not available, the
305-
/// login_url will be included in the returned error.
306-
pub fn auth_token(
307-
config: &Config,
308-
sid: &SourceId,
309-
login_url: Option<&Url>,
310-
mutation: Option<Mutation<'_>>,
311-
) -> CargoResult<String> {
312-
match auth_token_optional(config, sid, mutation.as_ref())? {
313-
Some(token) => Ok(token),
314-
None => Err(AuthorizationError {
315-
sid: sid.clone(),
316-
login_url: login_url.cloned(),
317-
reason: AuthorizationErrorReason::TokenMissing,
318-
}
319-
.into()),
320-
}
321-
}
322-
323-
/// Returns the token to use for the given registry.
324-
fn auth_token_optional(
325-
config: &Config,
326-
sid: &SourceId,
327-
mutation: Option<&'_ Mutation<'_>>,
328-
) -> CargoResult<Option<String>> {
306+
pub fn auth_token(config: &Config, sid: &SourceId) -> CargoResult<Rc<RegistryCredentialConfig>> {
329307
let mut cache = config.credential_cache();
330308
let url = sid.canonical_url();
331309

332-
if mutation.is_none() {
333-
if let Some(token) = cache.get(url) {
334-
return Ok(Some(token.clone()));
335-
}
310+
if let Some(token) = cache.get(url) {
311+
return Ok(Rc::clone(token));
336312
}
337313

338-
let credential = registry_credential_config(config, sid)?;
339-
let token = match credential {
340-
RegistryCredentialConfig::None => return Ok(None),
341-
RegistryCredentialConfig::Token(config_token) => config_token.to_string(),
342-
RegistryCredentialConfig::Process(process) => {
343-
// todo: PASETO with process
344-
run_command(config, &process, sid, Action::Get)?.unwrap()
345-
}
346-
RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) => {
347-
let secret: AsymmetricSecretKey<pasetors::version3::V3> =
348-
secret_key.as_str().try_into()?;
349-
let public: AsymmetricPublicKey<pasetors::version3::V3> = (&secret).try_into()?;
350-
let public_key_id: pasetors::paserk::Id = (&public).into();
351-
let mut kip = String::new();
352-
FormatAsPaserk::fmt(&public_key_id, &mut kip).unwrap();
353-
let iat = OffsetDateTime::now_utc();
354-
355-
let message = Message {
356-
iat: &iat.format(&Rfc3339)?,
357-
sub: secret_key_subject.as_deref(),
358-
mutation: mutation.and_then(|m| m.mutation),
359-
name: mutation.and_then(|m| m.name),
360-
vers: mutation.and_then(|m| m.vers),
361-
cksum: mutation.and_then(|m| m.cksum),
362-
challenge: None, // todo: PASETO with challenges
363-
v: None,
364-
};
365-
let footer = Footer {
366-
url: &sid.url().to_string(),
367-
kip: &kip,
368-
};
369-
370-
pasetors::version3::PublicToken::sign(
371-
&secret,
372-
&public,
373-
serde_json::to_string(&message)
374-
.expect("cannot serialize")
375-
.as_bytes(),
376-
Some(
377-
serde_json::to_string(&footer)
314+
let credential = Rc::new(registry_credential_config(config, sid)?);
315+
316+
cache.insert(url.clone(), Rc::clone(&credential));
317+
Ok(credential)
318+
}
319+
320+
impl RegistryCredentialConfig {
321+
/// If a `login_url` is provided and a token is not available, the
322+
/// login_url will be included in the returned error.
323+
pub fn as_header(
324+
self: &Rc<RegistryCredentialConfig>,
325+
config: &Config,
326+
sid: &SourceId,
327+
login_url: Option<&Url>,
328+
mutation: Option<&'_ Mutation<'_>>,
329+
) -> CargoResult<String> {
330+
Ok(match &**self {
331+
RegistryCredentialConfig::None => {
332+
return Err(AuthorizationError {
333+
sid: sid.clone(),
334+
login_url: login_url.cloned(),
335+
reason: AuthorizationErrorReason::TokenMissing,
336+
}
337+
.into())
338+
}
339+
RegistryCredentialConfig::Token(config_token) => config_token.to_string(),
340+
RegistryCredentialConfig::Process(process) => {
341+
// todo: PASETO with process
342+
run_command(config, &process, sid, Action::Get)?.unwrap()
343+
}
344+
RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) => {
345+
let secret: AsymmetricSecretKey<pasetors::version3::V3> =
346+
secret_key.as_str().try_into()?;
347+
let public: AsymmetricPublicKey<pasetors::version3::V3> = (&secret).try_into()?;
348+
let public_key_id: pasetors::paserk::Id = (&public).into();
349+
let mut kip = String::new();
350+
FormatAsPaserk::fmt(&public_key_id, &mut kip).unwrap();
351+
let iat = OffsetDateTime::now_utc();
352+
353+
let message = Message {
354+
iat: &iat.format(&Rfc3339)?,
355+
sub: secret_key_subject.as_deref(),
356+
mutation: mutation.and_then(|m| m.mutation),
357+
name: mutation.and_then(|m| m.name),
358+
vers: mutation.and_then(|m| m.vers),
359+
cksum: mutation.and_then(|m| m.cksum),
360+
challenge: None, // todo: PASETO with challenges
361+
v: None,
362+
};
363+
let footer = Footer {
364+
url: &sid.url().to_string(),
365+
kip: &kip,
366+
};
367+
368+
pasetors::version3::PublicToken::sign(
369+
&secret,
370+
&public,
371+
serde_json::to_string(&message)
378372
.expect("cannot serialize")
379373
.as_bytes(),
380-
),
381-
None,
382-
)?
383-
}
384-
};
385-
386-
if mutation.is_none() {
387-
cache.insert(url.clone(), token.clone());
374+
Some(
375+
serde_json::to_string(&footer)
376+
.expect("cannot serialize")
377+
.as_bytes(),
378+
),
379+
None,
380+
)?
381+
}
382+
})
388383
}
389-
Ok(Some(token))
390384
}
391385

392386
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;
@@ -193,7 +194,7 @@ pub struct Config {
193194
updated_sources: LazyCell<RefCell<HashSet<SourceId>>>,
194195
/// Cache of credentials from configuration or credential providers.
195196
/// Maps from url to credential value.
196-
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, String>>>,
197+
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, Rc<RegistryCredentialConfig>>>>,
197198
/// Lock, if held, of the global package cache along with the number of
198199
/// acquisitions so far.
199200
package_cache_lock: RefCell<Option<(Option<FileLock>, usize)>>,
@@ -468,7 +469,9 @@ impl Config {
468469
}
469470

470471
/// Cached credentials from credential providers or configuration.
471-
pub fn credential_cache(&self) -> RefMut<'_, HashMap<CanonicalUrl, String>> {
472+
pub fn credential_cache(
473+
&self,
474+
) -> RefMut<'_, HashMap<CanonicalUrl, Rc<RegistryCredentialConfig>>> {
472475
self.credential_cache
473476
.borrow_with(|| RefCell::new(HashMap::new()))
474477
.borrow_mut()

0 commit comments

Comments
 (0)