public static void ClassSetup(TestContext context)
 {
     SFApplicationHelper.RegisterServices();
     SDKServiceLocator.RegisterService <ILoggingService, Hybrid.Logging.Logger>();
     Store = SmartStore.GetGlobalSmartStore();
     SetupData();
 }
예제 #2
0
 public static void RegisterServices()
 {
     SDKServiceLocator.RegisterService <ISFApplicationHelper, SFApplicationHelper>();
     SDKServiceLocator.RegisterService <IAuthHelper, AuthHelper>();
     SDKServiceLocator.RegisterService <IEncryptionService, Encryptor>();
     SDKServiceLocator.RegisterService <IApplicationInformationService, ApplicationService>();
 }
 public static void TestSetup(TestContext context)
 {
     SFApplicationHelper.RegisterServices();
     SDKServiceLocator.RegisterService <ILoggingService, Hybrid.Logging.Logger>();
     Store = SmartStore.GetGlobalSmartStore();
     Store.ResetDatabase();
     Store.RegisterSoup(TEST_SOUP, new[] { new IndexSpec("key", SmartStoreType.SmartString) });
 }
예제 #4
0
        protected override Task InitializeConfig()
        {
            SDKServiceLocator.RegisterService <IEncryptionService, Encryptor>();
            Encryptor.init(new EncryptionSettings(new HmacSHA256KeyGenerator(HashAlgorithmNames.Sha256)));
            var config = SDKManager.InitializeConfigAsync <Config>().Result;

            return(config.SaveConfigAsync());
        }
        private async Task CheckIfLoginNeededAsync()
        {
            Account account = AccountManager.GetAccount();

            if (account == null)
            {
                SDKServiceLocator.Get <ILoggingService>().Log("Account object is null, calling StartLoginFlowAsync",
                                                              LoggingLevel.Verbose);
                await SDKServiceLocator.Get <IAuthHelper>().StartLoginFlowAsync();
            }
        }
        /// <summary>
        ///     This method will launch the pincode screen if the policy requires it.
        ///     If determined that no pincode screen is required, the flag requiring the pincode will be cleared.
        /// </summary>
        public static async void LaunchPincodeScreen()
        {
            var frame = Window.Current.Content as Frame;

            if (frame != null && typeof(PincodeDialog) != frame.SourcePageType)
            {
                await frame.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    SDKServiceLocator.Get <ILoggingService>().Log(" Launching Pincode Screen", LoggingLevel.Information);
                    Account account = AccountManager.GetAccount();
                    if (account != null)
                    {
                        PincodeOptions options = null;
                        bool required          = AuthStorageHelper.IsPincodeRequired();
                        if (account.Policy != null && !IsPincodeSet())
                        {
                            options = new PincodeOptions(PincodeOptions.PincodeScreen.Create, account, "");
                        }
                        else if (required)
                        {
                            MobilePolicy policy = AuthStorageHelper.GetMobilePolicy();
                            if (account.Policy != null)
                            {
                                if (policy.ScreenLockTimeout < account.Policy.ScreenLockTimeout)
                                {
                                    policy.ScreenLockTimeout = account.Policy.ScreenLockTimeout;
                                    AuthStorageHelper.GetAuthStorageHelper().PersistPincode(policy);
                                }
                                if (policy.PinLength < account.Policy.PinLength)
                                {
                                    options = new PincodeOptions(PincodeOptions.PincodeScreen.Create, account, "");
                                }
                                else
                                {
                                    options = new PincodeOptions(PincodeOptions.PincodeScreen.Locked, account, "");
                                }
                            }
                            else
                            {
                                options = new PincodeOptions(PincodeOptions.PincodeScreen.Locked, account, "");
                            }
                        }
                        if (options != null)
                        {
                            // As per MSDN documentation (https://msdn.microsoft.com/en-us/library/windows/apps/hh702394.aspx)
                            // the second param of Frame.Navigate must be a basic type otherwise Suspension manager will crash
                            // when serializing frame's state. So we serialize custom object using Json and pass that as the
                            // second param to avoid this crash.
                            frame.Navigate(typeof(PincodeDialog), PincodeOptions.ToJson(options));
                        }
                    }
                });
            }
        }
예제 #7
0
        /// <summary>
        ///     Async method for refreshing the token, persisting the data in the encrypted settings and returning the updated
        ///     account
        ///     with the new access token.
        /// </summary>
        /// <param name="account"></param>
        /// <returns>Boolean based on if the refresh auth token succeeded or not</returns>
        public static async Task <Account> RefreshAuthTokenAsync(Account account)
        {
            LoggingService.Log("Atempting to refresh auth token", LoggingLevel.Verbose);

            if (account == null)
            {
                return(null);
            }

            try
            {
                var loginOptions = account.GetLoginOptions();

                // args
                var argsStr = string.Format(OauthRefreshQueryString, loginOptions.ClientId, account.RefreshToken);

                // Refresh url
                var refreshUrl = loginOptions.LoginUrl + OauthRefreshPath;

                // Post
                var call = HttpCall.CreatePost(refreshUrl, argsStr);

                var response = await call.ExecuteAndDeserializeAsync <AuthResponse>();

                account.AccessToken = response.AccessToken;
                account.IdentityUrl = response.IdentityUrl;

                await SDKServiceLocator.Get <IAuthHelper>().PersistCurrentAccountAsync(account);
            }
            catch (DeviceOfflineException ex)
            {
                LoggingService.Log("Failed to refresh the token because we were offline", LoggingLevel.Warning);
                LoggingService.Log(ex, LoggingLevel.Warning);
                throw;
            }
            catch (WebException ex)
            {
                LoggingService.Log("Exception occurred when refreshing token:", LoggingLevel.Critical);
                LoggingService.Log(ex, LoggingLevel.Critical);
                Debug.WriteLine("Error refreshing token");
                throw new OAuthException(ex.Message, ex);
            }
            catch (Exception ex)
            {
                LoggingService.Log("Exception occurred when refreshing token:", LoggingLevel.Critical);
                LoggingService.Log(ex, LoggingLevel.Critical);
                Debug.WriteLine("Error refreshing token");
                throw new OAuthException(ex.Message, ex);
            }

            return(account);
        }
        private static void RegisterServices()
        {
            // setup logger
            SDKServiceLocator.RegisterService <ILoggingService, Logger>();

            // log registering services
            LoggingService.Log("Registering Services", LoggingLevel.Information);

            // register remaining services
            SDKServiceLocator.RegisterService <IAuthHelper, AuthHelper>();
            SDKServiceLocator.RegisterService <IEncryptionService, Encryptor>();
            SDKServiceLocator.RegisterService <IApplicationInformationService, ApplicationService>();
        }
예제 #9
0
        private async void RefreshToken(object sender, object e)
        {
            try
            {
                //Assign this to a var as ref requires it.
                var account = AccountManager.GetAccount();
                await OAuth2.RefreshAuthTokenAsync(account);

                SDKServiceLocator.Get <IAuthHelper>().RefreshCookies();
            }
            catch (OAuthException ex)
            {
                LoggingService.Log(ex, LoggingLevel.Critical, "Error occurred when refreshing token");
            }
        }
예제 #10
0
        /// <summary>
        /// This should be called when login is complete. A new account is created
        /// in the AccountManager and the pincode screen is shown if needeed
        /// </summary>
        /// <param name="loginOptions"></param>
        /// <param name="authResponse"></param>
        public async Task OnLoginCompleteAsync(LoginOptions loginOptions, AuthResponse authResponse)
        {
            var frame   = Window.Current.Content as Frame;
            var account = await AccountManager.CreateNewAccount(loginOptions, authResponse);

            if (account.Policy != null && (!PincodeManager.IsPincodeSet() || AuthStorageHelper.IsPincodeRequired()))
            {
                PincodeManager.LaunchPincodeScreen();
            }
            else
            {
                SDKServiceLocator.Get <ILoggingService>().Log($"Navigating to {SDKManager.RootApplicationPage}", LoggingLevel.Information);
                frame?.Navigate(SDKManager.RootApplicationPage);
            }
        }
예제 #11
0
        public void Dispose()
        {
            if (_httpClient == null)
            {
                return;
            }

            try
            {
                _httpClient.Dispose();
            }
            catch (Exception)
            {
                SDKServiceLocator.Get <ILoggingService>().Log("Error occurred while disposing", LoggingLevel.Warning);
            }
        }
예제 #12
0
        /// <summary>
        ///     Returns a RestClient if user is already authenticated or otherwise kicks off a login flow
        /// </summary>
        /// <returns></returns>
        public IRestClient GetRestClient()
        {
            var restClient = PeekRestClient();

            if (restClient == null)
            {
                try
                {
                    AuthHelper.StartLoginFlowAsync();
                }
                catch (InvalidOperationException)
                {
                    SDKServiceLocator.Get <ILoggingService>().Log("Platform doesn't support native login flow", LoggingLevel.Information);
                }
            }
            return(restClient);
        }
예제 #13
0
        protected SalesforceApplication()
        {
            SFApplicationHelper.RegisterServices();
            SDKServiceLocator.RegisterService <ILoggingService, Logger>();
            Suspending += OnSuspending;

            //do upgrade on stored config, account and pincode
            UpgradeConfigAsync().Wait();
            SDKUpgradeManager.GetInstance().UpgradeAsync().Wait();

            InitializeConfig();
            SDKManager.CreateClientManager(false);
            SDKManager.RootApplicationPage = SetRootApplicationPage();
            TokenRefresher = new DispatcherTimer {
                Interval = TimeSpan.FromMinutes(TokenRefreshInterval)
            };
            TokenRefresher.Tick += RefreshToken;
            AppHelper.Initialize();
        }
        public static async Task TestSetup(TestContext context)
        {
            SFApplicationHelper.RegisterServices();
            SDKServiceLocator.RegisterService <ILoggingService, Hybrid.Logging.Logger>();
            var settings = new EncryptionSettings(new HmacSHA256KeyGenerator(HashAlgorithmNames.Sha256));

            Encryptor.init(settings);
            var options = new LoginOptions(TestCredentials.LoginUrl, TestCredentials.ClientId, TestCallbackUrl, "mobile",
                                           TestScopes);
            var response = new AuthResponse
            {
                RefreshToken = TestCredentials.RefreshToken,
                AccessToken  = TestAuthToken,
                InstanceUrl  = TestCredentials.InstanceUrl,
                IdentityUrl  = TestCredentials.IdentityUrl,
                Scopes       = TestScopes,
            };
            Account account = await AccountManager.CreateNewAccount(options, response);

            account.UserId   = TestCredentials.UserId;
            account.UserName = TestCredentials.Username;
            await OAuth2.RefreshAuthTokenAsync(account);

            _smartStore = SmartStore.GetSmartStore();
            _smartStore.ResetDatabase();
            _syncManager = SyncManager.GetInstance();
            _restClient  = new RestClient(account.InstanceUrl, account.AccessToken,
                                          async(cancellationToken) =>
            {
                account = AccountManager.GetAccount();
                account = await OAuth2.RefreshAuthTokenAsync(account);
                return(account.AccessToken);
            }
                                          );
            CreateAccountsSoup();
            _idToNames = await CreateTestAccountsOnServer(CountTestAccounts);
        }
        private async void LockedClick(object sender, KeyRoutedEventArgs e)
        {
            if (e.Key != VirtualKey.Accept && e.Key != VirtualKey.Enter)
            {
                return;
            }
            e.Handled = true;
            Account account = AccountManager.GetAccount();

            if (account == null)
            {
                await SDKServiceLocator.Get <IAuthHelper>().StartLoginFlowAsync();
            }
            else if (AuthStorageHelper.ValidatePincode(Passcode.Password))
            {
                PincodeManager.Unlock();
                if (Frame.CanGoBack)
                {
                    Frame.GoBack();
                }
                else
                {
                    Frame.Navigate(SDKManager.RootApplicationPage);
                }
            }
            else
            {
                if (RetryCounter <= 1)
                {
                    await SDKManager.GlobalClientManager.Logout();
                }
                RetryCounter--;
                ContentFooter.Text       = String.Format(LocalizedStrings.GetString("passcode_incorrect"), RetryCounter);
                ContentFooter.Visibility = Visibility.Visible;
            }
        }
예제 #16
0
        /// <summary>
        ///     Executes the HttpCall. This will generate the headers, create the request and populate the HttpCall properties with
        ///     relevant data.
        ///     The HttpCall may only be called once; further attempts to execute the same call will throw an
        ///     InvalidOperationException.
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns>HttpCall with populated data</returns>
        public async Task <HttpCall> ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            if (Executed)
            {
                throw new InvalidOperationException("A HttpCall can only be executed once");
            }
            var req = new HttpRequestMessage(_method, new Uri(_url));

            // Setting header
            if (_headers != null)
            {
                if (_headers.Authorization != null)
                {
                    req.Headers.Authorization = _headers.Authorization;
                }
                foreach (var item in _headers.Headers)
                {
                    req.Headers.Add(item.Key, item.Value);
                }
            }
            // if the user agent has not yet been set, set it; we want to make sure this only really happens once since it requires an action that goes to the core thread.
            if (String.IsNullOrWhiteSpace(UserAgentHeader))
            {
                UserAgentHeader = await SDKServiceLocator.Get <IApplicationInformationService>().GenerateUserAgentHeaderAsync(false, String.Empty);
            }
            req.Headers.UserAgent.TryParseAdd(UserAgentHeader);
            if (!String.IsNullOrWhiteSpace(_requestBody))
            {
                switch (_contentType)
                {
                case ContentTypeValues.FormUrlEncoded:
                    req.Content = new FormUrlEncodedContent(_requestBody.ParseQueryString());
                    break;

                case ContentTypeValues.Gzip:
                    req.Content = await CompressAsync(new StringContent(_requestBody));

                    break;

                default:
                    req.Content = new StringContent(_requestBody);
                    req.Content.Headers.ContentType = new MediaTypeHeaderValue(_contentType.MimeType());
                    break;
                }
            }
            HttpResponseMessage message;

            try
            {
                message = await _httpClient.SendAsync(req, cancellationToken);
            }
            catch (HttpRequestException ex)
            {
                _httpCallErrorException =
                    new DeviceOfflineException("Request failed to send, most likely because we were offline", ex);
                return(this);
            }
            catch (WebException ex)
            {
                _httpCallErrorException =
                    new DeviceOfflineException("Request failed to send, most likely because we were offline", ex);
                return(this);
            }

            // If the result is null then it might be because the http call was canceled.
            // HttpClient has a bug where it doesn't throw when a cancellation is requested,
            // it just returns null immediately (however the cancellation token does get set
            // to canceled). More context on that bug at:
            // http://stackoverflow.com/questions/29319086/cancelling-an-httpclient-request-why-is-taskcanceledexception-cancellationtoke
            // The following if block will throw an OperationCanceledException (which is the
            // desired behavior for when a Task gets canceled) if a cancel was requested
            // and works around the HttpClient bug.
            if (message == null)
            {
                cancellationToken.ThrowIfCancellationRequested();
            }

            await HandleMessageResponseAsync(message);

            return(this);
        }
예제 #17
0
 public static void SetupClass(TestContext context)
 {
     SFApplicationHelper.RegisterServices();
     SDKServiceLocator.RegisterService <ILoggingService, Hybrid.Logging.Logger>();
 }
        private async void DoAuthFlow(LoginOptions loginOptions)
        {
            loginOptions.DisplayType = LoginOptions.DefaultStoreDisplayType;
            var loginUri    = new Uri(OAuth2.ComputeAuthorizationUrl(loginOptions));
            var callbackUri = new Uri(loginOptions.CallbackUrl);
            await SDKServiceLocator.Get <IAuthHelper>().ClearCookiesAsync(loginOptions);

            WebAuthenticationResult webAuthenticationResult = null;
            var hasWebAuthErrors = false;

            try
            {
                LoggingService.Log("Launching web authentication broker", LoggingLevel.Verbose);

                webAuthenticationResult =
                    await
                    WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, loginUri, callbackUri);
            }
            // If a bad URI was passed in the user is shown an error message by the WebAuthenticationBroken, when user
            // taps back arrow we are then thrown a FileNotFoundException, but since user already saw error message we
            // should just swallow that exception
            catch (FileNotFoundException)
            {
                SetupAccountPage();
                return;
            }
            catch (Exception ex)
            {
                LoggingService.Log("Exception occurred during login flow", LoggingLevel.Critical);
                LoggingService.Log(ex, LoggingLevel.Critical);

                hasWebAuthErrors = true;
            }

            if (hasWebAuthErrors)
            {
                await DisplayErrorDialogAsync(LocalizedStrings.GetString("generic_error"));

                SetupAccountPage();
                return;
            }

            if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
            {
                var responseUri = new Uri(webAuthenticationResult.ResponseData);
                if (!String.IsNullOrWhiteSpace(responseUri.Query) &&
                    responseUri.Query.IndexOf("error", StringComparison.CurrentCultureIgnoreCase) >= 0)
                {
                    await DisplayErrorDialogAsync(LocalizedStrings.GetString("generic_authentication_error"));

                    SetupAccountPage();
                }
                else
                {
                    AuthResponse authResponse = OAuth2.ParseFragment(responseUri.Fragment.Substring(1));

                    await SDKServiceLocator.Get <IAuthHelper>().OnLoginCompleteAsync(loginOptions, authResponse);
                }
            }
            else if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.UserCancel)
            {
                SetupAccountPage();
            }
            else
            {
                await DisplayErrorDialogAsync(LocalizedStrings.GetString("generic_error"));

                SetupAccountPage();
            }
        }
 private HybridAccountManager()
 {
     RegisterServices();
     SDKServiceLocator.Get <IApplicationInformationService>().GenerateUserAgentHeaderAsync(true, String.Empty);
 }
예제 #20
0
 public void SetupTest()
 {
     SFApplicationHelper.RegisterServices();
     SDKServiceLocator.RegisterService <ILoggingService, Hybrid.Logging.Logger>();
 }
예제 #21
0
        /// <summary>
        ///     Executes the HttpCall. This will generate the headers, create the request and populate the HttpCall properties with
        ///     relevant data.
        ///     The HttpCall may only be called once; further attempts to execute the same call will throw an
        ///     InvalidOperationException.
        /// </summary>
        /// <returns>HttpCall with populated data</returns>
        public async Task <HttpCall> ExecuteAsync()
        {
            if (Executed)
            {
                throw new InvalidOperationException("A HttpCall can only be executed once");
            }
            var req = new HttpRequestMessage(_method, new Uri(_url));

            // Setting header
            if (_headers != null)
            {
                if (_headers.Authorization != null)
                {
                    req.Headers.Authorization = _headers.Authorization;
                }
                foreach (var item in _headers.Headers)
                {
                    req.Headers.Add(item.Key, item.Value);
                }
            }
            // if the user agent has not yet been set, set it; we want to make sure this only really happens once since it requires an action that goes to the core thread.
            if (String.IsNullOrWhiteSpace(UserAgentHeader))
            {
                UserAgentHeader = await SDKServiceLocator.Get <IApplicationInformationService>().GenerateUserAgentHeaderAsync(false, String.Empty);
            }
            req.Headers.UserAgent.TryParseAdd(UserAgentHeader);
            if (!String.IsNullOrWhiteSpace(_requestBody))
            {
                switch (_contentType)
                {
                case ContentTypeValues.FormUrlEncoded:
                    req.Content = new FormUrlEncodedContent(_requestBody.ParseQueryString());
                    break;

                default:
                    req.Content = new StringContent(_requestBody);
                    req.Content.Headers.ContentType = new MediaTypeHeaderValue(_contentType.MimeType());
                    break;
                }
            }
            HttpResponseMessage message;

            try
            {
                message = await _httpClient.SendAsync(req);
            }
            catch (HttpRequestException ex)
            {
                _httpCallErrorException =
                    new DeviceOfflineException("Request failed to send, most likely because we were offline", ex);
                return(this);
            }
            catch (WebException ex)
            {
                _httpCallErrorException =
                    new DeviceOfflineException("Request failed to send, most likely because we were offline", ex);
                return(this);
            }

            await HandleMessageResponseAsync(message);

            return(this);
        }