private void LoadWebMap_GetMapCompleted(object sender, GetMapCompletedEventArgs e) { ESRI.ArcGIS.Client.WebMap.Document doc = (ESRI.ArcGIS.Client.WebMap.Document)sender; if (e.Error == null && e.Map != null) { attemptingReload = false; Map.InitializeFromWebMap(e, l_InitializationFailed); Map.GetMapUnitsAsync(SetScaleBarMapUnit, getMapUnitsFailed); doc.GetItemCompleted -= LoadWebMap_GetItemCompleted; doc.GetItemCompleted += LoadWebMap_GetItemCompleted; doc.GetItemAsync(loadWebMapID, e); } else { loadingWebMap = false; if (attemptingReload) { attemptingReload = false; loadWebMapCallback(e); return; } initializeAgolFromDocument(doc, (agol) => { // Attempt to sign in from isolated storage AGOLUser user = new AGOLUser(agol); user.SignInFromLocalStorage((o, a) => { if (user.Token != null) { // Sign in was successful - try loading web map again doc.Token = user.Token; attemptingReload = true; loadWebMap(loadWebMapID, doc, loadWebMapCallback, e.UserState); } else { // Try signing into ArcGIS Online/Portal if (_signInCommand == null) { // Initialize sign-on command _signInCommand = new SignInToAGSOLCommand(); _signInCommand.SignedIn += (o2, a2) => { doc.Token = _signInCommand.ArcGISOnline.User.Token; attemptingReload = true; loadWebMap(loadWebMapID, doc, loadWebMapCallback, e.UserState); }; _signInCommand.Cancelled += (o2, a2) => { if (loadWebMapCallback != null) loadWebMapCallback(e); }; } _signInCommand.ArcGISOnline = agol; _signInCommand.Execute(null); } }); }); } }
private IdentityManager.Credential cachedCredential; // Credential that was just retrieved from sign-in // Raised when an authentication challenge occurs in the application private async void OnChallenge(string url, Action<IdentityManager.Credential, Exception> callback, IdentityManager.GenerateTokenOptions options = null) { if (signedOut) // Sign-out occurred within the last two seconds. Do not prompt for login. { callback(null, null); return; } var uri = new Uri(url); var tree = uri.AbsolutePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); if (tree[tree.Length - 2].ToLower() == "services" && tree[tree.Length - 3].ToLower() == "rest") { // Challenge is coming from a secure folder. Do not prompt. callback(null, null); return; } // In some cases, multiple challenges are raised for resources at the same endpoint (e.g. tiles from // hosted tile services in ArcGIS Online). To keep the user from being prompted to login multiple times // in succession, each new credential is cached for a half-second. If another challenge is raised // within a half second, and the domain of the current challenge matches that of the cached credential, // then the cached credential is used. // Initialize timer for clearing cached credential if (credentialCacheTimer == null) { credentialCacheTimer = new ThrottleTimer(2000, () => cachedCredential = null); } // If there is a credential cached, then sign-in has just occurred. Check to see if the saved // should also be used for this challenge if (cachedCredential != null) { try { // check whether the domain of the currently requested URL matches that of the cached credential if ((new Uri(url)).Domain().ToLower() == (new Uri(cachedCredential.Url).Domain().ToLower())) { // Domains match, so use the cached credential callback(cachedCredential, null); return; } } catch { } } // Sometimes challenges are raised after sign-in is cancelled. To avoid prompting the user after // cancellation, this timer will suppress challenges for two seconds. // Initialize timer for resetting sign-in cancellation tracking if (signInCancelledTimer == null) { signInCancelledTimer = new ThrottleTimer(2000, () => { // Two seconds has expired since sign-in was cancelled. Reset tracking variables. signInCancelled = false; signInCancelUrl = null; }); } // Check whether sign-in has been cancelled within two seconds if (signInCancelled && !string.IsNullOrEmpty(signInCancelUrl)) { try { // Check whether the domain of the requested URL matches that for the cancelled sign-in Uri requestUri = new Uri(url); Uri cancelUri = new Uri(signInCancelUrl); if (requestUri.Domain().Equals(cancelUri.Domain(), StringComparison.OrdinalIgnoreCase) && requestUri.AbsolutePath.Equals(cancelUri.AbsolutePath, StringComparison.OrdinalIgnoreCase)) { // Domains match - do not prompt user callback(null, null); return; } } catch { } } var proxyUrl = options != null ? options.ProxyUrl : null; // Sign in suppression checks passed. Try to authenticate using existing credentials // Try existing credentials IdentityManager.Credential cred = await ApplicationHelper.TryExistingCredentials(url, proxyUrl); if (cred != null) { // The existing credentials were sufficient for authentication. // If the request was for a URL in the current ArcGIS Portal, sign into Portal if (await url.IsFederatedWithPortal()) await ApplicationHelper.SignInToPortal(cred); // If there is not already a credential in the app's credentials collection that has the // same URL, add this one to the collection if (!UserManagement.Current.Credentials.Any(c => c.Url != null && c.Url.Equals(cred.Url, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(c.Token))) UserManagement.Current.Credentials.Add(cred); // Pass the credential to the callback callback(cred, null); return; } // Try just getting a credential for the URL without specifying login info. This can work if // the browser has authenticated the user (e.g. using PKI or IWA auth) try { cred = await IdentityManager.Current.GenerateCredentialTaskAsyncEx(url, options); } catch { } // Swallow authorization exception if (cred != null) { callback(cred, null); return; } // Existing credentials were insufficient. Prompt user to sign in. SignInCommand signInCommand = null; if (await url.IsFederatedWithPortal()) // Sign into ArcGIS portal signInCommand = new SignInToAGSOLCommand() { ProxyUrl = proxyUrl }; else // Sign into ArcGIS Server signInCommand = new SignInToServerCommand() { Url = url, ProxyUrl = proxyUrl }; signInCommand.SignedIn += (o, e) => { // Temporarily store the credential and start the timer. This allows this credential // to be re-used if there is another challenge with the same domain within a couple // seconds of sign-in. cachedCredential = e.Credential; credentialCacheTimer.Invoke(); // Pass the retrieved credential to the callback callback(e.Credential, null); }; signInCommand.Cancelled += (o, e) => { // Set the flags indicating that sign-in was cancelled and start the timer. If another // challenge for the same resouce is raised within the next couple seconds, it is assumed // that the user should not be prompted because cancellation of sign-in has just occurred. signInCancelled = true; signInCancelUrl = url; signInCancelledTimer.Invoke(); // Pass the retrieved credential to the callback callback(null, null); }; // Promt user to sign-in signInCommand.Execute(null); }