Skip to content

Commit 30d055a

Browse files
Eric WongJunio C Hamano
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 73bcf53 commit 30d055a

File tree

1 file changed

+148
-8
lines changed

1 file changed

+148
-8
lines changed

git-svn.perl

Lines changed: 148 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
memoize('cmt_metadata');
4040
memoize('get_commit_time');
4141

42-
my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib);
42+
my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib, $AUTH_BATON, $AUTH_CALLBACKS);
4343

4444
sub nag_lib {
4545
print STDERR <<EOF;
@@ -66,7 +66,8 @@ sub nag_lib {
6666
$_template, $_shared, $_no_default_regex, $_no_graft_copy,
6767
$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
6868
$_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
69-
$_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive);
69+
$_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive,
70+
$_username, $_config_dir, $_no_auth_cache);
7071
my (@_branch_from, %tree_map, %users, %rusers, %equiv);
7172
my ($_svn_co_url_revs, $_svn_pg_peg_revs);
7273
my @repo_path_split_cache;
@@ -79,6 +80,9 @@ sub nag_lib {
7980
'repack:i' => \$_repack,
8081
'no-metadata' => \$_no_metadata,
8182
'quiet|q' => \$_q,
83+
'username=s' => \$_username,
84+
'config-dir=s' => \$_config_dir,
85+
'no-auth-cache' => \$_no_auth_cache,
8286
'ignore-nodate' => \$_ignore_nodate,
8387
'repack-flags|repack-args|repack-opts=s' => \$_repack_flags);
8488

@@ -2683,18 +2687,154 @@ sub libsvn_load {
26832687
my $kill_stupid_warnings = $SVN::Node::none.$SVN::Node::file.
26842688
$SVN::Node::dir.$SVN::Node::unknown.
26852689
$SVN::Node::none.$SVN::Node::file.
2686-
$SVN::Node::dir.$SVN::Node::unknown;
2690+
$SVN::Node::dir.$SVN::Node::unknown.
2691+
$SVN::Auth::SSL::CNMISMATCH.
2692+
$SVN::Auth::SSL::NOTYETVALID.
2693+
$SVN::Auth::SSL::EXPIRED.
2694+
$SVN::Auth::SSL::UNKNOWNCA.
2695+
$SVN::Auth::SSL::OTHER;
26872696
1;
26882697
};
26892698
}
26902699

2700+
sub _simple_prompt {
2701+
my ($cred, $realm, $default_username, $may_save, $pool) = @_;
2702+
$may_save = undef if $_no_auth_cache;
2703+
$default_username = $_username if defined $_username;
2704+
if (defined $default_username && length $default_username) {
2705+
if (defined $realm && length $realm) {
2706+
print "Authentication realm: $realm\n";
2707+
}
2708+
$cred->username($default_username);
2709+
} else {
2710+
_username_prompt($cred, $realm, $may_save, $pool);
2711+
}
2712+
$cred->password(_read_password("Password for '" .
2713+
$cred->username . "': ", $realm));
2714+
$cred->may_save($may_save);
2715+
$SVN::_Core::SVN_NO_ERROR;
2716+
}
2717+
2718+
sub _ssl_server_trust_prompt {
2719+
my ($cred, $realm, $failures, $cert_info, $may_save, $pool) = @_;
2720+
$may_save = undef if $_no_auth_cache;
2721+
print "Error validating server certificate for '$realm':\n";
2722+
if ($failures & $SVN::Auth::SSL::UNKNOWNCA) {
2723+
print " - The certificate is not issued by a trusted ",
2724+
"authority. Use the\n",
2725+
" fingerprint to validate the certificate manually!\n";
2726+
}
2727+
if ($failures & $SVN::Auth::SSL::CNMISMATCH) {
2728+
print " - The certificate hostname does not match.\n";
2729+
}
2730+
if ($failures & $SVN::Auth::SSL::NOTYETVALID) {
2731+
print " - The certificate is not yet valid.\n";
2732+
}
2733+
if ($failures & $SVN::Auth::SSL::EXPIRED) {
2734+
print " - The certificate has expired.\n";
2735+
}
2736+
if ($failures & $SVN::Auth::SSL::OTHER) {
2737+
print " - The certificate has an unknown error.\n";
2738+
}
2739+
printf( "Certificate information:\n".
2740+
" - Hostname: %s\n".
2741+
" - Valid: from %s until %s\n".
2742+
" - Issuer: %s\n".
2743+
" - Fingerprint: %s\n",
2744+
map $cert_info->$_, qw(hostname valid_from valid_until
2745+
issuer_dname fingerprint) );
2746+
my $choice;
2747+
prompt:
2748+
print $may_save ?
2749+
"(R)eject, accept (t)emporarily or accept (p)ermanently? " :
2750+
"(R)eject or accept (t)emporarily? ";
2751+
$choice = lc(substr(<STDIN> || 'R', 0, 1));
2752+
if ($choice =~ /^t$/i) {
2753+
$cred->may_save(undef);
2754+
} elsif ($choice =~ /^r$/i) {
2755+
return -1;
2756+
} elsif ($may_save && $choice =~ /^p$/i) {
2757+
$cred->may_save($may_save);
2758+
} else {
2759+
goto prompt;
2760+
}
2761+
$cred->accepted_failures($failures);
2762+
$SVN::_Core::SVN_NO_ERROR;
2763+
}
2764+
2765+
sub _ssl_client_cert_prompt {
2766+
my ($cred, $realm, $may_save, $pool) = @_;
2767+
$may_save = undef if $_no_auth_cache;
2768+
print "Client certificate filename: ";
2769+
chomp(my $filename = <STDIN>);
2770+
$cred->cert_file($filename);
2771+
$cred->may_save($may_save);
2772+
$SVN::_Core::SVN_NO_ERROR;
2773+
}
2774+
2775+
sub _ssl_client_cert_pw_prompt {
2776+
my ($cred, $realm, $may_save, $pool) = @_;
2777+
$may_save = undef if $_no_auth_cache;
2778+
$cred->password(_read_password("Password: ", $realm));
2779+
$cred->may_save($may_save);
2780+
$SVN::_Core::SVN_NO_ERROR;
2781+
}
2782+
2783+
sub _username_prompt {
2784+
my ($cred, $realm, $may_save, $pool) = @_;
2785+
$may_save = undef if $_no_auth_cache;
2786+
if (defined $realm && length $realm) {
2787+
print "Authentication realm: $realm\n";
2788+
}
2789+
my $username;
2790+
if (defined $_username) {
2791+
$username = $_username;
2792+
} else {
2793+
print "Username: ";
2794+
chomp($username = <STDIN>);
2795+
}
2796+
$cred->username($username);
2797+
$cred->may_save($may_save);
2798+
$SVN::_Core::SVN_NO_ERROR;
2799+
}
2800+
2801+
sub _read_password {
2802+
my ($prompt, $realm) = @_;
2803+
print $prompt;
2804+
require Term::ReadKey;
2805+
Term::ReadKey::ReadMode('noecho');
2806+
my $password = '';
2807+
while (defined(my $key = Term::ReadKey::ReadKey(0))) {
2808+
last if $key =~ /[\012\015]/; # \n\r
2809+
$password .= $key;
2810+
}
2811+
Term::ReadKey::ReadMode('restore');
2812+
print "\n";
2813+
$password;
2814+
}
2815+
26912816
sub libsvn_connect {
26922817
my ($url) = @_;
2693-
my $auth = SVN::Core::auth_open([SVN::Client::get_simple_provider(),
2694-
SVN::Client::get_ssl_server_trust_file_provider(),
2695-
SVN::Client::get_username_provider()]);
2696-
my $s = eval { SVN::Ra->new(url => $url, auth => $auth) };
2697-
return $s;
2818+
if (!$AUTH_BATON || !$AUTH_CALLBACKS) {
2819+
SVN::_Core::svn_config_ensure($_config_dir, undef);
2820+
($AUTH_BATON, $AUTH_CALLBACKS) = SVN::Core::auth_open_helper([
2821+
SVN::Client::get_simple_provider(),
2822+
SVN::Client::get_ssl_server_trust_file_provider(),
2823+
SVN::Client::get_simple_prompt_provider(
2824+
\&_simple_prompt, 2),
2825+
SVN::Client::get_ssl_client_cert_prompt_provider(
2826+
\&_ssl_client_cert_prompt, 2),
2827+
SVN::Client::get_ssl_client_cert_pw_prompt_provider(
2828+
\&_ssl_client_cert_pw_prompt, 2),
2829+
SVN::Client::get_username_provider(),
2830+
SVN::Client::get_ssl_server_trust_prompt_provider(
2831+
\&_ssl_server_trust_prompt),
2832+
SVN::Client::get_username_prompt_provider(
2833+
\&_username_prompt, 2),
2834+
]);
2835+
}
2836+
SVN::Ra->new(url => $url, auth => $AUTH_BATON,
2837+
auth_provider_callbacks => $AUTH_CALLBACKS);
26982838
}
26992839

27002840
sub libsvn_get_file {

0 commit comments

Comments
 (0)