Skip to content

Commit 9e3ec21

Browse files
authored
Merge pull request #23690 from JuliaLang/cv/libgit2-allow-keywords
Add settings to CredentialPayload
2 parents 0465eb2 + e27c77d commit 9e3ec21

File tree

7 files changed

+87
-80
lines changed

7 files changed

+87
-80
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@ Deprecated or removed
445445

446446
* `contains(eq, itr, item)` is deprecated in favor of `any` with a predicate ([#23716]).
447447

448+
* Constructors for `LibGit2.UserPasswordCredentials` and `LibGit2.SSHCredentials` which take a
449+
`prompt_if_incorrect` argument are deprecated. Instead, prompting behavior is controlled using
450+
the `allow_prompt` keyword in the `LibGit2.CredentialPayload` constructor ([#23690]).
451+
448452
Command-line option changes
449453
---------------------------
450454

base/deprecated.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,10 @@ end
18061806

18071807
@deprecate contains(eq::Function, itr, x) any(y->eq(y,x), itr)
18081808

1809+
# PR #23690
1810+
# `SSHCredentials` and `UserPasswordCredentials` constructors using `prompt_if_incorrect`
1811+
# are deprecated in base/libgit2/types.jl.
1812+
18091813
# END 0.7 deprecations
18101814

18111815
# BEGIN 1.0 deprecations

base/libgit2/callbacks.jl

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,15 @@ function authenticate_ssh(libgit2credptr::Ptr{Ptr{Void}}, p::CredentialPayload,
5757
end
5858

5959
# first try ssh-agent if credentials support its usage
60-
if p.use_ssh_agent == 'Y' && username_ptr != Cstring(C_NULL)
60+
if p.use_ssh_agent && username_ptr != Cstring(C_NULL)
6161
err = ccall((:git_cred_ssh_key_from_agent, :libgit2), Cint,
6262
(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
63+
64+
p.use_ssh_agent = false # use ssh-agent only one time
65+
err == 0 && return Cint(0)
6966
end
7067

71-
if creds.prompt_if_incorrect
68+
if p.allow_prompt
7269
# if username is not provided or empty, then prompt for it
7370
username = username_ptr != Cstring(C_NULL) ? unsafe_string(username_ptr) : ""
7471
if isempty(username)
@@ -166,7 +163,7 @@ function authenticate_userpass(libgit2credptr::Ptr{Ptr{Void}}, p::CredentialPayl
166163
creds.pass = ""
167164
end
168165

169-
if creds.prompt_if_incorrect
166+
if p.allow_prompt
170167
username = creds.user
171168
userpass = creds.pass
172169
if isempty(username) || isempty(userpass)
@@ -266,7 +263,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Void}}, url_ptr::Cstring,
266263
# use ssh key or ssh-agent
267264
if isset(allowed_types, Cuint(Consts.CREDTYPE_SSH_KEY))
268265
if isnull(p.credential) || !isa(unsafe_get(p.credential), SSHCredentials)
269-
creds = SSHCredentials(p.username, "", true)
266+
creds = SSHCredentials(p.username)
270267
if !isnull(p.cache)
271268
credid = "ssh://$(p.host)"
272269
creds = get_creds!(unsafe_get(p.cache), credid, creds)
@@ -279,7 +276,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Void}}, url_ptr::Cstring,
279276

280277
if isset(allowed_types, Cuint(Consts.CREDTYPE_USERPASS_PLAINTEXT))
281278
if isnull(p.credential) || !isa(unsafe_get(p.credential), UserPasswordCredentials)
282-
creds = UserPasswordCredentials(p.username, "", true)
279+
creds = UserPasswordCredentials(p.username)
283280
if !isnull(p.cache)
284281
credid = "$(isempty(p.scheme) ? "ssh" : p.scheme)://$(p.host)"
285282
creds = get_creds!(unsafe_get(p.cache), credid, creds)

base/libgit2/types.jl

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,13 +1066,21 @@ abstract type AbstractCredentials end
10661066
mutable struct UserPasswordCredentials <: AbstractCredentials
10671067
user::String
10681068
pass::String
1069-
prompt_if_incorrect::Bool # Whether to allow interactive prompting if the credentials are incorrect
1070-
function UserPasswordCredentials(u::AbstractString,p::AbstractString,prompt_if_incorrect::Bool=false)
1071-
c = new(u,p,prompt_if_incorrect)
1069+
function UserPasswordCredentials(user::AbstractString="", pass::AbstractString="")
1070+
c = new(user, pass)
10721071
finalizer(c, securezero!)
10731072
return c
10741073
end
1075-
UserPasswordCredentials(prompt_if_incorrect::Bool=false) = UserPasswordCredentials("","",prompt_if_incorrect)
1074+
1075+
# Deprecated constructors
1076+
function UserPasswordCredentials(u::AbstractString,p::AbstractString,prompt_if_incorrect::Bool)
1077+
Base.depwarn(string(
1078+
"`UserPasswordCredentials` no longer supports the `prompt_if_incorrect` parameter. ",
1079+
"Use the `allow_prompt` keyword in supported by `LibGit2.CredentialPayload` ",
1080+
"instead."), :UserPasswordCredentials)
1081+
UserPasswordCredentials(u, p)
1082+
end
1083+
UserPasswordCredentials(prompt_if_incorrect::Bool) = UserPasswordCredentials("","",prompt_if_incorrect)
10761084
end
10771085

10781086
function securezero!(cred::UserPasswordCredentials)
@@ -1091,14 +1099,23 @@ mutable struct SSHCredentials <: AbstractCredentials
10911099
pass::String
10921100
prvkey::String
10931101
pubkey::String
1094-
prompt_if_incorrect::Bool # Whether to allow interactive prompting if the credentials are incorrect
1095-
function SSHCredentials(u::AbstractString,p::AbstractString,prvkey::AbstractString,pubkey::AbstractString,prompt_if_incorrect::Bool=false)
1096-
c = new(u,p,prvkey,pubkey,prompt_if_incorrect)
1102+
function SSHCredentials(user::AbstractString="", pass::AbstractString="",
1103+
prvkey::AbstractString="", pubkey::AbstractString="")
1104+
c = new(user, pass, prvkey, pubkey)
10971105
finalizer(c, securezero!)
10981106
return c
10991107
end
1100-
SSHCredentials(u::AbstractString,p::AbstractString,prompt_if_incorrect::Bool=false) = SSHCredentials(u,p,"","",prompt_if_incorrect)
1101-
SSHCredentials(prompt_if_incorrect::Bool=false) = SSHCredentials("","","","",prompt_if_incorrect)
1108+
1109+
# Deprecated constructors
1110+
function SSHCredentials(u::AbstractString,p::AbstractString,prvkey::AbstractString,pubkey::AbstractString,prompt_if_incorrect::Bool)
1111+
Base.depwarn(string(
1112+
"`SSHCredentials` no longer supports the `prompt_if_incorrect` parameter. ",
1113+
"Use the `allow_prompt` keyword in supported by `LibGit2.CredentialPayload` ",
1114+
"instead."), :SSHCredentials)
1115+
SSHCredentials(u, p, prvkey, pubkey)
1116+
end
1117+
SSHCredentials(u::AbstractString, p::AbstractString, prompt_if_incorrect::Bool) = SSHCredentials(u,p,"","",prompt_if_incorrect)
1118+
SSHCredentials(prompt_if_incorrect::Bool) = SSHCredentials("","","","",prompt_if_incorrect)
11021119
end
11031120

11041121
function securezero!(cred::SSHCredentials)
@@ -1130,39 +1147,41 @@ end
11301147
"""
11311148
LibGit2.CredentialPayload
11321149
1133-
Retains state between multiple calls to the credential callback. A single
1134-
`CredentialPayload` instance will be used when authentication fails for a URL but different
1135-
instances will be used when the URL has changed.
1150+
Retains the state between multiple calls to the credential callback for the same URL.
1151+
A `CredentialPayload` instance is expected to be `reset!` whenever it will be used with a
1152+
different URL.
11361153
"""
11371154
mutable struct CredentialPayload <: Payload
11381155
explicit::Nullable{AbstractCredentials}
11391156
cache::Nullable{CachedCredentials}
1157+
allow_ssh_agent::Bool # Allow the use of the SSH agent to get credentials
1158+
allow_prompt::Bool # Allow prompting the user for credentials
11401159

11411160
# Ephemeral state fields
11421161
credential::Nullable{AbstractCredentials}
11431162
first_pass::Bool
1144-
use_ssh_agent::Char
1163+
use_ssh_agent::Bool
11451164
scheme::String
11461165
username::String
11471166
host::String
11481167
path::String
11491168

1150-
function CredentialPayload(credential::Nullable{<:AbstractCredentials}, cache::Nullable{CachedCredentials})
1151-
payload = new(credential, cache)
1169+
function CredentialPayload(
1170+
credential::Nullable{<:AbstractCredentials}=Nullable{AbstractCredentials}(),
1171+
cache::Nullable{CachedCredentials}=Nullable{CachedCredentials}();
1172+
allow_ssh_agent::Bool=true,
1173+
allow_prompt::Bool=true)
1174+
payload = new(credential, cache, allow_ssh_agent, allow_prompt)
11521175
return reset!(payload)
11531176
end
11541177
end
11551178

1156-
function CredentialPayload(credential::AbstractCredentials)
1157-
CredentialPayload(Nullable(credential), Nullable{CachedCredentials}())
1158-
end
1159-
1160-
function CredentialPayload(cache::CachedCredentials)
1161-
CredentialPayload(Nullable{AbstractCredentials}(), Nullable(cache))
1179+
function CredentialPayload(credential::AbstractCredentials; kwargs...)
1180+
CredentialPayload(Nullable(credential), Nullable{CachedCredentials}(); kwargs...)
11621181
end
11631182

1164-
function CredentialPayload()
1165-
CredentialPayload(Nullable{AbstractCredentials}(), Nullable{CachedCredentials}())
1183+
function CredentialPayload(cache::CachedCredentials; kwargs...)
1184+
CredentialPayload(Nullable{AbstractCredentials}(), Nullable(cache); kwargs...)
11661185
end
11671186

11681187
"""
@@ -1174,7 +1193,7 @@ the credential callback.
11741193
function reset!(p::CredentialPayload)
11751194
p.credential = Nullable{AbstractCredentials}()
11761195
p.first_pass = true
1177-
p.use_ssh_agent = 'Y'
1196+
p.use_ssh_agent = p.allow_ssh_agent
11781197
p.scheme = ""
11791198
p.username = ""
11801199
p.host = ""

test/libgit2-helpers.jl

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,14 @@ function credential_loop(
6161
valid_credential::SSHCredentials,
6262
url::AbstractString,
6363
user::Nullable{<:AbstractString}=Nullable{String}(),
64-
payload::CredentialPayload=CredentialPayload();
65-
use_ssh_agent::Bool=false)
66-
67-
if !use_ssh_agent
68-
payload.use_ssh_agent = 'N'
69-
end
70-
64+
payload::CredentialPayload=CredentialPayload(allow_ssh_agent=false))
7165
credential_loop(valid_credential, url, user, 0x000046, payload)
7266
end
7367

7468
function credential_loop(
75-
valid_credential::UserPasswordCredentials,
69+
valid_credential::AbstractCredentials,
7670
url::AbstractString,
7771
user::AbstractString,
78-
payload::CredentialPayload=CredentialPayload())
72+
payload::CredentialPayload=CredentialPayload(allow_ssh_agent=false))
7973
credential_loop(valid_credential, url, Nullable(user), payload)
8074
end
81-
82-
function credential_loop(
83-
valid_credential::SSHCredentials,
84-
url::AbstractString,
85-
user::AbstractString,
86-
payload::CredentialPayload=CredentialPayload();
87-
use_ssh_agent::Bool=false)
88-
credential_loop(valid_credential, url, Nullable(user), payload, use_ssh_agent=use_ssh_agent)
89-
end

test/libgit2-online.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ mktempdir() do dir
99
@testset "Cloning repository" begin
1010
@testset "with 'https' protocol" begin
1111
repo_path = joinpath(dir, "Example1")
12-
repo = LibGit2.clone(repo_url, repo_path)
12+
payload = LibGit2.CredentialPayload(allow_prompt=false)
13+
repo = LibGit2.clone(repo_url, repo_path, payload=payload)
1314
try
1415
@test isdir(repo_path)
1516
@test isdir(joinpath(repo_path, ".git"))
@@ -23,7 +24,7 @@ mktempdir() do dir
2324
repo_path = joinpath(dir, "Example2")
2425
# credentials are required because github tries to authenticate on unknown repo
2526
cred = LibGit2.UserPasswordCredentials("JeffBezanson", "hunter2") # make sure Jeff is using a good password :)
26-
payload = LibGit2.CredentialPayload(cred)
27+
payload = LibGit2.CredentialPayload(cred, allow_prompt=false)
2728
LibGit2.clone(repo_url*randstring(10), repo_path, payload=payload)
2829
error("unexpected")
2930
catch ex
@@ -37,7 +38,7 @@ mktempdir() do dir
3738
repo_path = joinpath(dir, "Example3")
3839
# credentials are required because github tries to authenticate on unknown repo
3940
cred = LibGit2.UserPasswordCredentials("","") # empty credentials cause authentication error
40-
payload = LibGit2.CredentialPayload(cred)
41+
payload = LibGit2.CredentialPayload(cred, allow_prompt=false)
4142
LibGit2.clone(repo_url*randstring(10), repo_path, payload=payload)
4243
error("unexpected")
4344
catch ex

test/libgit2.jl

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,26 +1936,23 @@ mktempdir() do dir
19361936
function gen_ex(; username="git")
19371937
quote
19381938
include($LIBGIT2_HELPER_PATH)
1939-
credential_loop($valid_cred, $url, Nullable{String}($username), use_ssh_agent=true)
1939+
payload = CredentialPayload(allow_ssh_agent=true, allow_prompt=false)
1940+
credential_loop($valid_cred, $url, Nullable{String}($username), payload)
19401941
end
19411942
end
19421943

1943-
challenges = [
1944-
"Username for 'github.com':" => "\x04",
1945-
]
1946-
19471944
# An empty string username_ptr
19481945
ex = gen_ex(username="")
1949-
err, auth_attempts = challenge_prompt(ex, challenges)
1950-
@test err == abort_prompt # TODO: `eauth_error` when we can disable prompting
1946+
err, auth_attempts = challenge_prompt(ex, [])
1947+
@test err == eauth_error
19511948
@test auth_attempts == 2
19521949

19531950
# A null username_ptr passed into `git_cred_ssh_key_from_agent` can cause a
19541951
# segfault.
19551952
ex = gen_ex(username=nothing)
1956-
err, auth_attempts = challenge_prompt(ex, challenges)
1957-
@test err == abort_prompt # TODO: `eauth_error` when we can disable prompting
1958-
@test auth_attempts == 1
1953+
err, auth_attempts = challenge_prompt(ex, [])
1954+
@test err == eauth_error
1955+
@test auth_attempts == 2
19591956
end
19601957

19611958
@testset "SSH explicit credentials" begin
@@ -1969,22 +1966,22 @@ mktempdir() do dir
19691966
invalid_key = joinpath(KEY_DIR, "invalid")
19701967
invalid_cred = LibGit2.SSHCredentials(username, "", invalid_key, invalid_key * ".pub")
19711968

1972-
function gen_ex(cred)
1969+
function gen_ex(cred; allow_prompt=true)
19731970
quote
19741971
include($LIBGIT2_HELPER_PATH)
1975-
payload = CredentialPayload($cred)
1976-
credential_loop($valid_cred, $url, $username, payload, use_ssh_agent=false)
1972+
payload = CredentialPayload($cred, allow_ssh_agent=false, allow_prompt=$allow_prompt)
1973+
credential_loop($valid_cred, $url, $username, payload)
19771974
end
19781975
end
19791976

19801977
# Explicitly provided credential is correct
1981-
ex = gen_ex(valid_cred)
1978+
ex = gen_ex(valid_cred, allow_prompt=true)
19821979
err, auth_attempts = challenge_prompt(ex, [])
19831980
@test err == git_ok
19841981
@test auth_attempts == 1
19851982

19861983
# Explicitly provided credential is incorrect
1987-
ex = gen_ex(invalid_cred)
1984+
ex = gen_ex(invalid_cred, allow_prompt=false)
19881985
err, auth_attempts = challenge_prompt(ex, [])
19891986
@test err == eauth_error
19901987
@test auth_attempts == 2
@@ -1996,22 +1993,22 @@ mktempdir() do dir
19961993
valid_cred = LibGit2.UserPasswordCredentials("julia", randstring(16))
19971994
invalid_cred = LibGit2.UserPasswordCredentials("alice", randstring(15))
19981995

1999-
function gen_ex(cred)
1996+
function gen_ex(cred; allow_prompt=true)
20001997
quote
20011998
include($LIBGIT2_HELPER_PATH)
2002-
payload = CredentialPayload($cred)
1999+
payload = CredentialPayload($cred, allow_prompt=$allow_prompt)
20032000
credential_loop($valid_cred, $url, "", payload)
20042001
end
20052002
end
20062003

20072004
# Explicitly provided credential is correct
2008-
ex = gen_ex(valid_cred)
2005+
ex = gen_ex(valid_cred, allow_prompt=true)
20092006
err, auth_attempts = challenge_prompt(ex, [])
20102007
@test err == git_ok
20112008
@test auth_attempts == 1
20122009

20132010
# Explicitly provided credential is incorrect
2014-
ex = gen_ex(invalid_cred)
2011+
ex = gen_ex(invalid_cred, allow_prompt=false)
20152012
err, auth_attempts = challenge_prompt(ex, [])
20162013
@test err == eauth_error
20172014
@test auth_attempts == 2
@@ -2023,11 +2020,11 @@ mktempdir() do dir
20232020

20242021
valid_username = "julia"
20252022
valid_password = randstring(16)
2026-
valid_cred = LibGit2.UserPasswordCredentials(valid_username, valid_password, true)
2023+
valid_cred = LibGit2.UserPasswordCredentials(valid_username, valid_password)
20272024

20282025
invalid_username = "alice"
20292026
invalid_password = randstring(15)
2030-
invalid_cred = LibGit2.UserPasswordCredentials(invalid_username, invalid_password, true)
2027+
invalid_cred = LibGit2.UserPasswordCredentials(invalid_username, invalid_password)
20312028

20322029
function gen_ex(; cached_cred=nothing)
20332030
quote
@@ -2076,7 +2073,7 @@ mktempdir() do dir
20762073
expect_ssh_ex = quote
20772074
include($LIBGIT2_HELPER_PATH)
20782075
valid_cred = LibGit2.UserPasswordCredentials("foo", "bar")
2079-
payload = CredentialPayload(valid_cred)
2076+
payload = CredentialPayload(valid_cred, allow_ssh_agent=false)
20802077
credential_loop(valid_cred, "ssh://github.com/repo", Nullable(""),
20812078
Cuint(LibGit2.Consts.CREDTYPE_SSH_KEY), payload)
20822079
end
@@ -2089,7 +2086,7 @@ mktempdir() do dir
20892086
expect_https_ex = quote
20902087
include($LIBGIT2_HELPER_PATH)
20912088
valid_cred = LibGit2.SSHCredentials("foo", "", "", "")
2092-
payload = CredentialPayload(valid_cred)
2089+
payload = CredentialPayload(valid_cred, allow_ssh_agent=false)
20932090
credential_loop(valid_cred, "https://github.com/repo", Nullable(""),
20942091
Cuint(LibGit2.Consts.CREDTYPE_USERPASS_PLAINTEXT), payload)
20952092
end
@@ -2109,7 +2106,7 @@ mktempdir() do dir
21092106
ex = quote
21102107
include($LIBGIT2_HELPER_PATH)
21112108
valid_cred = LibGit2.UserPasswordCredentials("foo", "bar")
2112-
payload = CredentialPayload(valid_cred)
2109+
payload = CredentialPayload(valid_cred, allow_ssh_agent=false)
21132110
credential_loop(valid_cred, "foo://github.com/repo", Nullable(""),
21142111
$allowed_types, payload)
21152112
end

0 commit comments

Comments
 (0)