diff --git a/client/SDL/CMakeLists.txt b/client/SDL/CMakeLists.txt index 885fefffd..00d44944f 100644 --- a/client/SDL/CMakeLists.txt +++ b/client/SDL/CMakeLists.txt @@ -98,10 +98,25 @@ set(LIBS freerdp-client ) +option(WITH_WEBVIEW "Build with QtWebEngine support for AAD login popup browser" OFF) +if (WITH_WEBVIEW) + include(FindPkgConfig) + pkg_check_modules(QT REQUIRED Qt5WebEngineWidgets) + + list(APPEND SRCS sdl_webview.cpp) + add_definitions(-DWITH_WEBVIEW) + include_directories(${QT_INCLUDE_DIRS}) + list(APPEND LIBS ${QT_LIBRARIES}) +endif() + add_executable(${PROJECT_NAME} ${SRCS} ) +if (QT_FOUND) + target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) +endif() + set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "sdl-freerdp") target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBS}) set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Client/SDL") diff --git a/client/SDL/sdl_freerdp.cpp b/client/SDL/sdl_freerdp.cpp index d2058f056..52193a09c 100644 --- a/client/SDL/sdl_freerdp.cpp +++ b/client/SDL/sdl_freerdp.cpp @@ -54,6 +54,10 @@ #include "sdl_touch.hpp" #include "sdl_pointer.hpp" +#ifdef WITH_WEBVIEW +#include "sdl_webview.hpp" +#endif + #define SDL_TAG CLIENT_TAG("SDL") enum SDL_EXIT_CODE @@ -1171,6 +1175,11 @@ static BOOL sdl_client_new(freerdp* instance, rdpContext* context) instance->VerifyCertificateEx = client_cli_verify_certificate_ex; instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex; instance->LogonErrorInfo = sdl_logon_error_info; +#ifdef WITH_WEBVIEW + instance->GetAadAuthCode = sdl_webview_get_aad_auth_code; +#else + instance->GetAadAuthCode = client_cli_get_aad_auth_code; +#endif /* TODO: Client display set up */ sdl->initialize = CreateEventA(nullptr, TRUE, FALSE, nullptr); diff --git a/client/SDL/sdl_webview.cpp b/client/SDL/sdl_webview.cpp new file mode 100644 index 000000000..a10d293d6 --- /dev/null +++ b/client/SDL/sdl_webview.cpp @@ -0,0 +1,96 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Popup browser for AAD authentication + * + * Copyright 2023 Isaac Klein + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "sdl_webview.hpp" + +class SchemeHandler : public QWebEngineUrlSchemeHandler +{ + public: + SchemeHandler(char** code, QObject* parent = nullptr) + : QWebEngineUrlSchemeHandler(parent), codeptr(code){}; + + void requestStarted(QWebEngineUrlRequestJob* request) + { + QUrl url = request->requestUrl(); + + for (auto& param : url.query().split('&')) + { + QStringList pair = param.split('='); + + if (pair.size() != 2 || pair[0] != "code") + continue; + + QByteArray code = pair[1].toUtf8(); + *codeptr = (char*)calloc(1, code.size() + 1); + strcpy(*codeptr, code.constData()); + break; + } + qApp->exit(); + } + + private: + char** codeptr; +}; + +BOOL sdl_webview_get_aad_auth_code(freerdp* instance, const char* hostname, char** code, + const char** client_id, const char** redirect_uri) +{ + int argc = 1; + char* name = "FreeRDP WebView"; + size_t size = 0; + char* login_url = NULL; + + *code = NULL; + *client_id = "5177bc73-fd99-4c77-a90c-76844c9b6999"; + *redirect_uri = + "ms-appx-web%3a%2f%2fMicrosoft.AAD.BrokerPlugin%2f5177bc73-fd99-4c77-a90c-76844c9b6999"; + + winpr_asprintf(&login_url, &size, + "https://login.microsoftonline.com/common/oauth2/v2.0/" + "authorize?client_id=%s&response_type=" + "code&scope=ms-device-service%%3A%%2F%%2Ftermsrv.wvd.microsoft.com%%2Fname%%" + "2F%s%%2Fuser_impersonation&redirect_uri=%s", + *client_id, hostname, *redirect_uri); + + QWebEngineUrlScheme::registerScheme(QWebEngineUrlScheme("ms-appx-web")); + + QApplication app(argc, &name); + + SchemeHandler handler(code); + QWebEngineProfile::defaultProfile()->installUrlSchemeHandler("ms-appx-web", &handler); + + QWebEngineView webview; + webview.load(QUrl(login_url)); + webview.show(); + + app.exec(); + + free(login_url); + return (*code != NULL); +} diff --git a/client/SDL/sdl_webview.hpp b/client/SDL/sdl_webview.hpp new file mode 100644 index 000000000..8e82587bd --- /dev/null +++ b/client/SDL/sdl_webview.hpp @@ -0,0 +1,34 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Popup browser for AAD authentication + * + * Copyright 2023 Isaac Klein + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + BOOL sdl_webview_get_aad_auth_code(freerdp* instance, const char* hostname, char** code, + const char** client_id, const char** redirect_uri); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index bc649ff7f..ebf0e42cd 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1879,6 +1879,7 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) instance->PostDisconnect = xf_post_disconnect; instance->PostFinalDisconnect = xf_post_final_disconnect; instance->LogonErrorInfo = xf_logon_error_info; + instance->GetAadAuthCode = client_cli_get_aad_auth_code; PubSub_SubscribeTerminate(context->pubSub, xf_TerminateEventHandler); #ifdef WITH_XRENDER PubSub_SubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler); diff --git a/client/common/client.c b/client/common/client.c index 58106b8d4..0e07a21a5 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -61,8 +61,6 @@ #include #define TAG CLIENT_TAG("common") -#define OAUTH2_CLIENT_ID "5177bc73-fd99-4c77-a90c-76844c9b6999" - static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context) { RDP_CLIENT_ENTRY_POINTS* pEntryPoints; @@ -77,7 +75,6 @@ static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context) instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex; instance->PresentGatewayMessage = client_cli_present_gateway_message; instance->LogonErrorInfo = client_cli_logon_error_info; - instance->GetAadAuthCode = client_cli_get_aad_auth_code; pEntryPoints = instance->pClientEntryPoints; WINPR_ASSERT(pEntryPoints); @@ -938,34 +935,57 @@ BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isD return TRUE; } -BOOL client_cli_get_aad_auth_code(freerdp* instance, const char* hostname, char** code) +BOOL client_cli_get_aad_auth_code(freerdp* instance, const char* hostname, char** code, + const char** client_id, const char** redirect_uri) { - size_t len = 0; - char* p = NULL; + size_t size = 0; + char* url = NULL; WINPR_ASSERT(instance); WINPR_ASSERT(hostname); WINPR_ASSERT(code); + WINPR_ASSERT(client_id); + WINPR_ASSERT(redirect_uri); + *code = NULL; + *client_id = "a85cf173-4192-42f8-81fa-777a763e6e2c"; + *redirect_uri = "https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient"; - printf( - "Browse to: " - "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" OAUTH2_CLIENT_ID - "&response_type=code" - "&scope=ms-device-service%%3A%%2F%%2Ftermsrv.wvd.microsoft.com%%2Fname%%2F%s%%2Fuser_" - "impersonation" - "&redirect_uri=ms-appx-web%%3a%%2f%%2fMicrosoft.AAD.BrokerPlugin%%2f5177bc73-fd99-4c77-" - "a90c-76844c9b6999\n", - hostname); - printf("Paste authorization code here: "); + printf("Browse to: https://login.microsoftonline.com/common/oauth2/v2.0/" + "authorize?client_id=%s&response_type=" + "code&scope=ms-device-service%%3A%%2F%%2Ftermsrv.wvd.microsoft.com%%2Fname%%" + "2F%s%%2Fuser_impersonation&redirect_uri=%s" + "\n", + *client_id, hostname, *redirect_uri); + printf("Paste redirect URL here: \n"); - if (freerdp_interruptible_get_line(instance->context, code, &len, stdin) < 0) + if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0) return FALSE; - p = strpbrk(*code, "\r\n"); - if (p) - *p = 0; - return TRUE; + for (char* p = strchr(url, '?'); p++ != NULL; p = strchr(p, '&')) + { + if (strncmp(p, "code=", 5) == 0) + { + char* end = NULL; + p += 5; + + end = strchr(p, '&'); + if (end) + *end = 0; + else + end = strchr(p, '\0'); + + *code = calloc(1, end - p); + if (!(*code)) + break; + + strcpy(*code, p); + break; + } + } + + free(url); + return (*code != NULL); } BOOL client_auto_reconnect(freerdp* instance) diff --git a/include/freerdp/client.h b/include/freerdp/client.h index 849b1ee9b..664253c9a 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -157,7 +157,8 @@ extern "C" FREERDP_API int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type); FREERDP_API BOOL client_cli_get_aad_auth_code(freerdp* instance, const char* hostname, - char** code); + char** code, const char** client_id, + const char** redirect_uri); FREERDP_API void freerdp_client_OnChannelConnectedEventHandler(void* context, diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index d1f1938cf..3b1df52e0 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -126,7 +126,8 @@ extern "C" char** domain, rdp_auth_reason reason); typedef BOOL (*pChooseSmartcard)(freerdp* instance, SmartcardCertInfo** cert_list, DWORD count, DWORD* choice, BOOL gateway); - typedef BOOL (*pGetAadAuthCode)(freerdp* instance, const char* hostname, char** code); + typedef BOOL (*pGetAadAuthCode)(freerdp* instance, const char* hostname, char** code, + const char** client_id, const char** redirect_uri); /** @brief Callback used if user interaction is required to accept * an unknown certificate. diff --git a/libfreerdp/core/aad.c b/libfreerdp/core/aad.c index ba0860cbb..280ccc974 100644 --- a/libfreerdp/core/aad.c +++ b/libfreerdp/core/aad.c @@ -94,7 +94,6 @@ static int BIO_get_line(BIO* bio, char* buf, int size) } #endif -#define OAUTH2_CLIENT_ID "5177bc73-fd99-4c77-a90c-76844c9b6999" static const char* auth_server = "login.microsoftonline.com"; static const char nonce_http_request[] = "" @@ -115,13 +114,13 @@ static const char token_http_request_header[] = "\r\n"; static const char token_http_request_body[] = "" - "client_id=" OAUTH2_CLIENT_ID "&grant_type=authorization_code" + "client_id=%s&grant_type=authorization_code" "&code=%s" - "&scope=ms-device-service%%3A%%2F%%2Ftermsrv.wvd.microsoft.com%%2Fname%%2F%s%%2Fuser_" + "&scope=ms-device-service%%3A%%2F%%2Ftermsrv.wvd.microsoft.com%%2Fid%%2F23444de0-61b7-42a2-" + "bef2-5512675a5f4d%%2Fuser_" "impersonation" "&req_cnf=%s" - "&redirect_uri=ms-appx-web%%3a%%2f%%2fMicrosoft.AAD.BrokerPlugin%%2f5177bc73-fd99-4c77-a90c-" - "76844c9b6999" + "&redirect_uri=%s" "\r\n\r\n"; static BOOL get_encoded_rsa_params(wLog* wlog, rdpPrivateKey* key, char** e, char** n); @@ -408,7 +407,8 @@ fail: return rc; } -static BOOL aad_send_token_request(rdpAad* aad, BIO* bio, const char* auth_code) +static BOOL aad_send_token_request(rdpAad* aad, BIO* bio, const char* auth_code, + const char* client_id, const char* redirect_uri) { BOOL rc = FALSE; @@ -416,8 +416,8 @@ static BOOL aad_send_token_request(rdpAad* aad, BIO* bio, const char* auth_code) char* req_header = NULL; size_t req_body_len = 0; size_t req_header_len = 0; - const int trc = winpr_asprintf(&req_body, &req_body_len, token_http_request_body, auth_code, - aad->hostname, aad->kid); + const int trc = winpr_asprintf(&req_body, &req_body_len, token_http_request_body, client_id, + auth_code, aad->kid, redirect_uri); if (trc < 0) goto fail; const int trh = winpr_asprintf(&req_header, &req_header_len, token_http_request_header, trc); @@ -443,6 +443,8 @@ int aad_client_begin(rdpAad* aad) SSL_CTX* ssl_ctx = NULL; BIO* bio = NULL; char* auth_code = NULL; + const char* client_id = NULL; + const char* redirect_uri = NULL; WINPR_ASSERT(aad); WINPR_ASSERT(aad->rdpcontext); @@ -481,7 +483,8 @@ int aad_client_begin(rdpAad* aad) WLog_Print(aad->log, WLOG_ERROR, "instance->GetAadAuthCode == NULL"); goto fail; } - const BOOL arc = instance->GetAadAuthCode(instance, aad->hostname, &auth_code); + const BOOL arc = + instance->GetAadAuthCode(instance, aad->hostname, &auth_code, &client_id, &redirect_uri); if (!arc) { WLog_Print(aad->log, WLOG_ERROR, "Unable to obtain authorization code"); @@ -501,7 +504,7 @@ int aad_client_begin(rdpAad* aad) goto fail; /* Construct and send the token request message */ - if (!aad_send_token_request(aad, bio, auth_code)) + if (!aad_send_token_request(aad, bio, auth_code, client_id, redirect_uri)) goto fail; /* Extract the access token from the JSON response */ @@ -560,15 +563,15 @@ static char* aad_create_jws_payload(rdpAad* aad, const char* ts_nonce) size_t bufferlen = 0; const int length = winpr_asprintf(&buffer, &bufferlen, - "{" - "\"ts\":\"%li\"," - "\"at\":\"%s\"," - "\"u\":\"ms-device-service://termsrv.wvd.microsoft.com/name/%s\"," - "\"nonce\":\"%s\"," - "\"cnf\":{\"jwk\":{\"kty\":\"RSA\",\"e\":\"%s\",\"n\":\"%s\"}}," - "\"client_claims\":\"{\\\"aad_nonce\\\":\\\"%s\\\"}\"" - "}", - ts, aad->access_token, aad->hostname, ts_nonce, e, n, aad->nonce); + "{" + "\"ts\":\"%li\"," + "\"at\":\"%s\"," + "\"u\":\"ms-device-service://termsrv.wvd.microsoft.com/name/%s\"," + "\"nonce\":\"%s\"," + "\"cnf\":{\"jwk\":{\"kty\":\"RSA\",\"e\":\"%s\",\"n\":\"%s\"}}," + "\"client_claims\":\"{\\\"aad_nonce\\\":\\\"%s\\\"}\"" + "}", + ts, aad->access_token, aad->hostname, ts_nonce, e, n, aad->nonce); free(e); free(n); diff --git a/libfreerdp/core/smartcardlogon.c b/libfreerdp/core/smartcardlogon.c index 3b17f97d6..a42114834 100644 --- a/libfreerdp/core/smartcardlogon.c +++ b/libfreerdp/core/smartcardlogon.c @@ -249,8 +249,8 @@ static BOOL build_pkinit_args(const rdpSettings* settings, SmartcardCertInfo* sc const char* pkModule = Pkcs11Module ? Pkcs11Module : "opensc-pkcs11.so"; size_t size = 0; - if (winpr_asprintf(&scCert->pkinitArgs, &size, "PKCS11:module_name=%s:slotid=%" PRIu16, pkModule, - (UINT16)scCert->slotId) <= 0) + if (winpr_asprintf(&scCert->pkinitArgs, &size, "PKCS11:module_name=%s:slotid=%" PRIu16, + pkModule, (UINT16)scCert->slotId) <= 0) return FALSE; return TRUE; } diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index 8d8ea7663..89d879e43 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -38,7 +38,7 @@ extern "C" WINPR_API BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator); - + WINPR_API int winpr_asprintf(char** s, size_t* slen, const char* templ, ...); #ifndef _WIN32