FreeRDP
Loading...
Searching...
No Matches
test_qt_aad_auth_helper Namespace Reference

Data Structures

class  HelperProcess
 
class  RedirectHandler
 

Functions

 skip (message)
 
 fail (message)
 
 main ()
 

Variables

int HELLO_TIMEOUT = 20
 
int REQUEST_TIMEOUT = 20
 
int SKIP_EXIT_CODE = 125
 
str BROKER_TARGET = "ms-appx-web://microsoft.aad.brokerplugin/test-client-id?code=TESTCODE123"
 

Detailed Description

Drives the real freerdp-qt-aad-helper binary over its JSON-RPC protocol (see
client/common/aad-auth-helper-protocol.md) against a local HTTP redirect fixture, under
QT_QPA_PLATFORM=offscreen. The protocol travels over a dedicated pair of pipes handed to the
helper via --cmdInFd=/--cmdOutFd= command line arguments (not stdin/stdout - see
client/common/aad_helper.c), so this test builds those pipes itself and passes them the same way
FreeRDP does (see HelperProcess below for the platform-specific handle encoding/inheritance).

This exists to catch, as a regression test, two bugs found while developing the helper: AAD's
native-broker redirect_uri uses the non-standard "ms-appx-web" scheme, which QtWebEngine (1)
never surfaces to navigationRequested() at all unless the scheme is registered first (Chromium
instead hands it off to the desktop environment and the redirect is lost), and (2) - even once
registered - refused with net::ERR_UNSAFE_REDIRECT to let a real https-shaped redirect into it
unless the scheme is also flagged CORS-enabled (see kBrokerScheme's comment in main.cpp for
both). A plain http(s) redirect_uri is exercised too, as a regression check that fix didn't
break the common case.

If the helper doesn't answer the initial "hello" handshake at all, the environment is assumed
unable to run Qt WebEngine (e.g. a minimal CI image missing GL/X11 libs) and the test is skipped
rather than failed.

Function Documentation

◆ fail()

test_qt_aad_auth_helper.fail (   message)

Definition at line 168 of file test_qt_aad_auth_helper.py.

168def fail(message):
169 print(f"FAIL: {message}")
170 sys.exit(1)
171
172

◆ main()

test_qt_aad_auth_helper.main ( )

Definition at line 173 of file test_qt_aad_auth_helper.py.

173def main():
174 if len(sys.argv) != 2:
175 fail("usage: test_qt_aad_auth_helper.py <path-to-freerdp-qt-aad-helper>")
176 helper_path = sys.argv[1]
177 if not os.path.isfile(helper_path):
178 fail(f"helper binary not found: {helper_path}")
179
180 server = http.server.HTTPServer(("127.0.0.1", 0), RedirectHandler)
181 port = server.server_port
182 server_thread = threading.Thread(target=server.serve_forever, daemon=True)
183 server_thread.start()
184
185 env = dict(os.environ)
186 env["QT_QPA_PLATFORM"] = "offscreen"
187 env["QT_QUICK_BACKEND"] = "software"
188 env["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu --disable-software-rasterizer"
189
190 helper = HelperProcess(helper_path, env)
191 try:
192 try:
193 hello = helper.request(
194 "hello", {"protocol_version": 1, "client": "freerdp"}, timeout=HELLO_TIMEOUT
195 )
196 except TimeoutError:
197 skip("helper did not answer 'hello' - environment likely can't run Qt WebEngine")
198 if "error" in hello:
199 fail(f"hello returned an error: {hello['error']}")
200 print(f"hello ok: {hello['result']}")
201
202 # Case 1: real HTTP redirect into AAD's ms-appx-web native-broker scheme - the exact
203 # shape that broke twice during development (scheme not observed at all, then
204 # ERR_UNSAFE_REDIRECT).
205 nav = helper.request(
206 "navigate",
207 {
208 "title": "test",
209 "url": f"http://127.0.0.1:{port}/redirect",
210 "redirect_uri": "ms-appx-web://microsoft.aad.brokerplugin/test-client-id",
211 "timeout_ms": REQUEST_TIMEOUT * 1000,
212 },
213 )
214 if "error" in nav:
215 fail(f"navigate (broker redirect) failed: {nav['error']}")
216 got = nav["result"].get("redirect_url")
217 if got != BROKER_TARGET:
218 fail(f"navigate (broker redirect): expected {BROKER_TARGET!r}, got {got!r}")
219 print("broker redirect ok")
220
221 # Case 2: plain http(s)-shaped redirect_uri - regression check, must keep working.
222 plain_url = f"http://127.0.0.1:{port}/"
223 nav2 = helper.request(
224 "navigate",
225 {
226 "title": "test",
227 "url": plain_url,
228 "redirect_uri": plain_url,
229 "timeout_ms": REQUEST_TIMEOUT * 1000,
230 },
231 )
232 if "error" in nav2:
233 fail(f"navigate (plain redirect_uri) failed: {nav2['error']}")
234 got2 = nav2["result"].get("redirect_url")
235 if got2 != plain_url:
236 fail(f"navigate (plain redirect_uri): expected {plain_url!r}, got {got2!r}")
237 print("plain redirect_uri ok")
238
239 shut = helper.request("shutdown")
240 if shut.get("result") is not None:
241 fail(f"shutdown expected a null result, got {shut}")
242 helper.notify("exit")
243
244 rc = helper.wait(timeout=10)
245 if rc != 0:
246 fail(f"helper exited with code {rc}, expected 0")
247 print("shutdown/exit ok")
248 finally:
249 server.shutdown()
250 if helper.proc.poll() is None:
251 helper.proc.kill()
252
253 print("PASS")
254
255

◆ skip()

test_qt_aad_auth_helper.skip (   message)

Definition at line 163 of file test_qt_aad_auth_helper.py.

163def skip(message):
164 print(f"SKIP: {message}")
165 sys.exit(SKIP_EXIT_CODE)
166
167

Variable Documentation

◆ BROKER_TARGET

str test_qt_aad_auth_helper.BROKER_TARGET = "ms-appx-web://microsoft.aad.brokerplugin/test-client-id?code=TESTCODE123"

Definition at line 55 of file test_qt_aad_auth_helper.py.

◆ HELLO_TIMEOUT

int test_qt_aad_auth_helper.HELLO_TIMEOUT = 20

Definition at line 51 of file test_qt_aad_auth_helper.py.

◆ REQUEST_TIMEOUT

int test_qt_aad_auth_helper.REQUEST_TIMEOUT = 20

Definition at line 52 of file test_qt_aad_auth_helper.py.

◆ SKIP_EXIT_CODE

int test_qt_aad_auth_helper.SKIP_EXIT_CODE = 125

Definition at line 53 of file test_qt_aad_auth_helper.py.