private BWebServiceResponse OnRequest_Internal(HttpListenerContext _Context, Action <string> _ErrorMessageAction = null) { if (!UrlParameters.TryGetValue("redirect_url", out string RedirectUrlEncoded) || RedirectUrlEncoded.Length == 0) { RedirectUrlEncoded = DEFAULT_REDIRECT_URL_ENCODED; } if (_Context.Request.HttpMethod != "GET") { _ErrorMessageAction?.Invoke("SSOLoginRequest: GET method is accepted. But received request method: " + _Context.Request.HttpMethod); return(SSOCommon.MakeCallerRedirected(WebUtility.UrlDecode(RedirectUrlEncoded), true, BWebResponse.Error_BadRequest_Code, "GET method is accepted. But received request method: " + _Context.Request.HttpMethod)); } if (!UrlParameters.TryGetValue("tenant", out string TenantName) || TenantName.Length == 0) { TenantName = DEFAULT_TENANT_NAME; } else { TenantName = TenantName.ToLower(); } //Existing token from header string ClientAuthorization = null; if (BWebUtilities.DoesContextContainHeader(out List <string> ClientAuthorizationHeaderValues, out string _, _Context, "client-authorization")) { BUtility.CheckAndGetFirstStringFromList(ClientAuthorizationHeaderValues, out ClientAuthorization); if (ClientAuthorization != null && ClientAuthorization.Length == 0) { ClientAuthorization = null; } } //Existing token from url parameters //Note: Must be token type prepended. Example: ?existing_token=bearer%20abc123123 if (!UrlParameters.TryGetValue("existing_token", out string ExistingToken) || ExistingToken.Length == 0) { ExistingToken = null; } else { ExistingToken = WebUtility.UrlDecode(ExistingToken); } //If both existing tokens are non-null; it is error if (ClientAuthorization != null && ExistingToken != null) { _ErrorMessageAction?.Invoke("Error: SSOLoginRequest: Both existing tokens from url parameters and headers are non-null."); return(SSOCommon.MakeCallerRedirected(WebUtility.UrlDecode(RedirectUrlEncoded), true, BWebResponse.Error_BadRequest_Code, "Both existing tokens from url parameters and headers are non-null.")); } //From now on, use ClientAuthorization; not ExistingToken if (ExistingToken != null) { ClientAuthorization = ExistingToken; } //Check and try refresh if expired if (ClientAuthorization != null && new Controller_SSOAccessToken(ClientAuthorization, DatabaseService, MemoryService, AzureAD_AppID, AzureAD_ClientSecret, SSOSuperAdmins, _ErrorMessageAction) .PerformCheckAndRefresh( out Controller_SSOAccessToken.EPerformCheckAndRefreshSuccessStatus _, out ClientAuthorization, out string UserID, out string _)) { return(SSOCommon.MakeCallerRedirected(WebUtility.UrlDecode(RedirectUrlEncoded), false, 0, null, UserID, ClientAuthorization)); } //Get api passthrough endpoint from internal set state var LocalErrorString = ""; if (!InternalSetState.GetValueFromMemoryService( out string ApiPassthroughEndpoint, InternalSetState.API_PASSTHROUGH_PUBLIC_ENDPOINT_PROPERTY, MemoryService, (string _Message) => { LocalErrorString = _Message; _ErrorMessageAction?.Invoke(_Message); })) { return(SSOCommon.MakeCallerRedirected(WebUtility.UrlDecode(RedirectUrlEncoded), true, 500, LocalErrorString)); } string ServersideRedirectUrl = WebUtility.UrlEncode(ApiPassthroughEndpoint + "/auth/login/azure/callback"); string AzureAuthenticationEndpointBase = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" + "?client_id=" + AzureAD_AppID + "&response_type=id_token code" + "&redirect_uri=" + ServersideRedirectUrl; var TrialCount = 0; string SSOStateUniqueID; BMemoryQueryParameters SSOStateUniqueID_QueryParameters; do { if (!BUtility.CalculateStringMD5(BUtility.RandomString(32, true), out SSOStateUniqueID, _ErrorMessageAction)) { return(SSOCommon.MakeCallerRedirected(WebUtility.UrlDecode(RedirectUrlEncoded), true, 500, "SSO State ID generation has failed.")); } SSOStateUniqueID_QueryParameters = SSOStateMEntry.ID_SSO_STATE_MEMORY_SERVICE_KEY(SSOStateUniqueID); if (!MemoryService.SetKeyValueConditionally( SSOStateUniqueID_QueryParameters, new Tuple <string, BPrimitiveType>( SSOStateMEntry.HASH_KEY, new BPrimitiveType(JsonConvert.SerializeObject( new SSOStateMEntry() { ServersideRedirectUrl = ServersideRedirectUrl, TenantName = TenantName, Status = SSOStateMEntry.STATUS_AUTHENTICATING }) ) ), _ErrorMessageAction)) { SSOStateUniqueID = null; } } while (SSOStateUniqueID == null && ++TrialCount < 5); if (SSOStateUniqueID == null) { return(SSOCommon.MakeCallerRedirected(WebUtility.UrlDecode(RedirectUrlEncoded), true, 500, "Unique SSO State ID generation has failed.")); } MemoryService.SetKeyExpireTime(SSOStateUniqueID_QueryParameters, TimeSpan.FromSeconds(120), _ErrorMessageAction); var AzureAuthenticationEndpoint = AzureAuthenticationEndpointBase + "&scope=" + SSOCommon.SCOPE_URL_ENCODED + "&response_mode=form_post" + "&nonce=" + SSOStateUniqueID + "&state=" + WebUtility.UrlEncode( "redirect_url=" + RedirectUrlEncoded + "&tenant=" + TenantName + "&state=" + SSOStateUniqueID); return(SSOCommon.MakeCallerRedirected(AzureAuthenticationEndpoint, false, 0, null)); }