Skip to content

Commit 5145e87

Browse files
committed
fixes & tests for auth
1 parent 0590b89 commit 5145e87

File tree

3 files changed

+91
-23
lines changed

3 files changed

+91
-23
lines changed

src/authentication.jl

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ mutable struct Authentication
5050
tokenpath::Union{AbstractString, Nothing}=nothing,
5151
email::Union{AbstractString, Nothing}=nothing,
5252
expires::Union{Integer, Nothing}=nothing,
53-
project_uuid::Union{UUIDs.UUID, Nothing}=nothing,
53+
project_id::Union{UUIDs.UUID, Nothing}=nothing,
5454
)
5555
# The authentication() function should take care of sanitizing the inputs here,
5656
# so it is fine to just error() here.
@@ -61,7 +61,7 @@ mutable struct Authentication
6161
@warn "Invalid auth.toml token path passed to Authentication, ignoring." tokenpath
6262
tokenpath = nothing
6363
end
64-
new(server, username, token, project_uuid, api_version, tokenpath, email, expires)
64+
new(server, username, token, project_id, api_version, tokenpath, email, expires)
6565
end
6666
end
6767

@@ -232,10 +232,14 @@ This can be set by passing the optional `project` argument, which works as follo
232232
"""
233233
function authenticate end
234234

235-
function authenticate(server::AbstractString, token::Union{AbstractString, Secret})
235+
function authenticate(
236+
server::AbstractString, token::Union{AbstractString, Secret};
237+
project::Union{AbstractString, UUIDs.UUID, Nothing, Missing}=missing,
238+
)
236239
auth = _authentication(
237240
_juliahub_uri(server);
238241
token=isa(token, Secret) ? token : Secret(token),
242+
project_id=_juliahub_project(project),
239243
)
240244
global __AUTH__[] = auth
241245
return auth
@@ -256,9 +260,9 @@ function authenticate(
256260
),
257261
)
258262
end
259-
project_uuid = _normalize_project(project)
263+
project_id = _juliahub_project(project)
260264
server_uri = _juliahub_uri(server)
261-
auth = Mocking.@mock _authenticate(server_uri; force, maxcount, hook, project_uuid)
265+
auth = Mocking.@mock _authenticate(server_uri; force, maxcount, hook, project_id)
262266
global __AUTH__[] = auth
263267
return auth
264268
end
@@ -291,14 +295,14 @@ end
291295
function _authenticate(
292296
server_uri::URIs.URI;
293297
force::Bool, maxcount::Integer, hook::Union{Base.Callable, Nothing},
294-
project_uuid::Union{UUID, Nothing},
298+
project_id::Union{UUID, Nothing},
295299
)
296300
isnothing(hook) || PkgAuthentication.register_open_browser_hook(hook)
297301
try
298302
# _authenticate either returns a valid token, or throws
299303
auth_toml = _authenticate_retry(string(server_uri), 1; force, maxcount)
300304
# Note: _authentication may throw, which gets passed on to the user
301-
_authentication(server_uri; project_uuid, auth_toml...)
305+
_authentication(server_uri; project_id, auth_toml...)
302306
finally
303307
isnothing(hook) || PkgAuthentication.clear_open_browser_hook()
304308
end
@@ -371,7 +375,7 @@ function _authentication(
371375
email::Union{AbstractString, Nothing}=nothing,
372376
username::Union{AbstractString, Nothing}=nothing,
373377
tokenpath::Union{AbstractString, Nothing}=nothing,
374-
project_uuid::Union{UUID, Nothing}=nothing,
378+
project_id::Union{UUID, Nothing}=nothing,
375379
)
376380
# If something goes badly wrong in _get_api_information, it may throw. We won't really
377381
# be able to proceed, since we do not know what JuliaHub APIs to use, so we need to
@@ -409,12 +413,12 @@ function _authentication(
409413
end
410414
return Authentication(
411415
server, api.api_version, username, token;
412-
email, expires, tokenpath, project_uuid,
416+
email, expires, tokenpath, project_id,
413417
)
414418
end
415419
_authentication(server::AbstractString; kwargs...) = _authentication(URIs.URI(server); kwargs...)
416420

417-
function _normalize_project(
421+
function _juliahub_project(
418422
project::Union{AbstractString, UUIDs.UUID, Nothing, Missing}
419423
)::Union{UUID, Nothing}
420424
if ismissing(project)
@@ -426,7 +430,7 @@ function _normalize_project(
426430
return project
427431
elseif isa(project, AbstractString)
428432
project_uuid = tryparse(UUIDs.UUID, project)
429-
if isnothing(project)
433+
if isnothing(project_uuid)
430434
throw(
431435
ArgumentError(
432436
"Invalid project_id passed to Authentication() - not a UUID: $(project)"
@@ -476,7 +480,8 @@ The `force`, `maxcount` and `hook` are relevant for interactive authentication,
476480
same way as in the [`authenticate`](@ref) function.
477481
478482
This is mostly meant to be used to re-acquire authentication tokens in long-running sessions, where
479-
the initial authentication token may have expired.
483+
the initial authentication token may have expired. If the original `auth` object was authenticated
484+
in the context of a project (i.e. `.project_id` is set), the project association will be retained.
480485
481486
As [`Authentication`](@ref) objects are mutable, the token will be updated in all contexts
482487
where the reference to the [`Authentication`](@ref) has been passed to.
@@ -534,7 +539,7 @@ function reauthenticate!(
534539
end
535540
end
536541
@debug "reauthenticate! -- calling PkgAuthentication" auth.server
537-
new_auth = _authenticate(auth.server; force, maxcount, hook)
542+
new_auth = _authenticate(auth.server; force, maxcount, hook, project_id=auth.project_id)
538543
if new_auth.username != auth.username
539544
throw(
540545
AuthenticationError(

test/authentication.jl

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,70 @@
1+
@testset "_juliahub_project" begin
2+
uuid1 = "80c74bbd-fd5a-4f99-a647-0eec08183ed4"
3+
uuid2 = "24d0f8a7-4c3f-4168-aef4-e49248f3cb40"
4+
withenv("JULIAHUB_PROJECT_UUID" => nothing) do
5+
@test JuliaHub._juliahub_project(uuid1) == UUIDs.UUID(uuid1)
6+
@test_throws ArgumentError JuliaHub._juliahub_project("invalid")
7+
@test JuliaHub._juliahub_project(nothing) === nothing
8+
@test JuliaHub._juliahub_project(missing) === nothing
9+
end
10+
withenv("JULIAHUB_PROJECT_UUID" => uuid1) do
11+
@test JuliaHub._juliahub_project(uuid2) == UUIDs.UUID(uuid2)
12+
@test_throws ArgumentError JuliaHub._juliahub_project("invalid")
13+
@test JuliaHub._juliahub_project(nothing) === nothing
14+
@test JuliaHub._juliahub_project(missing) === UUIDs.UUID(uuid1)
15+
end
16+
end
17+
118
@testset "JuliaHub.authenticate()" begin
219
empty!(MOCK_JULIAHUB_STATE)
320
Mocking.apply(mocking_patch) do
4-
withenv("JULIA_PKG_SERVER" => nothing) do
21+
withenv("JULIA_PKG_SERVER" => nothing, "JULIAHUB_PROJECT_UUID" => nothing) do
522
@test_throws JuliaHub.AuthenticationError JuliaHub.authenticate()
623
@test JuliaHub.authenticate("https://juliahub.example.org") isa JuliaHub.Authentication
724
@test JuliaHub.authenticate("juliahub.example.org") isa JuliaHub.Authentication
825
end
9-
withenv("JULIA_PKG_SERVER" => "juliahub.example.org") do
26+
withenv("JULIA_PKG_SERVER" => "juliahub.example.org", "JULIAHUB_PROJECT_UUID" => nothing) do
1027
@test JuliaHub.authenticate() isa JuliaHub.Authentication
1128
end
12-
withenv("JULIA_PKG_SERVER" => "https://juliahub.example.org") do
29+
withenv(
30+
"JULIA_PKG_SERVER" => "https://juliahub.example.org", "JULIAHUB_PROJECT_UUID" => nothing
31+
) do
1332
@test JuliaHub.authenticate() isa JuliaHub.Authentication
1433
end
15-
# Conflicting declarations, argument takes precendence
16-
withenv("JULIA_PKG_SERVER" => "https://juliahub-one.example.org") do
34+
# Conflicting declarations, explicit argument takes precedence
35+
withenv(
36+
"JULIA_PKG_SERVER" => "https://juliahub-one.example.org",
37+
"JULIAHUB_PROJECT_UUID" => nothing,
38+
) do
1739
auth = JuliaHub.authenticate("https://juliahub-two.example.org")
1840
@test auth isa JuliaHub.Authentication
1941
@test auth.server == URIs.URI("https://juliahub-two.example.org")
42+
@test auth.project_id === nothing
2043
# check_authentication
2144
MOCK_JULIAHUB_STATE[:invalid_authentication] = false
2245
@test JuliaHub.check_authentication(; auth) === true
2346
MOCK_JULIAHUB_STATE[:invalid_authentication] = true
2447
@test JuliaHub.check_authentication(; auth) === false
2548
delete!(MOCK_JULIAHUB_STATE, :invalid_authentication)
2649
end
50+
51+
# Projects integration
52+
uuid1 = "80c74bbd-fd5a-4f99-a647-0eec08183ed4"
53+
uuid2 = "24d0f8a7-4c3f-4168-aef4-e49248f3cb40"
54+
withenv(
55+
"JULIA_PKG_SERVER" => nothing,
56+
"JULIAHUB_PROJECT_UUID" => uuid1,
57+
) do
58+
auth = JuliaHub.authenticate("https://juliahub.example.org")
59+
@test auth.server == URIs.URI("https://juliahub.example.org")
60+
@test auth.project_id === UUIDs.UUID(uuid1)
61+
auth = JuliaHub.authenticate("https://juliahub.example.org"; project=uuid2)
62+
@test auth.server == URIs.URI("https://juliahub.example.org")
63+
@test auth.project_id === UUIDs.UUID(uuid2)
64+
auth = JuliaHub.authenticate("https://juliahub.example.org"; project=nothing)
65+
@test auth.server == URIs.URI("https://juliahub.example.org")
66+
@test auth.project_id === nothing
67+
end
2768
end
2869
end
2970

@@ -141,6 +182,25 @@ end
141182
@test a._email === nothing
142183
@test a._expires === nothing
143184
end
185+
# Projects integration
186+
# The JuliaHub.authenticate(server, token) method also takes the `project`
187+
# keyword, and also falls back to the JULIAHUB_PROJECT_UUID.
188+
uuid1 = "80c74bbd-fd5a-4f99-a647-0eec08183ed4"
189+
uuid2 = "24d0f8a7-4c3f-4168-aef4-e49248f3cb40"
190+
withenv(
191+
"JULIA_PKG_SERVER" => nothing,
192+
"JULIAHUB_PROJECT_UUID" => uuid1,
193+
) do
194+
auth = JuliaHub.authenticate(server, token)
195+
@test auth.server == URIs.URI("https://juliahub.example.org")
196+
@test auth.project_id === UUIDs.UUID(uuid1)
197+
auth = JuliaHub.authenticate(server, token; project=uuid2)
198+
@test auth.server == URIs.URI("https://juliahub.example.org")
199+
@test auth.project_id === UUIDs.UUID(uuid2)
200+
auth = JuliaHub.authenticate(server, token; project=nothing)
201+
@test auth.server == URIs.URI("https://juliahub.example.org")
202+
@test auth.project_id === nothing
203+
end
144204
# On old instances, we handle if /api/v1 404s
145205
MOCK_JULIAHUB_STATE[:auth_v1_status] = 404
146206
let a = JuliaHub.authenticate(server, token)

test/mocking.jl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ end
2323

2424
# Set up a mock authentication so that the __auth__() fallbacks would work and use this.
2525
const MOCK_USERNAME = "username"
26-
mockauth(server_uri) = JuliaHub.Authentication(
27-
server_uri, JuliaHub._MISSING_API_VERSION, MOCK_USERNAME, JuliaHub.Secret("")
28-
)
29-
JuliaHub.__AUTH__[] = mockauth(URIs.URI("https://juliahub.com"))
26+
function mockauth(server_uri; project_id, kwargs...)
27+
JuliaHub.Authentication(
28+
server_uri, JuliaHub._MISSING_API_VERSION, MOCK_USERNAME, JuliaHub.Secret("");
29+
project_id,
30+
)
31+
end
32+
JuliaHub.__AUTH__[] = mockauth(URIs.URI("https://juliahub.com"); project_id=nothing)
3033

3134
# The following Mocking.jl patches _rest_request, so the the rest calls would have fixed
3235
# reponses.
@@ -69,7 +72,7 @@ mocking_patch = [
6972
),
7073
Mocking.@patch(
7174
function JuliaHub._authenticate(server_uri; kwargs...)
72-
return mockauth(server_uri)
75+
return mockauth(server_uri; kwargs...)
7376
end
7477
),
7578
Mocking.@patch(

0 commit comments

Comments
 (0)