Auth API update (#41197)
Updates the auth API result to make it more easily used with the pull inputs.
JohnMcPMS committed
Jul 29, 2026 at 14:30 UTC
2f68e20e9eafaa0c94cf14d3287fc6f6096f2226
10 files changed
+166
-28
src/windows/WslcSDK/winrt/AuthenticateResult.cpp
new
+22
@@ -0,0 +1,22 @@
1
+// Copyright (C) Microsoft Corporation. All rights reserved.
2
+
3
+#include "precomp.h"
4
+#include "AuthenticateResult.h"
5
+#include "Microsoft.WSL.Containers.AuthenticateResult.g.cpp"
6
+
7
+namespace winrt::Microsoft::WSL::Containers::implementation {
8
+AuthenticateResult::AuthenticateResult(hstring identityToken, winrt::Microsoft::WSL::Containers::IdentityTokenType tokenType) :
9
+ m_identityToken(std::move(identityToken)), m_tokenType(tokenType)
10
+{
11
+}
12
+
13
+hstring AuthenticateResult::IdentityToken()
14
+{
15
+ return m_identityToken;
16
+}
17
+
18
+winrt::Microsoft::WSL::Containers::IdentityTokenType AuthenticateResult::TokenType()
19
+{
20
+ return m_tokenType;
21
+}
22
+} // namespace winrt::Microsoft::WSL::Containers::implementation
src/windows/WslcSDK/winrt/AuthenticateResult.h
new
+20
@@ -0,0 +1,20 @@
1
+// Copyright (C) Microsoft Corporation. All rights reserved.
2
+
3
+#pragma once
4
+#include "Microsoft.WSL.Containers.AuthenticateResult.g.h"
5
+
6
+namespace winrt::Microsoft::WSL::Containers::implementation {
7
+struct AuthenticateResult : AuthenticateResultT<AuthenticateResult>
8
+{
9
+ AuthenticateResult(hstring identityToken, winrt::Microsoft::WSL::Containers::IdentityTokenType tokenType);
10
+
11
+ hstring IdentityToken();
12
+ winrt::Microsoft::WSL::Containers::IdentityTokenType TokenType();
13
+
14
+private:
15
+ hstring m_identityToken{};
16
+ winrt::Microsoft::WSL::Containers::IdentityTokenType m_tokenType{};
17
+};
18
+} // namespace winrt::Microsoft::WSL::Containers::implementation
19
+
20
+DEFINE_TYPE_HELPERS(AuthenticateResult);
src/windows/WslcSDK/winrt/CMakeLists.txt
+2
@@ -2,6 +2,7 @@ add_idl_winrt(wslcsdkwinrtidl "wslcsdk.idl")
2
set_target_properties(wslcsdkwinrtidl PROPERTIES FOLDER windows)
3
4
set(SOURCES
5
+ AuthenticateResult.cpp
6
Container.cpp
7
ContainerNamedVolume.cpp
8
ContainerPortMapping.cpp
@@ -26,6 +27,7 @@ set(SOURCES
27
)
28
29
set(HEADERS
30
+ AuthenticateResult.h
31
Container.h
32
ContainerNamedVolume.h
33
ContainerPortMapping.h
src/windows/WslcSDK/winrt/Session.cpp
+6
-2
@@ -14,6 +14,7 @@ Abstract:
14
15
#include "precomp.h"
16
#include "Session.h"
17
+#include "AuthenticateResult.h"
18
#include "ProcessCrashInformation.h"
19
#include "SessionSettings.h"
20
#include "Microsoft.WSL.Containers.Session.g.cpp"
@@ -319,7 +320,7 @@ void Session::DeleteVhdVolume(hstring const& name)
320
THROW_MSG_IF_FAILED(hr, errorMessage);
321
}
322
322
-hstring Session::Authenticate(Uri const& serverAddress, hstring const& username, hstring const& password)
323
+winrt::Microsoft::WSL::Containers::AuthenticateResult Session::Authenticate(Uri const& serverAddress, hstring const& username, hstring const& password)
324
{
325
if (!serverAddress)
326
{
@@ -335,15 +336,18 @@ hstring Session::Authenticate(Uri const& serverAddress, hstring const& username,
336
337
wil::unique_cotaskmem_string errorMessage;
338
wil::unique_cotaskmem_ansistring token;
339
+ WslcIdentityTokenType tokenType{};
340
auto hr = WslcSessionAuthenticate(
341
ToHandle(),
342
winrt::to_string(serverAddress.ToString()).c_str(),
343
winrt::to_string(username).c_str(),
344
winrt::to_string(password).c_str(),
345
token.put(),
346
+ &tokenType,
347
errorMessage.put());
348
THROW_MSG_IF_FAILED(hr, errorMessage);
346
- return winrt::to_hstring(token.get());
349
+ return winrt::make<implementation::AuthenticateResult>(
350
+ winrt::to_hstring(token.get()), static_cast<winrt::Microsoft::WSL::Containers::IdentityTokenType>(tokenType));
351
}
352
353
winrt::event_token Session::Terminated(winrt::Microsoft::WSL::Containers::SessionTerminationHandler const& handler)
src/windows/WslcSDK/winrt/Session.h
+2
-1
@@ -38,7 +38,8 @@ struct Session : SessionT<Session>
38
void TagImage(winrt::Microsoft::WSL::Containers::TagImageOptions const& options);
39
void CreateVhdVolume(winrt::Microsoft::WSL::Containers::VhdOptions const& options);
40
void DeleteVhdVolume(hstring const& name);
41
- hstring Authenticate(winrt::Windows::Foundation::Uri const& serverAddress, hstring const& username, hstring const& password);
41
+ winrt::Microsoft::WSL::Containers::AuthenticateResult Authenticate(
42
+ winrt::Windows::Foundation::Uri const& serverAddress, hstring const& username, hstring const& password);
43
winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::WSL::Containers::ImageInfo> GetImages();
44
winrt::event_token Terminated(winrt::Microsoft::WSL::Containers::SessionTerminationHandler const& handler);
45
void Terminated(winrt::event_token const& token) noexcept;
src/windows/WslcSDK/winrt/wslcsdk.idl
+14
-1
@@ -34,6 +34,19 @@ namespace Microsoft.WSL.Containers
34
35
delegate void ProcessCrashHandler(ProcessCrashInformation information);
36
37
+ enum IdentityTokenType
38
+ {
39
+ Unknown = 0,
40
+ Token = 1,
41
+ Credentials = 2,
42
+ };
43
+
44
+ runtimeclass AuthenticateResult
45
+ {
46
+ String IdentityToken { get; };
47
+ IdentityTokenType TokenType { get; };
48
+ };
49
+
50
runtimeclass SessionSettings
51
{
52
SessionSettings(String name, String storagePath);
@@ -73,7 +86,7 @@ namespace Microsoft.WSL.Containers
86
void CreateVhdVolume(VhdOptions options);
87
void DeleteVhdVolume(String name);
88
76
- String Authenticate(Windows.Foundation.Uri serverAddress, String username, String password);
89
+ AuthenticateResult Authenticate(Windows.Foundation.Uri serverAddress, String username, String password);
90
91
IVectorView<ImageInfo> GetImages();
92
src/windows/WslcSDK/wslcsdk.cpp
+28
-3
@@ -1536,6 +1536,7 @@ STDAPI WslcSessionAuthenticate(
1536
_In_z_ PCSTR username,
1537
_In_z_ PCSTR password,
1538
_Outptr_result_z_ PSTR* identityToken,
1539
+ _Out_opt_ WslcIdentityTokenType* tokenType,
1540
_Outptr_opt_result_z_ PWSTR* errorMessage)
1541
try
1542
{
@@ -1548,12 +1549,36 @@ try
1549
RETURN_HR_IF_NULL(E_POINTER, identityToken);
1550
1551
*identityToken = nullptr;
1552
+ if (tokenType != nullptr)
1553
+ {
1554
+ *tokenType = WSLC_IDENTITY_TOKEN_TYPE_UNKNOWN;
1555
+ }
1556
1552
- wil::unique_cotaskmem_ansistring token;
1553
- auto hr = errorInfoWrapper.CaptureResult(internalType->session->Authenticate(serverAddress, username, password, &token));
1557
+ wil::unique_cotaskmem_ansistring rawToken;
1558
+ auto hr = errorInfoWrapper.CaptureResult(internalType->session->Authenticate(serverAddress, username, password, &rawToken));
1559
if (SUCCEEDED(hr))
1560
{
1556
- *identityToken = token.release();
1561
+ std::string authHeader;
1562
+ WslcIdentityTokenType type;
1563
+
1564
+ if (rawToken && strlen(rawToken.get()) > 0)
1565
+ {
1566
+ authHeader = BuildRegistryAuthHeader(std::string{rawToken.get()});
1567
+ type = WSLC_IDENTITY_TOKEN_TYPE_TOKEN;
1568
+ }
1569
+ else
1570
+ {
1571
+ authHeader = BuildRegistryAuthHeader(std::string{username}, std::string{password});
1572
+ type = WSLC_IDENTITY_TOKEN_TYPE_CREDENTIALS;
1573
+ }
1574
+
1575
+ auto result = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(authHeader.c_str());
1576
+ *identityToken = result.release();
1577
+
1578
+ if (tokenType != nullptr)
1579
+ {
1580
+ *tokenType = type;
1581
+ }
1582
}
1583
1584
return errorInfoWrapper;
src/windows/WslcSDK/wslcsdk.h
+35
-6
@@ -530,7 +530,15 @@ typedef struct WslcPushImageOptions
530
531
STDAPI WslcPushSessionImage(_In_ WslcSession session, _In_ const WslcPushImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);
532
533
-// Authenticates with a container registry and returns an identity token.
533
+typedef enum WslcIdentityTokenType
534
+{
535
+ WSLC_IDENTITY_TOKEN_TYPE_UNKNOWN = 0,
536
+ WSLC_IDENTITY_TOKEN_TYPE_TOKEN = 1,
537
+ WSLC_IDENTITY_TOKEN_TYPE_CREDENTIALS = 2,
538
+} WslcIdentityTokenType;
539
+
540
+// Authenticates with a container registry and returns an identity token suitable for use as
541
+// the registryAuth value in WslcPullSessionImage and WslcPushSessionImage.
542
//
543
// Parameters:
544
// session
@@ -546,21 +554,42 @@ STDAPI WslcPushSessionImage(_In_ WslcSession session, _In_ const WslcPushImageOp
554
// The password for authentication.
555
//
556
// identityToken
549
-// On success, receives a pointer to a null-terminated ANSI string
550
-// containing the identity token.
557
+// On success, receives a pointer to a null-terminated ANSI string containing a
558
+// base64-encoded JSON object that can be passed directly as the registryAuth value to
559
+// WslcPullSessionImage or WslcPushSessionImage.
560
//
552
-// The string is allocated using CoTaskMemAlloc. The caller takes
553
-// ownership of the returned memory and must free it by calling
554
-// CoTaskMemFree when it is no longer needed.
561
+// The string is allocated using CoTaskMemAlloc. The caller takes ownership of the
562
+// returned memory and must free it by calling CoTaskMemFree when it is no longer needed.
563
+//
564
+// tokenType
565
+// Optional. On success, receives the type of credential embedded in identityToken:
566
+// WSLC_IDENTITY_TOKEN_TYPE_TOKEN - the server returned an identity token;
567
+// identityToken encodes {"identitytoken": ...}
568
+// WSLC_IDENTITY_TOKEN_TYPE_CREDENTIALS - the server returned no token; the supplied
569
+// username/password are embedded instead as
570
+// {"username": ..., "password": ...}
571
+// On failure, set to WSLC_IDENTITY_TOKEN_TYPE_UNKNOWN.
572
+// May be null if the caller does not need the token type.
573
+//
574
+// errorMessage
575
+// Optional. On failure, receives a human-readable error message. May be null.
576
//
577
// Return Value:
578
// S_OK on success. Otherwise, an HRESULT error code indicating the failure.
579
+//
580
+// Outcome table:
581
+// Outcome | HRESULT | identityToken | tokenType
582
+// ------------------------------|---------|--------------------------------------|----------
583
+// Failure | FAILED | nullptr | UNKNOWN
584
+// Success, server returns token | S_OK | base64({"identitytoken": "<token>"}) | TOKEN
585
+// Success, no token returned | S_OK | base64({"username":..,"password":..})| CREDENTIALS
586
STDAPI WslcSessionAuthenticate(
587
_In_ WslcSession session,
588
_In_z_ PCSTR serverAddress,
589
_In_z_ PCSTR username,
590
_In_z_ PCSTR password,
591
_Outptr_result_z_ PSTR* identityToken,
592
+ _Out_opt_ WslcIdentityTokenType* tokenType,
593
_Outptr_opt_result_z_ PWSTR* errorMessage);
594
595
// Retrieves the list of container images
test/windows/WslcSdkTests.cpp
+26
-10
@@ -2335,19 +2335,27 @@ class WslcSdkTests
2335
{
2336
wil::unique_cotaskmem_ansistring token;
2337
wil::unique_cotaskmem_string errorMsg;
2338
+ WslcIdentityTokenType tokenType{};
2339
VERIFY_ARE_EQUAL(
2339
- WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, "wrong-password", &token, &errorMsg), E_FAIL);
2340
+ WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, "wrong-password", &token, &tokenType, &errorMsg),
2341
+ E_FAIL);
2342
VERIFY_IS_NOT_NULL(errorMsg.get());
2343
+ VERIFY_ARE_EQUAL(tokenType, WSLC_IDENTITY_TOKEN_TYPE_UNKNOWN);
2344
}
2345
2343
- // Positive: correct credentials must succeed and return a non-null token.
2346
+ // Positive: correct credentials must succeed and return a non-null, registry-auth-ready token.
2347
{
2348
wil::unique_cotaskmem_ansistring token;
2349
wil::unique_cotaskmem_string errorMsg;
2347
- VERIFY_SUCCEEDED(WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, c_password, &token, &errorMsg));
2350
+ WslcIdentityTokenType tokenType{};
2351
+ VERIFY_SUCCEEDED(WslcSessionAuthenticate(
2352
+ m_defaultSession, registryAddress.c_str(), c_username, c_password, &token, &tokenType, &errorMsg));
2353
VERIFY_IS_NOT_NULL(token.get());
2354
+ // The local test registry does not return an identity token, so credentials are embedded.
2355
+ VERIFY_ARE_EQUAL(tokenType, WSLC_IDENTITY_TOKEN_TYPE_CREDENTIALS);
2356
}
2357
2358
+ // The local registry requires auth; push the test image for the pull tests below.
2359
auto xRegistryAuth = wsl::windows::common::wslutil::BuildRegistryAuthHeader(c_username, c_password);
2360
PushImageToRegistry("hello-world", "latest", registryAddress, xRegistryAuth);
2361
@@ -2356,11 +2364,16 @@ class WslcSdkTests
2364
auto imageCleanup = wil::scope_exit_log(
2365
WI_DIAGNOSTICS_INFO, [&]() { LOG_IF_FAILED(WslcDeleteSessionImage(m_defaultSession, image.c_str(), nullptr)); });
2366
2359
- // Pulling with credentials should succeed.
2367
+ // Positive: pulling with the identityToken from WslcSessionAuthenticate directly should succeed,
2368
+ // demonstrating that the output can be passed as registryAuth without any transformation.
2369
{
2370
+ wil::unique_cotaskmem_ansistring authToken;
2371
+ VERIFY_SUCCEEDED(WslcSessionAuthenticate(
2372
+ m_defaultSession, registryAddress.c_str(), c_username, c_password, &authToken, nullptr, nullptr));
2373
+
2374
WslcPullImageOptions opts{};
2375
opts.uri = image.c_str();
2363
- opts.registryAuth = xRegistryAuth.c_str();
2376
+ opts.registryAuth = authToken.get();
2377
VERIFY_SUCCEEDED(WslcPullSessionImage(m_defaultSession, &opts, nullptr));
2378
VERIFY_IS_TRUE(HasImage(image));
2379
}
@@ -2388,13 +2401,16 @@ class WslcSdkTests
2401
VERIFY_IS_NOT_NULL(errorMsg.get());
2402
}
2403
2391
- // Negative: null parameters must fail.
2404
+ // Negative: null parameters must fail; tokenType is optional and may be null.
2405
{
2406
wil::unique_cotaskmem_ansistring token;
2394
- VERIFY_ARE_EQUAL(WslcSessionAuthenticate(m_defaultSession, nullptr, c_username, c_password, &token, nullptr), E_POINTER);
2395
- VERIFY_ARE_EQUAL(WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), nullptr, c_password, &token, nullptr), E_POINTER);
2396
- VERIFY_ARE_EQUAL(WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, nullptr, &token, nullptr), E_POINTER);
2397
- VERIFY_ARE_EQUAL(WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, c_password, nullptr, nullptr), E_POINTER);
2407
+ VERIFY_ARE_EQUAL(WslcSessionAuthenticate(m_defaultSession, nullptr, c_username, c_password, &token, nullptr, nullptr), E_POINTER);
2408
+ VERIFY_ARE_EQUAL(
2409
+ WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), nullptr, c_password, &token, nullptr, nullptr), E_POINTER);
2410
+ VERIFY_ARE_EQUAL(
2411
+ WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, nullptr, &token, nullptr, nullptr), E_POINTER);
2412
+ VERIFY_ARE_EQUAL(
2413
+ WslcSessionAuthenticate(m_defaultSession, registryAddress.c_str(), c_username, c_password, nullptr, nullptr, nullptr), E_POINTER);
2414
}
2415
}
2416
test/windows/WslcSdkWinRTTests.cpp
+11
-5
@@ -1624,8 +1624,13 @@ class WslcSdkWinRtTests
1624
// Negative: wrong password must fail.
1625
VERIFY_THROWS_HR(m_defaultSession.Authenticate(serverUri, winrt::to_hstring(c_username), L"wrong-password"), E_FAIL);
1626
1627
- // Positive: correct credentials
1628
- VERIFY_NO_THROW(m_defaultSession.Authenticate(serverUri, winrt::to_hstring(c_username), winrt::to_hstring(c_password)));
1627
+ // Positive: correct credentials must return a non-null token of the expected type.
1628
+ {
1629
+ const auto result = m_defaultSession.Authenticate(serverUri, winrt::to_hstring(c_username), winrt::to_hstring(c_password));
1630
+ VERIFY_IS_FALSE(result.IdentityToken().empty());
1631
+ // The local test registry does not return an identity token, so credentials are embedded.
1632
+ VERIFY_ARE_EQUAL(result.TokenType(), WSLCSDK::IdentityTokenType::Credentials);
1633
+ }
1634
1635
const auto xRegistryAuth = wsl::windows::common::wslutil::BuildRegistryAuthHeader(c_username, c_password);
1636
PushImageToRegistry("hello-world", "latest", registryAddress, xRegistryAuth);
@@ -1634,11 +1639,12 @@ class WslcSdkWinRtTests
1639
1640
auto cleanup = SCOPE_CLEANUP(m_defaultSession.DeleteImage(image));
1641
1637
- // Positive: pulling with correct credentials must succeed.
1642
+ // Positive: the IdentityToken from Authenticate can be passed directly as RegistryAuth.
1643
{
1644
+ const auto authResult = m_defaultSession.Authenticate(serverUri, winrt::to_hstring(c_username), winrt::to_hstring(c_password));
1645
auto opts = WSLCSDK::PullImageOptions(image);
1640
- opts.RegistryAuth(winrt::to_hstring(xRegistryAuth));
1641
- m_defaultSession.PullImageAsync(opts).get();
1646
+ opts.RegistryAuth(authResult.IdentityToken());
1647
+ VERIFY_NO_THROW(m_defaultSession.PullImageAsync(opts).get());
1648
VERIFY_IS_TRUE(HasImage(image));
1649
}
1650