Skip to content

Commit 49776dd

Browse files
authored
Merge pull request #23641 from JuliaLang/cv/libgit2-ssh-agent
Move SSH agent state out of SSHCredentials
2 parents b3ec03f + be167aa commit 49776dd

File tree

4 files changed

+50
-31
lines changed

4 files changed

+50
-31
lines changed

base/libgit2/callbacks.jl

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,16 @@ function authenticate_ssh(libgit2credptr::Ptr{Ptr{Void}}, p::CredentialPayload,
5656
creds.pass = ""
5757
end
5858

59-
# Note: The same SSHCredentials can be used to authenticate separate requests using the
60-
# same credential cache. e.g. using Pkg.update when there are two private packages.
61-
errcls, errmsg = Error.last_error()
62-
if errcls != Error.None
63-
# Check if we used ssh-agent
64-
if creds.usesshagent == "U"
65-
creds.usesshagent = "E" # reported ssh-agent error, disables ssh agent use for the future
66-
end
67-
end
68-
6959
# first try ssh-agent if credentials support its usage
70-
if creds.usesshagent == "Y" || creds.usesshagent == "U"
60+
if p.use_ssh_agent == 'Y' && username_ptr != Cstring(C_NULL)
7161
err = ccall((:git_cred_ssh_key_from_agent, :libgit2), Cint,
72-
(Ptr{Ptr{Void}}, Cstring), libgit2credptr, username_ptr)
73-
creds.usesshagent = "U" # used ssh-agent only one time
74-
err == 0 && return Cint(0)
62+
(Ptr{Ptr{Void}}, Cstring), libgit2credptr, username_ptr)
63+
if err == 0
64+
p.use_ssh_agent = 'U' # used ssh-agent only one time
65+
return Cint(0)
66+
else
67+
p.use_ssh_agent = 'E'
68+
end
7569
end
7670

7771
if creds.prompt_if_incorrect
@@ -221,7 +215,7 @@ For `LibGit2.Consts.CREDTYPE_SSH_KEY` type, if the payload contains fields:
221215
Typing `^D` (control key together with the `d` key) will abort the credential prompt.
222216
223217
Credentials are checked in the following order (if supported):
224-
- ssh key pair (`ssh-agent` if specified in payload's `usesshagent` field)
218+
- ssh key pair (`ssh-agent` if specified in payload's `use_ssh_agent` field)
225219
- plain text
226220
227221
**Note**: Due to the specifics of the `libgit2` authentication procedure, when

base/libgit2/types.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,10 +1095,9 @@ mutable struct SSHCredentials <: AbstractCredentials
10951095
pass::String
10961096
prvkey::String
10971097
pubkey::String
1098-
usesshagent::String # used for ssh-agent authentication
10991098
prompt_if_incorrect::Bool # Whether to allow interactive prompting if the credentials are incorrect
11001099
function SSHCredentials(u::AbstractString,p::AbstractString,prvkey::AbstractString,pubkey::AbstractString,prompt_if_incorrect::Bool=false)
1101-
c = new(u,p,prvkey,pubkey,"Y",prompt_if_incorrect)
1100+
c = new(u,p,prvkey,pubkey,prompt_if_incorrect)
11021101
finalizer(c, securezero!)
11031102
return c
11041103
end
@@ -1143,13 +1142,14 @@ mutable struct CredentialPayload <: Payload
11431142
credential::Nullable{AbstractCredentials}
11441143
cache::Nullable{CachedCredentials}
11451144
first_pass::Bool
1145+
use_ssh_agent::Char
11461146
scheme::String
11471147
username::String
11481148
host::String
11491149
path::String
11501150

11511151
function CredentialPayload(credential::Nullable{<:AbstractCredentials}, cache::Nullable{CachedCredentials})
1152-
new(credential, cache, true, "", "", "", "")
1152+
new(credential, cache, true, 'Y', "", "", "", "")
11531153
end
11541154
end
11551155

test/libgit2-helpers.jl

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,7 @@ function credential_loop(
6565
use_ssh_agent::Bool=false)
6666

6767
if !use_ssh_agent
68-
if isnull(payload.cache)
69-
payload.cache = Nullable(CachedCredentials())
70-
end
71-
cache = get(payload.cache)
72-
73-
m = match(LibGit2.URL_REGEX, url)
74-
default_cred = SSHCredentials(true)
75-
default_cred.usesshagent = "N"
76-
LibGit2.get_creds!(cache, "ssh://$(m[:host])", default_cred)
68+
payload.use_ssh_agent = 'N'
7769
end
7870

7971
credential_loop(valid_credential, url, user, 0x000046, payload)

test/libgit2.jl

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,10 +1644,11 @@ mktempdir() do dir
16441644
end
16451645

16461646
# SSH requires username
1647+
url_no_username = "github.com:test/package.jl"
16471648
ssh_u_ex = quote
16481649
include($LIBGIT2_HELPER_PATH)
16491650
valid_cred = SSHCredentials($username, "", $valid_key, $(valid_key * ".pub"))
1650-
credential_loop(valid_cred, $url)
1651+
credential_loop(valid_cred, $url_no_username)
16511652
end
16521653

16531654
# Note: We cannot use the default ~/.ssh/id_rsa for tests since we cannot be
@@ -1748,7 +1749,7 @@ mktempdir() do dir
17481749
ssh_user_empty_ex = quote
17491750
include($LIBGIT2_HELPER_PATH)
17501751
valid_cred = LibGit2.SSHCredentials($username, "", $valid_key, $(valid_key * ".pub"))
1751-
credential_loop(valid_cred, $url, "")
1752+
credential_loop(valid_cred, $url_no_username, "")
17521753
end
17531754

17541755
challenges = [
@@ -1901,6 +1902,39 @@ mktempdir() do dir
19011902
@test auth_attempts == 2
19021903
end
19031904

1905+
@testset "SSH agent username" begin
1906+
url = "github.com:test/package.jl"
1907+
1908+
valid_key = joinpath(KEY_DIR, "valid")
1909+
username = "git"
1910+
1911+
ssh_empty_ex = quote
1912+
include($LIBGIT2_HELPER_PATH)
1913+
valid_cred = LibGit2.SSHCredentials($username, "", $valid_key, $(valid_key * ".pub"))
1914+
credential_loop(valid_cred, $url, Nullable(""), use_ssh_agent=true)
1915+
end
1916+
1917+
ssh_null_ex = quote
1918+
include($LIBGIT2_HELPER_PATH)
1919+
valid_cred = LibGit2.SSHCredentials($username, "", $valid_key, $(valid_key * ".pub"))
1920+
credential_loop(valid_cred, $url, Nullable(), use_ssh_agent=true)
1921+
end
1922+
1923+
challenges = [
1924+
"Username for 'github.com':" => "\x04",
1925+
]
1926+
1927+
err, auth_attempts = challenge_prompt(ssh_empty_ex, challenges)
1928+
@test err == abort_prompt # TODO: `eauth_error` when we can disable prompting
1929+
@test auth_attempts == 2
1930+
1931+
# A null username_ptr passed into `git_cred_ssh_key_from_agent` can cause a
1932+
# segfault.
1933+
err, auth_attempts = challenge_prompt(ssh_null_ex, challenges)
1934+
@test err == abort_prompt # TODO: `eauth_error` when we can disable prompting
1935+
@test auth_attempts == 1
1936+
end
1937+
19041938
@testset "SSH explicit credentials" begin
19051939
url = "git@github.com:test/package.jl"
19061940

@@ -1920,9 +1954,8 @@ mktempdir() do dir
19201954
include($LIBGIT2_HELPER_PATH)
19211955
valid_cred = LibGit2.SSHCredentials($username, $passphrase, $valid_p_key, $(valid_p_key * ".pub"))
19221956
invalid_cred = LibGit2.SSHCredentials($username, "", $invalid_key, $(invalid_key * ".pub"))
1923-
invalid_cred.usesshagent = "N" # Disable SSH agent use
19241957
payload = CredentialPayload(Nullable(invalid_cred))
1925-
credential_loop(valid_cred, $url, $username, payload)
1958+
credential_loop(valid_cred, $url, $username, payload, use_ssh_agent=false)
19261959
end
19271960

19281961
# Explicitly provided credential is correct

0 commit comments

Comments
 (0)