/// <summary> /// Checks whether the string represents a URL for a resource within the application environment's /// current ArcGIS Online or Portal instance /// </summary> public async static Task <bool> IsFederatedWithPortal(this string url, string proxyUrl = null) { string portalUrl = null; if (MapApplication.Current != null && MapApplication.Current.Portal != null) { portalUrl = MapApplication.Current.Portal.Url; } bool isFederatedWithPortal = url.ToLower().Contains(portalUrl.ToLower()); if (!isFederatedWithPortal) { try { // Check the requested URL's owning system URL to see if it matches that of the current portal var serverInfo = await ArcGISServerDataSource.GetServerInfo(url, proxyUrl); if (serverInfo != null) { if (!string.IsNullOrEmpty(serverInfo.OwningSystemUrl)) { if (!string.IsNullOrEmpty(portalUrl)) { string owningUrl = serverInfo.OwningSystemUrl; // Convert to lower case, remove http/https and "/sharing" from URLs portalUrl = portalUrl.ToLower().TrimEnd('/').Replace("http://", "").Replace("https://", "").Replace("/sharing", ""); owningUrl = owningUrl.ToLower().TrimEnd('/').Replace("http://", "").Replace("https://", "").Replace("/sharing", ""); isFederatedWithPortal = portalUrl == owningUrl; } } } } catch { } } return(isFederatedWithPortal); }
/// <summary> /// Attempts to authenticate with the credentials and against the server specified by the command /// </summary> protected async override void onSignIn(object parameter) { if (viewModel == null) { return; } // Set state to busy viewModel.SigningIn = true; try { string credentialUrl = Url; if (viewModel.Url != null) { // Get the token URL for the ArcGIS Server credentialUrl = await ArcGISServerDataSource.GetServicesDirectoryURL(viewModel.Url, null); if (credentialUrl == null) { onSignInFailed(new Exception(Strings.InvalidUrlUserPassword)); } } if (IdentityManager.Current != null) { var options = new IdentityManager.GenerateTokenOptions() { ProxyUrl = ProxyUrl }; // Authenticate against the server to retrieve user token IdentityManager.Credential cred = await IdentityManager.Current.GenerateCredentialTaskAsync( credentialUrl, viewModel.Username, viewModel.Password, options); if (cred != null) { // Save the credential info so it can be used to try to access other services 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); } try { // Complete sign-in viewModel.SigningIn = false; viewModel.SignInError = null; closeWindow(); OnSignedIn(cred); } catch (Exception ex) { onSignInFailed(ex); } } else { onSignInFailed(new Exception(agolStrings.Get("SignInFailed"))); } } } catch (Exception ex) { onSignInFailed(ex); } }
/// <summary> /// Attempt to use application environment credentials to authenticate against the specified URL /// </summary> public static async Task <IdentityManager.Credential> TryExistingCredentials(string requestUrl, string proxyUrl = null) { if (string.IsNullOrEmpty(requestUrl) || UserManagement.Current.Credentials.Count == 0) { return(null); } bool isPortalUrl = await requestUrl.IsFederatedWithPortal(); string credentialUrl = requestUrl; // Get the token auth endpoint if the requested URL is not an ArcGIS Online/Portal URL if (!isPortalUrl) { credentialUrl = await ArcGISServerDataSource.GetServicesDirectoryURL(requestUrl, proxyUrl); } // Check whether there's already a credential for the url foreach (IdentityManager.Credential cred in UserManagement.Current.Credentials) { IdentityManager.Credential newCred = null; if (isPortalUrl && !string.IsNullOrEmpty(cred.Url) && await cred.Url.IsFederatedWithPortal()) { try { // If a portal credential already exists, try simply getting a new credential for the same portal newCred = await IdentityManager.Current.GetCredentialTaskAsync(requestUrl, false); } catch { } } else if (!string.IsNullOrEmpty(cred.Url) && cred.Url.Equals(credentialUrl, StringComparison.OrdinalIgnoreCase)) { newCred = cred; // If a credential that matches the requested URL exists, try it } else if (!string.IsNullOrEmpty(cred.UserName) && !string.IsNullOrEmpty(cred.Password)) { try { var options = new IdentityManager.GenerateTokenOptions() { ProxyUrl = proxyUrl }; // Try authenticating with the user name and password newCred = await IdentityManager.Current.GenerateCredentialTaskAsync(credentialUrl, cred.UserName, cred.Password, options); } catch { } // Intentionally trying credentials that may not work, so swallow exceptions } if (newCred != null) { // Try the original request URL with the new credential's token string testUrl = requestUrl; // Construct the URL with the token if (testUrl.Contains("?")) { testUrl += string.Format("&token={0}&f=json", newCred.Token); } else { testUrl += string.Format("?token={0}&f=json", newCred.Token); } var wc = new ArcGISWebClient() { ProxyUrl = proxyUrl }; string result = null; try { // Issue the request result = await wc.DownloadStringTaskAsync(new Uri(testUrl)); } catch { continue; } if (result != null) { try { // Check whether the response contains a JSON error JsonObject o = (JsonObject)JsonObject.Parse(result); if (o.ContainsKey("error")) { o = (JsonObject)o["error"]; // Check the error code if (o.ContainsKey("code")) { int statusCode = o["code"]; // Server should return 401 Unauthorized, 403 Forbidden, 498 Invalid Token, or 499 // Token Required if the token was insufficient authorization. Other errors should // mean that the resource was accessible with the token, but was just not used // properly. if (statusCode == 401 || statusCode == 403 || statusCode == 498 || statusCode == 499) { continue; } } } } catch { // could not parse response, so it's probably HTML or an image. Assume the // credential is valid since these types of responses are generally not returned // by Portal/Server if there is an error. return(newCred); } return(newCred); } } } return(null); }