git-svn: handle authentication without relying on cached tokens on disk
This is mostly gleaned off SVN::Mirror, with added support for --no-auth-cache and --config-dir. Even with this patch, git-svn does not yet support repositories where the user only has partial read permissions. Signed-off-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
73bcf53342
commit
30d055aa1e
156
git-svn.perl
156
git-svn.perl
@ -39,7 +39,7 @@ memoize('revisions_eq');
|
|||||||
memoize('cmt_metadata');
|
memoize('cmt_metadata');
|
||||||
memoize('get_commit_time');
|
memoize('get_commit_time');
|
||||||
|
|
||||||
my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib);
|
my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib, $AUTH_BATON, $AUTH_CALLBACKS);
|
||||||
|
|
||||||
sub nag_lib {
|
sub nag_lib {
|
||||||
print STDERR <<EOF;
|
print STDERR <<EOF;
|
||||||
@ -66,7 +66,8 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
|
|||||||
$_template, $_shared, $_no_default_regex, $_no_graft_copy,
|
$_template, $_shared, $_no_default_regex, $_no_graft_copy,
|
||||||
$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
|
$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
|
||||||
$_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
|
$_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
|
||||||
$_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive);
|
$_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive,
|
||||||
|
$_username, $_config_dir, $_no_auth_cache);
|
||||||
my (@_branch_from, %tree_map, %users, %rusers, %equiv);
|
my (@_branch_from, %tree_map, %users, %rusers, %equiv);
|
||||||
my ($_svn_co_url_revs, $_svn_pg_peg_revs);
|
my ($_svn_co_url_revs, $_svn_pg_peg_revs);
|
||||||
my @repo_path_split_cache;
|
my @repo_path_split_cache;
|
||||||
@ -79,6 +80,9 @@ my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
|
|||||||
'repack:i' => \$_repack,
|
'repack:i' => \$_repack,
|
||||||
'no-metadata' => \$_no_metadata,
|
'no-metadata' => \$_no_metadata,
|
||||||
'quiet|q' => \$_q,
|
'quiet|q' => \$_q,
|
||||||
|
'username=s' => \$_username,
|
||||||
|
'config-dir=s' => \$_config_dir,
|
||||||
|
'no-auth-cache' => \$_no_auth_cache,
|
||||||
'ignore-nodate' => \$_ignore_nodate,
|
'ignore-nodate' => \$_ignore_nodate,
|
||||||
'repack-flags|repack-args|repack-opts=s' => \$_repack_flags);
|
'repack-flags|repack-args|repack-opts=s' => \$_repack_flags);
|
||||||
|
|
||||||
@ -2683,18 +2687,154 @@ sub libsvn_load {
|
|||||||
my $kill_stupid_warnings = $SVN::Node::none.$SVN::Node::file.
|
my $kill_stupid_warnings = $SVN::Node::none.$SVN::Node::file.
|
||||||
$SVN::Node::dir.$SVN::Node::unknown.
|
$SVN::Node::dir.$SVN::Node::unknown.
|
||||||
$SVN::Node::none.$SVN::Node::file.
|
$SVN::Node::none.$SVN::Node::file.
|
||||||
$SVN::Node::dir.$SVN::Node::unknown;
|
$SVN::Node::dir.$SVN::Node::unknown.
|
||||||
|
$SVN::Auth::SSL::CNMISMATCH.
|
||||||
|
$SVN::Auth::SSL::NOTYETVALID.
|
||||||
|
$SVN::Auth::SSL::EXPIRED.
|
||||||
|
$SVN::Auth::SSL::UNKNOWNCA.
|
||||||
|
$SVN::Auth::SSL::OTHER;
|
||||||
1;
|
1;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _simple_prompt {
|
||||||
|
my ($cred, $realm, $default_username, $may_save, $pool) = @_;
|
||||||
|
$may_save = undef if $_no_auth_cache;
|
||||||
|
$default_username = $_username if defined $_username;
|
||||||
|
if (defined $default_username && length $default_username) {
|
||||||
|
if (defined $realm && length $realm) {
|
||||||
|
print "Authentication realm: $realm\n";
|
||||||
|
}
|
||||||
|
$cred->username($default_username);
|
||||||
|
} else {
|
||||||
|
_username_prompt($cred, $realm, $may_save, $pool);
|
||||||
|
}
|
||||||
|
$cred->password(_read_password("Password for '" .
|
||||||
|
$cred->username . "': ", $realm));
|
||||||
|
$cred->may_save($may_save);
|
||||||
|
$SVN::_Core::SVN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _ssl_server_trust_prompt {
|
||||||
|
my ($cred, $realm, $failures, $cert_info, $may_save, $pool) = @_;
|
||||||
|
$may_save = undef if $_no_auth_cache;
|
||||||
|
print "Error validating server certificate for '$realm':\n";
|
||||||
|
if ($failures & $SVN::Auth::SSL::UNKNOWNCA) {
|
||||||
|
print " - The certificate is not issued by a trusted ",
|
||||||
|
"authority. Use the\n",
|
||||||
|
" fingerprint to validate the certificate manually!\n";
|
||||||
|
}
|
||||||
|
if ($failures & $SVN::Auth::SSL::CNMISMATCH) {
|
||||||
|
print " - The certificate hostname does not match.\n";
|
||||||
|
}
|
||||||
|
if ($failures & $SVN::Auth::SSL::NOTYETVALID) {
|
||||||
|
print " - The certificate is not yet valid.\n";
|
||||||
|
}
|
||||||
|
if ($failures & $SVN::Auth::SSL::EXPIRED) {
|
||||||
|
print " - The certificate has expired.\n";
|
||||||
|
}
|
||||||
|
if ($failures & $SVN::Auth::SSL::OTHER) {
|
||||||
|
print " - The certificate has an unknown error.\n";
|
||||||
|
}
|
||||||
|
printf( "Certificate information:\n".
|
||||||
|
" - Hostname: %s\n".
|
||||||
|
" - Valid: from %s until %s\n".
|
||||||
|
" - Issuer: %s\n".
|
||||||
|
" - Fingerprint: %s\n",
|
||||||
|
map $cert_info->$_, qw(hostname valid_from valid_until
|
||||||
|
issuer_dname fingerprint) );
|
||||||
|
my $choice;
|
||||||
|
prompt:
|
||||||
|
print $may_save ?
|
||||||
|
"(R)eject, accept (t)emporarily or accept (p)ermanently? " :
|
||||||
|
"(R)eject or accept (t)emporarily? ";
|
||||||
|
$choice = lc(substr(<STDIN> || 'R', 0, 1));
|
||||||
|
if ($choice =~ /^t$/i) {
|
||||||
|
$cred->may_save(undef);
|
||||||
|
} elsif ($choice =~ /^r$/i) {
|
||||||
|
return -1;
|
||||||
|
} elsif ($may_save && $choice =~ /^p$/i) {
|
||||||
|
$cred->may_save($may_save);
|
||||||
|
} else {
|
||||||
|
goto prompt;
|
||||||
|
}
|
||||||
|
$cred->accepted_failures($failures);
|
||||||
|
$SVN::_Core::SVN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _ssl_client_cert_prompt {
|
||||||
|
my ($cred, $realm, $may_save, $pool) = @_;
|
||||||
|
$may_save = undef if $_no_auth_cache;
|
||||||
|
print "Client certificate filename: ";
|
||||||
|
chomp(my $filename = <STDIN>);
|
||||||
|
$cred->cert_file($filename);
|
||||||
|
$cred->may_save($may_save);
|
||||||
|
$SVN::_Core::SVN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _ssl_client_cert_pw_prompt {
|
||||||
|
my ($cred, $realm, $may_save, $pool) = @_;
|
||||||
|
$may_save = undef if $_no_auth_cache;
|
||||||
|
$cred->password(_read_password("Password: ", $realm));
|
||||||
|
$cred->may_save($may_save);
|
||||||
|
$SVN::_Core::SVN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _username_prompt {
|
||||||
|
my ($cred, $realm, $may_save, $pool) = @_;
|
||||||
|
$may_save = undef if $_no_auth_cache;
|
||||||
|
if (defined $realm && length $realm) {
|
||||||
|
print "Authentication realm: $realm\n";
|
||||||
|
}
|
||||||
|
my $username;
|
||||||
|
if (defined $_username) {
|
||||||
|
$username = $_username;
|
||||||
|
} else {
|
||||||
|
print "Username: ";
|
||||||
|
chomp($username = <STDIN>);
|
||||||
|
}
|
||||||
|
$cred->username($username);
|
||||||
|
$cred->may_save($may_save);
|
||||||
|
$SVN::_Core::SVN_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _read_password {
|
||||||
|
my ($prompt, $realm) = @_;
|
||||||
|
print $prompt;
|
||||||
|
require Term::ReadKey;
|
||||||
|
Term::ReadKey::ReadMode('noecho');
|
||||||
|
my $password = '';
|
||||||
|
while (defined(my $key = Term::ReadKey::ReadKey(0))) {
|
||||||
|
last if $key =~ /[\012\015]/; # \n\r
|
||||||
|
$password .= $key;
|
||||||
|
}
|
||||||
|
Term::ReadKey::ReadMode('restore');
|
||||||
|
print "\n";
|
||||||
|
$password;
|
||||||
|
}
|
||||||
|
|
||||||
sub libsvn_connect {
|
sub libsvn_connect {
|
||||||
my ($url) = @_;
|
my ($url) = @_;
|
||||||
my $auth = SVN::Core::auth_open([SVN::Client::get_simple_provider(),
|
if (!$AUTH_BATON || !$AUTH_CALLBACKS) {
|
||||||
SVN::Client::get_ssl_server_trust_file_provider(),
|
SVN::_Core::svn_config_ensure($_config_dir, undef);
|
||||||
SVN::Client::get_username_provider()]);
|
($AUTH_BATON, $AUTH_CALLBACKS) = SVN::Core::auth_open_helper([
|
||||||
my $s = eval { SVN::Ra->new(url => $url, auth => $auth) };
|
SVN::Client::get_simple_provider(),
|
||||||
return $s;
|
SVN::Client::get_ssl_server_trust_file_provider(),
|
||||||
|
SVN::Client::get_simple_prompt_provider(
|
||||||
|
\&_simple_prompt, 2),
|
||||||
|
SVN::Client::get_ssl_client_cert_prompt_provider(
|
||||||
|
\&_ssl_client_cert_prompt, 2),
|
||||||
|
SVN::Client::get_ssl_client_cert_pw_prompt_provider(
|
||||||
|
\&_ssl_client_cert_pw_prompt, 2),
|
||||||
|
SVN::Client::get_username_provider(),
|
||||||
|
SVN::Client::get_ssl_server_trust_prompt_provider(
|
||||||
|
\&_ssl_server_trust_prompt),
|
||||||
|
SVN::Client::get_username_prompt_provider(
|
||||||
|
\&_username_prompt, 2),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
SVN::Ra->new(url => $url, auth => $AUTH_BATON,
|
||||||
|
auth_provider_callbacks => $AUTH_CALLBACKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub libsvn_get_file {
|
sub libsvn_get_file {
|
||||||
|
Loading…
Reference in New Issue
Block a user