6#include <sso-mib/sso-mib.h>
7#include <freerdp/crypto/crypto.h>
9#include <winpr/string.h>
11#include "sso_mib_tokens.h"
13#include <freerdp/log.h>
14#define TAG CLIENT_TAG("common.sso")
18 SSO_MIB_STATE_INIT = 0,
19 SSO_MIB_STATE_FAILED = 1,
20 SSO_MIB_STATE_SUCCESS = 2,
23struct MIBClientWrapper
26 enum sso_mib_state state;
27 pGetCommonAccessToken GetCommonAccessToken;
31static BOOL sso_mib_get_avd_access_token(rdpClientContext* client_context,
char** token)
33 WINPR_ASSERT(client_context);
34 WINPR_ASSERT(client_context->mibClientWrapper);
35 WINPR_ASSERT(client_context->mibClientWrapper->app);
38 MIBAccount* account =
nullptr;
39 GSList* scopes =
nullptr;
44 account = mib_client_app_get_account_by_upn(client_context->mibClientWrapper->app,
nullptr);
50 scopes = g_slist_append(scopes, g_strdup(
"https://www.wvd.microsoft.com/.default"));
52 MIBPrt* prt = mib_client_app_acquire_token_silent(client_context->mibClientWrapper->app,
53 account, scopes,
nullptr,
nullptr,
nullptr);
56 const char* access_token = mib_prt_get_access_token(prt);
59 *token = strdup(access_token);
64 rc = TRUE && *token !=
nullptr;
67 g_object_unref(account);
68 g_slist_free_full(scopes, g_free);
73static BOOL sso_mib_get_rdsaad_access_token(rdpClientContext* client_context,
const char* scope,
74 const char* req_cnf,
char** token)
76 WINPR_ASSERT(client_context);
77 WINPR_ASSERT(client_context->mibClientWrapper);
78 WINPR_ASSERT(client_context->mibClientWrapper->app);
81 WINPR_ASSERT(req_cnf);
83 GSList* scopes =
nullptr;
84 WINPR_JSON* json =
nullptr;
85 MIBPopParams* params =
nullptr;
89 BYTE* req_cnf_dec =
nullptr;
90 size_t req_cnf_dec_len = 0;
92 scopes = g_slist_append(scopes, g_strdup(scope));
95 crypto_base64_decode(req_cnf, strlen(req_cnf), &req_cnf_dec, &req_cnf_dec_len);
117 params = mib_pop_params_new(MIB_AUTH_SCHEME_POP, MIB_REQUEST_METHOD_GET,
"");
118 mib_pop_params_set_kid(params, kid);
119 MIBPrt* prt = mib_client_app_acquire_token_interactive(client_context->mibClientWrapper->app,
120 scopes, MIB_PROMPT_NONE,
nullptr,
121 nullptr,
nullptr, params);
124 const gchar* str = mib_prt_get_access_token(prt);
126 *token = strdup(str);
127 rc = *token !=
nullptr;
133 g_object_unref(params);
136 g_slist_free_full(scopes, g_free);
141static BOOL sso_mib_get_access_token(rdpContext* context, AccessTokenType tokenType,
char** token,
145 rdpClientContext* client_context = (rdpClientContext*)context;
146 WINPR_ASSERT(client_context);
147 WINPR_ASSERT(client_context->mibClientWrapper);
149 if (!client_context->mibClientWrapper->app)
151 const char* client_id =
159 const BOOL useTenant =
161 const char* tenantid =
"common";
166 char* authority =
nullptr;
167 if (base && tenantid)
170 winpr_asprintf(&authority, &len,
"https://%s/%s", base, tenantid);
175 client_context->mibClientWrapper->app = mib_public_client_app_new(
176 client_id, authority ? authority : MIB_AUTHORITY_COMMON, nullptr, nullptr);
180 if (!client_context->mibClientWrapper->app)
183 const char* scope =
nullptr;
184 const char* req_cnf =
nullptr;
186 va_list ap = WINPR_C_ARRAY_INIT;
189 if (tokenType == ACCESS_TOKEN_TYPE_AAD)
191 scope = va_arg(ap,
const char*);
192 req_cnf = va_arg(ap,
const char*);
195 if ((client_context->mibClientWrapper->state == SSO_MIB_STATE_INIT) ||
196 (client_context->mibClientWrapper->state == SSO_MIB_STATE_SUCCESS))
200 case ACCESS_TOKEN_TYPE_AVD:
202 rc = sso_mib_get_avd_access_token(client_context, token);
204 client_context->mibClientWrapper->state = SSO_MIB_STATE_SUCCESS;
207 WLog_WARN(TAG,
"Getting AVD token from identity broker failed, falling back to "
208 "browser-based authentication.");
209 client_context->mibClientWrapper->state = SSO_MIB_STATE_FAILED;
213 case ACCESS_TOKEN_TYPE_AAD:
216 char* scope_copy = winpr_str_url_decode(scope, strlen(scope));
218 WLog_ERR(TAG,
"Failed to decode scope");
222 sso_mib_get_rdsaad_access_token(client_context, scope_copy, req_cnf, token);
225 client_context->mibClientWrapper->state = SSO_MIB_STATE_SUCCESS;
229 "Getting RDS token from identity broker failed, falling back to "
230 "browser-based authentication.");
231 client_context->mibClientWrapper->state = SSO_MIB_STATE_FAILED;
240 if (!rc && client_context->mibClientWrapper->GetCommonAccessToken)
241 rc = client_context->mibClientWrapper->GetCommonAccessToken(context, tokenType, token,
242 count, scope, req_cnf);
248MIBClientWrapper* sso_mib_new(rdpContext* context)
251 MIBClientWrapper* mibClientWrapper = (MIBClientWrapper*)calloc(1,
sizeof(MIBClientWrapper));
252 if (!mibClientWrapper)
255 mibClientWrapper->GetCommonAccessToken = freerdp_get_common_access_token(context);
256 if (!freerdp_set_common_access_token(context, sso_mib_get_access_token))
258 sso_mib_free(mibClientWrapper);
261 mibClientWrapper->state = SSO_MIB_STATE_INIT;
262 return mibClientWrapper;
265void sso_mib_free(MIBClientWrapper* sso)
271 g_object_unref(sso->app);
WINPR_ATTR_NODISCARD WINPR_API WINPR_JSON * WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON *object, const char *string)
Same as WINPR_JSON_GetObjectItem but with case sensitive matching.
WINPR_API void WINPR_JSON_Delete(WINPR_JSON *item)
Delete a WinPR JSON wrapper object.
WINPR_ATTR_NODISCARD WINPR_API const char * WINPR_JSON_GetStringValue(WINPR_JSON *item)
Return the String value of a JSON item.
WINPR_API WINPR_JSON * WINPR_JSON_Parse(const char *value)
Parse a '\0' terminated JSON string.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.