mirror of https://github.com/FreeRDP/FreeRDP
Use popup browser for AAD auth in SDL client
Optionally build the SDL client with Qt WebEngine to create a popup browser for authentication to AAD. Also change the URL output on the command line to use the "nativeclient" redirect for easier copy/pasting of the authorization code.
This commit is contained in:
parent
ba7fdcb5f0
commit
449b96adb2
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Popup browser for AAD authentication
|
||||
*
|
||||
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.com>
|
||||
*
|
||||
* 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 <QApplication>
|
||||
#include <QWebEngineView>
|
||||
#include <QWebEngineProfile>
|
||||
#include <QWebEngineUrlScheme>
|
||||
#include <QWebEngineUrlSchemeHandler>
|
||||
#include <QWebEngineUrlRequestJob>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Popup browser for AAD authentication
|
||||
*
|
||||
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.com>
|
||||
*
|
||||
* 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 <freerdp/freerdp.h>
|
||||
|
||||
#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
|
|
@ -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);
|
||||
|
|
|
@ -61,8 +61,6 @@
|
|||
#include <freerdp/log.h>
|
||||
#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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue