Skip to content

Commit f9cfd4c

Browse files
committed
wip
1 parent 97a154b commit f9cfd4c

File tree

1 file changed

+34
-19
lines changed

1 file changed

+34
-19
lines changed

src/PkgAuthentication.jl

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -178,17 +178,25 @@ function step(state::NoAuthentication)::Union{RequestLogin, Failure}
178178
output = IOBuffer()
179179
# Try device flow first
180180
response = Downloads.request(
181-
string(state.server, "/dex/device/code"),
181+
joinpath(state.server, "dex/device/code"),
182182
method = "POST",
183-
input = IOBuffer("client_id=device&scopes=openid email profile offline_access"),
183+
input = IOBuffer("client_id=device&scope=openid email profile offline_access"),
184184
output = output,
185185
throw = false,
186-
headers = ["Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded"],
186+
headers = Dict("Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded"),
187187
)
188188
if response isa Downloads.Response && response.status == 200
189-
body = JSON.parse(String(take!(output)))
190-
body["client_id"] = "device"
191-
return RequestLogin(state.server, "", body)
189+
body = nothing
190+
try
191+
body = JSON.parse(String(take!(output)))
192+
catch ex
193+
@debug "Request for device code returned: ", body
194+
end
195+
196+
if body !== nothing
197+
body["client_id"] = "device"
198+
return RequestLogin(state.server, "", body)
199+
end
192200
end
193201

194202
challenge = Random.randstring(32)
@@ -200,7 +208,7 @@ function step(state::NoAuthentication)::Union{RequestLogin, Failure}
200208
throw = false,
201209
)
202210
if response isa Downloads.Response && response.status == 200
203-
return RequestLogin(state.server, challenge, String(take!(output)), false)
211+
return RequestLogin(state.server, challenge, String(take!(output)))
204212
else
205213
return HttpError(response)
206214
end
@@ -246,7 +254,7 @@ function step(state::NeedRefresh)::Union{HasNewToken, NoAuthentication}
246254
is_device = get(state.token, "client_id", nothing) == "device"
247255
response = if is_device
248256
Downloads.request(
249-
"$(state.server)/dex/token",
257+
joinpath(state.server, "dex/token"),
250258
method = "POST",
251259
headers = ["Content-Type" => "application/x-www-form-urlencoded"],
252260
input = IOBuffer("grant_type=refresh_token&client_id=device&refresh_token=$refresh_token"),
@@ -273,6 +281,7 @@ function step(state::NeedRefresh)::Union{HasNewToken, NoAuthentication}
273281
end
274282
if is_device
275283
body["client_id"] = "device"
284+
body["expires"] = body["expires_in"] + Int(floor(time()))
276285
end
277286
return HasNewToken(state.server, body)
278287
catch err
@@ -344,16 +353,17 @@ end
344353
Base.show(io::IO, s::RequestLogin) = print(io, "RequestLogin($(s.server), <REDACTED>, $(s.response))")
345354

346355
function step(state::RequestLogin)::Union{ClaimToken, Failure}
347-
is_device = response isa Dict{String, Any} && get(response, "client_id", nothing) == "device"
356+
is_device = state.response isa Dict{String, Any} && get(state.response, "client_id", nothing) == "device"
348357
url = if is_device
349358
string(state.response["verification_uri_complete"])
350359
else
351360
string(state.server, "/response?", state.response)
352361
end
353362

354363
success = open_browser(url)
355-
if success && state.is_device
356-
return ClaimToken(state.server, state.challenge, state.response, expiry=state.response["expires_in"])
364+
if success && is_device
365+
# In case of device tokens, timeout for challenge is received in the initial request.
366+
return ClaimToken(state.server, state.challenge, state.response, Inf, time(), state.response["expires_in"], 2, 0, 10)
357367
elseif success
358368
return ClaimToken(state.server, state.challenge, state.response)
359369
else # this can only happen for the browser hook
@@ -394,15 +404,16 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure}
394404
sleep(state.poll_interval)
395405

396406
output = IOBuffer()
397-
is_device = response isa Dict{String, Any} && get(response, "client_id", nothing) == "device")
407+
is_device = state.response isa Dict{String, Any} && get(state.response, "client_id", nothing) == "device"
398408
if is_device
409+
output = IOBuffer()
399410
response = Downloads.request(
400-
string(state.server, "/dex/token"),
411+
joinpath(state.server, "dex/token"),
401412
method = "POST",
402-
input = IOBuffer("client_id=device&scope=openid profile offline_access&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=$(state.response["device_code"])"),
413+
input = IOBuffer(reqstr),
403414
output = output,
404415
throw = false,
405-
headers = ["Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded"],
416+
headers = Dict("Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded"),
406417
)
407418
else
408419
data = JSON.json(Dict(
@@ -418,7 +429,7 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure}
418429
)
419430
end
420431

421-
if response isa Downloads.Response && response.status == 200 && state.challenge !== nothing
432+
if response isa Downloads.Response && response.status == 200 && !is_device
422433
body = try
423434
JSON.parse(String(take!(output)))
424435
catch err
@@ -433,8 +444,11 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure}
433444
return ClaimToken(state.server, state.challenge, state.response, state.expiry, state.start_time, state.timeout, state.poll_interval, state.failures + 1, state.max_failures)
434445
end
435446
elseif response isa Downloads.Response && response.status == 200
436-
return HasNewToken(state.server, JSON.parse(String(take!(output)))["access_token"])
437-
elseif response isa Downloads.Response && response.status == 401 && is_device
447+
body = JSON.parse(String(take!(output)))
448+
body["client_id"] = "device"
449+
body["expires"] = body["expires_in"] + Int(floor(time()))
450+
return HasNewToken(state.server, body)
451+
elseif response isa Downloads.Response && response.status in [401, 400] && is_device
438452
return ClaimToken(state.server, state.challenge, state.response, state.expiry, state.start_time, state.timeout, state.poll_interval, state.failures + 1, state.max_failures)
439453
else
440454
return HttpError(response)
@@ -487,7 +501,8 @@ is_new_auth_mechanism() =
487501
is_token_valid(toml) =
488502
get(toml, "id_token", nothing) isa AbstractString &&
489503
get(toml, "refresh_token", nothing) isa AbstractString &&
490-
get(toml, "refresh_url", nothing) isa AbstractString &&
504+
(get(toml, "refresh_url", nothing) isa AbstractString ||
505+
get(toml, "client_id", nothing) == "device") &&
491506
(get(toml, "expires_at", nothing) isa Union{Integer, AbstractFloat} ||
492507
get(toml, "expires", nothing) isa Union{Integer, AbstractFloat})
493508

0 commit comments

Comments
 (0)