public static AuthorizationResult ParseAuthorizeResponse(string webAuthenticationResult, CallState callState) { AuthorizationResult result = null; var resultUri = new Uri(webAuthenticationResult); // NOTE: The Fragment property actually contains the leading '#' character and that must be dropped string resultData = resultUri.Query; if (!string.IsNullOrWhiteSpace(resultData)) { // Remove the leading '?' first Dictionary <string, string> response = EncodingHelper.ParseKeyValueList(resultData.Substring(1), '&', true, callState); if (response.ContainsKey(OAuthReservedClaim.Code)) { result = new AuthorizationResult(response[OAuthReservedClaim.Code]); } else if (response.ContainsKey(OAuthReservedClaim.Error)) { result = new AuthorizationResult(response[OAuthReservedClaim.Error], response.ContainsKey(OAuthReservedClaim.ErrorDescription) ? response[OAuthReservedClaim.ErrorDescription] : null); } else { result = new AuthorizationResult(AdalError.AuthenticationFailed, AdalErrorMessage.AuthorizationServerInvalidResponse); } } return(result); }
/// <summary> /// Creates authentication parameters from the WWW-Authenticate header in response received from resource. This method expects the header to contain authentication parameters. /// </summary> /// <param name="authenticateHeader">Content of header WWW-Authenticate header</param> /// <returns>AuthenticationParameters object containing authentication parameters</returns> public static AuthenticationParameters CreateFromResponseAuthenticateHeader(string authenticateHeader) { if (string.IsNullOrWhiteSpace(authenticateHeader)) { throw new ArgumentNullException("authenticateHeader"); } authenticateHeader = authenticateHeader.Trim(); // This also checks for cases like "BearerXXXX authorization_uri=...." and "Bearer" and "Bearer " if (!authenticateHeader.StartsWith(Bearer, StringComparison.OrdinalIgnoreCase) || authenticateHeader.Length < Bearer.Length + 2 || !char.IsWhiteSpace(authenticateHeader[Bearer.Length])) { var ex = new ArgumentException(AdalErrorMessage.InvalidAuthenticateHeaderFormat, "authenticateHeader"); Logger.Error(null, ex); throw ex; } authenticateHeader = authenticateHeader.Substring(Bearer.Length).Trim(); Dictionary <string, string> authenticateHeaderItems = EncodingHelper.ParseKeyValueList(authenticateHeader, ',', false, null); var authParams = new AuthenticationParameters(); string param; authenticateHeaderItems.TryGetValue(AuthorityKey, out param); authParams.Authority = param; authenticateHeaderItems.TryGetValue(ResourceKey, out param); authParams.Resource = param; return(authParams); }
private string CreateDeviceCodeRequestUriString() { var deviceCodeRequestParameters = new DictionaryRequestParameters(this.resource, this.clientKey); if (this.callState != null && this.callState.CorrelationId != Guid.Empty) { deviceCodeRequestParameters[OAuthParameter.CorrelationId] = this.callState.CorrelationId.ToString(); } if (PlatformPlugin.HttpClientFactory.AddAdditionalHeaders) { IDictionary <string, string> adalIdParameters = AdalIdHelper.GetAdalIdParameters(); foreach (KeyValuePair <string, string> kvp in adalIdParameters) { deviceCodeRequestParameters[kvp.Key] = kvp.Value; } } if (!string.IsNullOrWhiteSpace(extraQueryParameters)) { // Checks for extraQueryParameters duplicating standard parameters Dictionary <string, string> kvps = EncodingHelper.ParseKeyValueList(extraQueryParameters, '&', false, this.callState); foreach (KeyValuePair <string, string> kvp in kvps) { if (deviceCodeRequestParameters.ContainsKey(kvp.Key)) { throw new AdalException(AdalError.DuplicateQueryParameter, string.Format(CultureInfo.CurrentCulture, AdalErrorMessage.DuplicateQueryParameterTemplate, kvp.Key)); } } deviceCodeRequestParameters.ExtraQueryParameter = extraQueryParameters; } return(new Uri(new Uri(this.authenticator.DeviceCodeUri), "?" + deviceCodeRequestParameters).AbsoluteUri); }
protected override void UpdateBrokerParameters(IDictionary <string, string> parameters) { Uri uri = new Uri(this.authorizationResult.Code); string query = EncodingHelper.UrlDecode(uri.Query); Dictionary <string, string> kvps = EncodingHelper.ParseKeyValueList(query, '&', false, this.CallState); parameters["username"] = kvps["username"]; }
private RequestParameters CreateAuthorizationRequest(string loginHint, bool includeFormsAuthParam) { RequestParameters authorizationRequestParameters = new RequestParameters(this.Resource, this.ClientKey); authorizationRequestParameters[OAuthParameter.ResponseType] = OAuthResponseType.Code; authorizationRequestParameters[OAuthParameter.RedirectUri] = this.redirectUriRequestParameter; if (!string.IsNullOrWhiteSpace(loginHint)) { authorizationRequestParameters[OAuthParameter.LoginHint] = loginHint; } if (this.CallState != null && this.CallState.CorrelationId != Guid.Empty) { authorizationRequestParameters[OAuthParameter.CorrelationId] = this.CallState.CorrelationId.ToString(); } // ADFS currently ignores the parameter for now. if (promptBehavior == PromptBehavior.Always) { authorizationRequestParameters[OAuthParameter.Prompt] = PromptValue.Login; } else if (promptBehavior == PromptBehavior.RefreshSession) { authorizationRequestParameters[OAuthParameter.Prompt] = PromptValue.RefreshSession; } else if (promptBehavior == PromptBehavior.Never) { authorizationRequestParameters[OAuthParameter.Prompt] = PromptValue.AttemptNone; } if (includeFormsAuthParam) { authorizationRequestParameters[OAuthParameter.FormsAuth] = OAuthValue.FormsAuth; } AdalIdHelper.AddAsQueryParameters(authorizationRequestParameters); if (!string.IsNullOrWhiteSpace(extraQueryParameters)) { // Checks for extraQueryParameters duplicating standard parameters Dictionary <string, string> kvps = EncodingHelper.ParseKeyValueList(extraQueryParameters, '&', false, this.CallState); foreach (KeyValuePair <string, string> kvp in kvps) { if (authorizationRequestParameters.ContainsKey(kvp.Key)) { var ex = new AdalException(AdalError.DuplicateQueryParameter, string.Format(AdalErrorMessage.DuplicateQueryParameterTemplate, kvp.Key)); Logger.LogException(this.CallState, ex); throw ex; } } authorizationRequestParameters.ExtraQueryParameter = extraQueryParameters; } return(authorizationRequestParameters); }
public override bool ShouldOverrideUrlLoading(WebView view, string url) { Uri uri = new Uri(url); if (url.StartsWith(BrokerConstants.BrowserExtPrefix)) { PlatformPlugin.Logger.Verbose(null, "It is browser launch request"); OpenLinkInBrowser(url, ((Activity)view.Context)); view.StopLoading(); ((Activity)view.Context).Finish(); return(true); } if (url.StartsWith(BrokerConstants.BrowserExtInstallPrefix)) { PlatformPlugin.Logger.Verbose(null, "It is an azure authenticator install request"); view.StopLoading(); this.Finish(view, url); return(true); } if (url.StartsWith(BrokerConstants.ClientTlsRedirect, StringComparison.CurrentCultureIgnoreCase)) { string query = uri.Query; if (query.StartsWith("?")) { query = query.Substring(1); } Dictionary <string, string> keyPair = EncodingHelper.ParseKeyValueList(query, '&', true, false, null); string responseHeader = PlatformPlugin.DeviceAuthHelper.CreateDeviceAuthChallengeResponse(keyPair).Result; Dictionary <string, string> pkeyAuthEmptyResponse = new Dictionary <string, string>(); pkeyAuthEmptyResponse[BrokerConstants.ChallangeResponseHeader] = responseHeader; view.LoadUrl(keyPair["SubmitUrl"], pkeyAuthEmptyResponse); return(true); } if (url.StartsWith(callback, StringComparison.OrdinalIgnoreCase)) { this.Finish(view, url); return(true); } if (!url.Equals("about:blank", StringComparison.CurrentCultureIgnoreCase) && !uri.Scheme.Equals("https", StringComparison.CurrentCultureIgnoreCase)) { UriBuilder errorUri = new UriBuilder(callback); errorUri.Query = string.Format("error={0}&error_description={1}", AdalError.NonHttpsRedirectNotSupported, AdalErrorMessage.NonHttpsRedirectNotSupported); this.Finish(view, errorUri.ToString()); return(true); } return(false); }
private DictionaryRequestParameters CreateAuthorizationRequest(string loginHint) { var authorizationRequestParameters = new DictionaryRequestParameters(this.Resource, this.ClientKey); authorizationRequestParameters[OAuthParameter.ResponseType] = OAuthResponseType.Code; authorizationRequestParameters[OAuthParameter.HasChrome] = "1"; authorizationRequestParameters[OAuthParameter.RedirectUri] = this.redirectUriRequestParameter; if (!string.IsNullOrWhiteSpace(loginHint)) { authorizationRequestParameters[OAuthParameter.LoginHint] = loginHint; } if (!string.IsNullOrWhiteSpace(claims)) { authorizationRequestParameters["claims"] = claims; } if (this.CallState != null && this.CallState.CorrelationId != Guid.Empty) { authorizationRequestParameters[OAuthParameter.CorrelationId] = this.CallState.CorrelationId.ToString(); } if (this.authorizationParameters != null) { PlatformPlugin.PlatformInformation.AddPromptBehaviorQueryParameter(this.authorizationParameters, authorizationRequestParameters); } if (PlatformPlugin.HttpClientFactory.AddAdditionalHeaders) { IDictionary <string, string> adalIdParameters = AdalIdHelper.GetAdalIdParameters(); foreach (KeyValuePair <string, string> kvp in adalIdParameters) { authorizationRequestParameters[kvp.Key] = kvp.Value; } } if (!string.IsNullOrWhiteSpace(extraQueryParameters)) { // Checks for extraQueryParameters duplicating standard parameters Dictionary <string, string> kvps = EncodingHelper.ParseKeyValueList(extraQueryParameters, '&', false, this.CallState); foreach (KeyValuePair <string, string> kvp in kvps) { if (authorizationRequestParameters.ContainsKey(kvp.Key)) { throw new AdalException(AdalError.DuplicateQueryParameter, string.Format(CultureInfo.CurrentCulture, AdalErrorMessage.DuplicateQueryParameterTemplate, kvp.Key)); } } authorizationRequestParameters.ExtraQueryParameter = extraQueryParameters; } return(authorizationRequestParameters); }
public async Task <AuthenticationResultEx> AcquireTokenUsingBroker(IDictionary <string, string> brokerPayload) { if (brokerPayload.ContainsKey("silent_broker_flow")) { throw new AdalSilentTokenAcquisitionException(); } brokerResponse = null; brokerResponseReady = new SemaphoreSlim(0); //call broker string base64EncodedString = Base64UrlEncoder.Encode(BrokerKeyHelper.GetRawBrokerKey()); brokerPayload["broker_key"] = base64EncodedString; brokerPayload["max_protocol_ver"] = "2"; if (brokerPayload.ContainsKey("claims")) { brokerPayload.Add("skip_cache", "YES"); string claims = EncodingHelper.UrlEncode(brokerPayload["claims"]); brokerPayload["claims"] = claims; } if (brokerPayload.ContainsKey("broker_install_url")) { string url = brokerPayload["broker_install_url"]; Uri uri = new Uri(url); string query = uri.Query; if (query.StartsWith("?", StringComparison.OrdinalIgnoreCase)) { query = query.Substring(1); } Dictionary <string, string> keyPair = EncodingHelper.ParseKeyValueList(query, '&', true, false, null); DispatchQueue.MainQueue.DispatchAsync(() => UIApplication.SharedApplication.OpenUrl(new NSUrl(keyPair["app_link"]))); throw new AdalException(AdalErrorIOSEx.BrokerApplicationRequired, AdalErrorMessageIOSEx.BrokerApplicationRequired); } else { NSUrl url = new NSUrl("msauth://broker?" + brokerPayload.ToQueryParameter()); DispatchQueue.MainQueue.DispatchAsync(() => UIApplication.SharedApplication.OpenUrl(url)); } await brokerResponseReady.WaitAsync().ConfigureAwait(false); PlatformParameters = null; return(ProcessBrokerResponse()); }
public void ParseAuthorizeResponse(string webAuthenticationResult) { var resultUri = new Uri(webAuthenticationResult); // NOTE: The Fragment property actually contains the leading '#' character and that must be dropped string resultData = resultUri.Query; if (!string.IsNullOrWhiteSpace(resultData)) { // Remove the leading '?' first Dictionary <string, string> response = EncodingHelper.ParseKeyValueList(resultData.Substring(1), '&', true, null); if (response.ContainsKey(TokenResponseClaim.Code)) { this.Code = response[TokenResponseClaim.Code]; } else if (webAuthenticationResult.StartsWith("msauth://", StringComparison.OrdinalIgnoreCase)) { this.Code = webAuthenticationResult; } else if (response.ContainsKey(TokenResponseClaim.Error)) { this.Error = response[TokenResponseClaim.Error]; this.ErrorDescription = response.ContainsKey(TokenResponseClaim.ErrorDescription) ? response[TokenResponseClaim.ErrorDescription] : null; this.Status = AuthorizationStatus.ProtocolError; } else { this.Error = AdalError.AuthenticationFailed; this.ErrorDescription = AdalErrorMessage.AuthorizationServerInvalidResponse; this.Status = AuthorizationStatus.UnknownError; } if (response.ContainsKey(TokenResponseClaim.CloudInstanceHost)) { this.CloudInstanceHost = response[TokenResponseClaim.CloudInstanceHost]; } } else { this.Error = AdalError.AuthenticationFailed; this.ErrorDescription = AdalErrorMessage.AuthorizationServerInvalidResponse; this.Status = AuthorizationStatus.UnknownError; } }
public void ParseAuthorizeResponse(string webAuthenticationResult) { AuthorizationResult result = null; var resultUri = new Uri(webAuthenticationResult); // NOTE: The Fragment property actually contains the leading '#' character and that must be dropped string resultData = resultUri.Query; if (!string.IsNullOrWhiteSpace(resultData)) { // Remove the leading '?' first Dictionary <string, string> response = EncodingHelper.ParseKeyValueList(resultData.Substring(1), '&', true, null); if (response.ContainsKey(OAuthReservedClaim.Code)) { this.Code = response[OAuthReservedClaim.Code]; } else if (response.ContainsKey(OAuthReservedClaim.Error)) { this.Error = response[OAuthReservedClaim.Error]; this.ErrorDescription = response.ContainsKey(OAuthReservedClaim.ErrorDescription) ? response[OAuthReservedClaim.ErrorDescription] : null; this.Status = AuthorizationStatus.ProtocolError; } else { this.Error = AdalError.AuthenticationFailed; this.ErrorDescription = AdalErrorMessage.AuthorizationServerInvalidResponse; this.Status = AuthorizationStatus.UnknownError; } } else { this.Error = AdalError.AuthenticationFailed; this.ErrorDescription = AdalErrorMessage.AuthorizationServerInvalidResponse; this.Status = AuthorizationStatus.UnknownError; } }
private AuthenticationResultEx ResultFromBrokerResponse(IDictionary <string, string> responseDictionary) { TokenResponse response = new TokenResponse(); if (responseDictionary.ContainsKey("error") || responseDictionary.ContainsKey("error_description")) { response = TokenResponse.CreateFromBrokerResponse(responseDictionary); } else { string expectedHash = responseDictionary["hash"]; string encryptedResponse = responseDictionary["response"]; string decryptedResponse = BrokerKeyHelper.DecryptBrokerResponse(encryptedResponse); string responseActualHash = PlatformPlugin.CryptographyHelper.CreateSha256Hash(decryptedResponse); byte[] rawHash = Convert.FromBase64String(responseActualHash); string hash = BitConverter.ToString(rawHash); if (expectedHash.Equals(hash.Replace("-", ""))) { responseDictionary = EncodingHelper.ParseKeyValueList(decryptedResponse, '&', false, null); response = TokenResponse.CreateFromBrokerResponse(responseDictionary); } else { response = new TokenResponse { Error = AdalError.BrokerReponseHashMismatch, ErrorDescription = AdalErrorMessage.BrokerReponseHashMismatch }; } } var dateTimeOffset = new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)); dateTimeOffset = dateTimeOffset.AddSeconds(response.ExpiresOn); return(response.GetResult(dateTimeOffset, dateTimeOffset)); }
public override void ViewDidLoad() { base.ViewDidLoad(); View.BackgroundColor = UIColor.White; webView = new UIWebView((CGRect)View.Bounds); webView.ShouldStartLoad = (wView, request, navType) => { if (request == null) { return(true); } string requestUrlString = request.Url.ToString(); if (requestUrlString.StartsWith(BrokerConstants.BrowserExtPrefix, StringComparison.OrdinalIgnoreCase)) { DispatchQueue.MainQueue.DispatchAsync(() => CancelAuthentication(null, null)); requestUrlString = requestUrlString.Replace(BrokerConstants.BrowserExtPrefix, "https://"); DispatchQueue.MainQueue.DispatchAsync( () => UIApplication.SharedApplication.OpenUrl(new NSUrl(requestUrlString))); this.DismissViewController(true, null); return(false); } if (requestUrlString.ToLower(CultureInfo.InvariantCulture).StartsWith(callback.ToLower(CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase) || requestUrlString.StartsWith(BrokerConstants.BrowserExtInstallPrefix, StringComparison.OrdinalIgnoreCase)) { callbackMethod(new AuthorizationResult(AuthorizationStatus.Success, request.Url.ToString())); this.DismissViewController(true, null); return(false); } if (requestUrlString.StartsWith(BrokerConstants.DeviceAuthChallengeRedirect, StringComparison.CurrentCultureIgnoreCase)) { Uri uri = new Uri(requestUrlString); string query = uri.Query; if (query.StartsWith("?", StringComparison.OrdinalIgnoreCase)) { query = query.Substring(1); } Dictionary <string, string> keyPair = EncodingHelper.ParseKeyValueList(query, '&', true, false, null); string responseHeader = PlatformPlugin.DeviceAuthHelper.CreateDeviceAuthChallengeResponse(keyPair).Result; NSMutableUrlRequest newRequest = (NSMutableUrlRequest)request.MutableCopy(); newRequest.Url = new NSUrl(keyPair["SubmitUrl"]); newRequest[BrokerConstants.ChallengeResponseHeader] = responseHeader; wView.LoadRequest(newRequest); return(false); } if (!request.Url.AbsoluteString.Equals("about:blank", StringComparison.CurrentCultureIgnoreCase) && !request.Url.Scheme.Equals("https", StringComparison.CurrentCultureIgnoreCase)) { AuthorizationResult result = new AuthorizationResult(AuthorizationStatus.ErrorHttp); result.Error = AdalError.NonHttpsRedirectNotSupported; result.ErrorDescription = AdalErrorMessage.NonHttpsRedirectNotSupported; callbackMethod(result); this.DismissViewController(true, null); return(false); } return(true); }; webView.LoadFinished += delegate { // If the title is too long, iOS automatically truncates it and adds ... this.Title = webView.EvaluateJavascript(@"document.title") ?? "Sign in"; }; View.AddSubview(webView); this.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, this.CancelAuthentication); webView.LoadRequest(new NSUrlRequest(new NSUrl(this.url))); // if this is false, page will be 'zoomed in' to normal size //webView.ScalesPageToFit = true; }
public void AcquireToken(IDictionary <string, string> brokerPayload) { if (brokerPayload.ContainsKey("broker_install_url")) { string url = brokerPayload["broker_install_url"]; Uri uri = new Uri(url); string query = uri.Query; if (query.StartsWith("?")) { query = query.Substring(1); } Dictionary <string, string> keyPair = EncodingHelper.ParseKeyValueList(query, '&', true, false, null); PlatformParameters pp = PlatformParameters as PlatformParameters; pp.CallerActivity.StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse(keyPair["app_link"]))); throw new AdalException(AdalErrorAndroidEx.BrokerApplicationRequired, AdalErrorMessageAndroidEx.BrokerApplicationRequired); } Context mContext = Application.Context; AuthenticationRequest request = new AuthenticationRequest(brokerPayload); PlatformParameters platformParams = PlatformParameters as PlatformParameters; // BROKER flow intercepts here // cache and refresh call happens through the authenticator service if (mBrokerProxy.VerifyUser(request.LoginHint, request.UserId)) { CallState.Logger.Verbose(null, "It switched to broker for context: " + mContext.PackageName); request.BrokerAccountName = request.LoginHint; // Don't send background request, if prompt flag is always or // refresh_session bool hasAccountNameOrUserId = !string.IsNullOrEmpty(request.BrokerAccountName) || !string.IsNullOrEmpty(request.UserId); if (string.IsNullOrEmpty(request.Claims) && hasAccountNameOrUserId) { CallState.Logger.Verbose(null, "User is specified for background token request"); resultEx = mBrokerProxy.GetAuthTokenInBackground(request, platformParams.CallerActivity); } else { CallState.Logger.Verbose(null, "User is not specified for background token request"); } if (resultEx != null && resultEx.Result != null && !string.IsNullOrEmpty(resultEx.Result.AccessToken)) { CallState.Logger.Verbose(null, "Token is returned from background call "); readyForResponse.Release(); return; } // Launch broker activity // if cache and refresh request is not handled. // Initial request to authenticator needs to launch activity to // record calling uid for the account. This happens for Prompt auto // or always behavior. CallState.Logger.Verbose(null, "Token is not returned from backgroud call"); // Only happens with callback since silent call does not show UI CallState.Logger.Verbose(null, "Launch activity for Authenticator"); CallState.Logger.Verbose(null, "Starting Authentication Activity"); if (resultEx == null) { CallState.Logger.Verbose(null, "Initial request to authenticator"); // Log the initial request but not force a prompt } if (brokerPayload.ContainsKey("silent_broker_flow")) { throw new AdalSilentTokenAcquisitionException(); } // onActivityResult will receive the response // Activity needs to launch to record calling app for this // account Intent brokerIntent = mBrokerProxy.GetIntentForBrokerActivity(request, platformParams.CallerActivity); if (brokerIntent != null) { try { CallState.Logger.Verbose(null, "Calling activity pid:" + Android.OS.Process.MyPid() + " tid:" + Android.OS.Process.MyTid() + "uid:" + Android.OS.Process.MyUid()); platformParams.CallerActivity.StartActivityForResult(brokerIntent, 1001); } catch (ActivityNotFoundException e) { CallState.Logger.Error(null, e); } } } else { throw new AdalException(AdalErrorAndroidEx.NoBrokerAccountFound, "Add requested account as a Workplace account via Settings->Accounts or set UseBroker=true."); } }