public static IPromise<IReadOnlyResult> ApplyAsync(this IAsyncConnection conn, Command query, bool async, bool noItemsIsError, params object[] parameters) { var result = new Promise<IReadOnlyResult>(); if (parameters != null) { for (var i = 0; i < parameters.Length; i++) { query.WithParam(i.ToString(), parameters[i]); } } result.CancelTarget( conn.Process(query, async) .Progress((p, m) => result.Notify(p, m)) .Done(r => { try { var res = conn.AmlContext.FromXml(r, query.Aml, conn); var ex = res.Exception; if (ex != null && (noItemsIsError || !(ex is NoItemsFoundException))) { result.Reject(ex); } else { result.Resolve(res); } } catch (Exception ex) { result.Reject(ex); } }).Fail(ex => { result.Reject(ex); })); return result; }
/// <summary> /// Get a single item from the database using the specified query asynchronously. If the result is not a single item, an exception will be thrown /// </summary> /// <param name="conn">Server connection</param> /// <param name="action">SOAP action</param> /// <param name="request">Query/command which should return a single item</param> /// <param name="async">Whether to perform this request asynchronously</param> /// <returns>A promise to return a single readonly item</returns> public static IPromise<IReadOnlyItem> ItemByQuery(this IConnection conn, Command request, bool async) { var result = new Promise<IReadOnlyItem>(); result.CancelTarget(conn.ProcessAsync(request, async) .Progress((p, m) => result.Notify(p, m)) .Done(r => { if (string.IsNullOrEmpty(conn.UserId)) { result.Reject(new LoggedOutException()); } else { var res = conn.AmlContext.FromXml(r, request.Aml, conn); var ex = res.Exception; if (ex == null) { try { result.Resolve(res.AssertItem()); } catch (Exception exc) { result.Reject(exc); } } else { result.Reject(ex); } } }).Fail(ex => result.Reject(ex))); return result; }
/// <summary> /// Log in to the database asynchronosuly /// </summary> /// <param name="credentials">Credentials used for authenticating to the instance</param> /// <param name="async">Whether to perform this action asynchronously</param> /// <returns> /// A promise to return the user ID as a string /// </returns> /// <exception cref="NotSupportedException">This connection implementation does not support the specified credential type</exception> public IPromise <string> Login(ICredentials credentials, bool async) { var authProcess = HashCreds(credentials, async); _lastCredentials = credentials; var unHashedPassword = default(SecureToken); var result = new Promise <string>(); result.CancelTarget( authProcess.Continue(h => { unHashedPassword = h.UnhashedPassword; _httpDatabase = h.Cred.Database; _httpPassword = h.Cred.PasswordHash; _httpUsername = h.Cred.Username; return(Process(new Command("<Item/>").WithAction(CommandAction.ValidateUser), async)); }) .Progress(result.Notify) .Done(r => { string xml; using (var reader = new StreamReader(r)) { xml = reader.ReadToEnd(); } var root = XElement.Parse(xml); var data = root.DescendantsAndSelf("Result").FirstOrDefault(); var afNs = (XNamespace)"http://www.aras.com/InnovatorFault"; var authNode = root.DescendantsAndSelf(afNs + "supported_authentication_schema").FirstOrDefault(); if (authNode != null && unHashedPassword != null && authNode.Element(afNs + "schema")?.Attribute("mode")?.Value == "SHA256" && _httpPassword?.Length == 32) { _hashFunc = ElementFactory.Local.CalcSha256; // Switch from MD5 hashing to SHA256 Login(new ExplicitHashCredentials(_httpDatabase, _httpUsername, _hashFunc(unHashedPassword)), true) .Done(result.Resolve) .Fail(result.Reject); } else if (data == null) { var res = ElementFactory.Local.FromXml(xml); var ex = res.Exception ?? ElementFactory.Local.ServerException("Failed to login"); ex.SetDetails(_httpDatabase, "<Item/>"); _httpDatabase = null; _httpUsername = null; _httpPassword = null; result.Reject(ex); } else { foreach (var elem in data.Elements()) { switch (elem.Name.LocalName) { case "id": _userId = elem.Value; break; case "i18nsessioncontext": _context.DefaultLanguageCode = elem.Element("default_language_code").Value; _context.DefaultLanguageSuffix = elem.Element("default_language_suffix").Value; _context.LanguageCode = elem.Element("language_code").Value; _context.LanguageSuffix = elem.Element("language_suffix").Value; _context.Locale = elem.Element("locale").Value; _context.TimeZone = elem.Element("time_zone").Value; break; case "ServerInfo": foreach (var info in elem.Elements()) { if (info.Name.LocalName == "Version") { _arasVersion = new Version(info.Value); } if (!string.IsNullOrEmpty(elem.Value)) { _serverInfo.Add(new KeyValuePair <string, string>("ServerInfo/" + elem.Name.LocalName, elem.Value)); } } break; default: if (!string.IsNullOrEmpty(elem.Value)) { _serverInfo.Add(new KeyValuePair <string, string>(elem.Name.LocalName, elem.Value)); } break; } } _vaultConn.InitializeStrategy(); result.Resolve(_userId); } }).Fail(ex => { _httpDatabase = null; _httpUsername = null; _httpPassword = null; result.Reject(ex); })); return(result); }
/// <summary> /// Asynchronously gets an HTTP connection to an innovator instance (or proxy) at the given URL /// </summary> /// <param name="url">URL of the innovator instance (or proxy)</param> /// <param name="preferences">Object containing preferences for the connection</param> /// <returns>A promise to return a connection object</returns> public static IPromise<IRemoteConnection> GetConnection(string url , ConnectionPreferences preferences, bool async) { url = (url ?? "").TrimEnd('/'); if (!url.EndsWith("/server", StringComparison.OrdinalIgnoreCase)) url += "/Server"; var configUrl = url + "/mapping.xml"; var masterService = preferences.HttpService ?? DefaultService.Invoke(); var arasSerice = preferences.HttpService ?? new DefaultHttpService() { Compression = CompressionType.none }; Func<ServerMapping, IRemoteConnection> connFactory = m => { var uri = (m.Url ?? "").TrimEnd('/'); if (!uri.EndsWith("/server", StringComparison.OrdinalIgnoreCase)) url += "/Server"; switch (m.Type) { case ServerType.Proxy: m.Endpoints.Base = new Uri(uri + "/"); var conn = new Connection.ProxyServerConnection(masterService, m.Endpoints); conn.SessionPolicy = preferences.SessionPolicy; if (!string.IsNullOrEmpty(preferences.UserAgent)) conn.DefaultSettings(req => req.UserAgent = preferences.UserAgent); return conn; default: return ArasConn(arasSerice, uri, preferences); } }; var result = new Promise<IRemoteConnection>(); result.CancelTarget(masterService.Execute("GET", configUrl, null, CredentialCache.DefaultCredentials , async, request => { request.UserAgent = preferences.UserAgent; request.SetHeader("Accept", "text/xml"); }).Progress((p, m) => result.Notify(p, m)) .Done(r => { var data = r.AsString(); if (string.IsNullOrEmpty(data)) { result.Resolve(ArasConn(arasSerice, url, preferences)); } else { try { var servers = ServerMapping.FromXml(data).ToArray(); if (servers.Length < 1) { result.Resolve(ArasConn(arasSerice, url, preferences)); } else if (servers.Length == 1) { result.Resolve(connFactory(servers.Single())); } else { foreach (var server in servers) { server.Factory = connFactory; } result.Resolve(new MappedConnection(servers)); } } catch (XmlException) { result.Resolve(ArasConn(arasSerice, url, preferences)); } } }).Fail(ex => { result.Resolve(ArasConn(arasSerice, url, preferences)); })); return result; }
private IPromise<AuthenticationSchemes> CheckAuthentication(Vault vault, bool async) { var result = new Promise<AuthenticationSchemes>(); if (vault.Authentication == AuthenticationSchemes.None && _conn.Version >= 11) { var hReq = (HttpWebRequest)System.Net.WebRequest.Create(vault.Url); hReq.Credentials = null; hReq.UnsafeAuthenticatedConnectionSharing = true; hReq.Method = "HEAD"; var req = new WebRequest(hReq, CompressionType.none); result.CancelTarget( req.Execute(async) .Progress((p, m) => result.Notify(p, m)) .Done(r => { vault.Authentication = AuthenticationSchemes.Anonymous; result.Resolve(vault.Authentication); }).Fail(ex => { var webEx = ex as HttpException; if (webEx != null && webEx.Response.StatusCode == HttpStatusCode.Unauthorized) { vault.Authentication = req.CheckForNotAuthorized(webEx.Response); result.Resolve(vault.Authentication); } else { result.Reject(ex); } })); } else { result.Resolve(AuthenticationSchemes.Anonymous); } return result; }
private IPromise<string> PolicyToken(PolicyTokenType type, string userId , string database, bool async) { var result = new Promise<string>(); result.CancelTarget(PolicyService(type.ToString(), userId, database, async) .Progress((p, m) => result.Notify(p, m)) .Done(r => { result.Resolve(r.AsString()); }) .Fail(ex => { if (ex is NullReferenceException || ex is HttpException) { result.Resolve(string.Empty); } else { result.Reject(ex); } })); return result; }
public IPromise<string> Login(ICredentials credentials, bool async) { var result = new Promise<string>(); _lastCredentials = credentials; var database = string.Empty; var tokenCred = credentials as TokenCredentials; IPromise<IHttpResponse> loginPromise; if (tokenCred != null) { database = tokenCred.Database; loginPromise = PolicyToken(PolicyTokenType.connection, null, null, true) .Continue(p => { return RenewSession(tokenCred.Content, p, true); }); } else { var tokenPromise = (_lastLoginToken == null || _lastLoginToken.Expiration > DateTime.UtcNow.AddSeconds(-5)) ? Query(null, null, null, this.SessionPolicy, null, async) .Convert<IHttpResponse, InitializeSessionToken>((r, p) => { p.Reject(new Exception("Unauthorized error expected")); }, (ex, p) => { var httpEx = ex as HttpException; if (httpEx != null && httpEx.Response.StatusCode == System.Net.HttpStatusCode.Forbidden) { var header = AuthenticationScheme.Parse(httpEx.Response.Headers["WWW-Authenticate"]); var auth = header.FirstOrDefault(a => a.Name == "bearer"); if (auth == null) throw new InvalidOperationException(); var ssoAuth = header.FirstOrDefault(a => a.Name == "winsso"); _lastLoginToken = new InitializeSessionToken(auth.Parameters["token"] , auth.Parameters["nonce"], auth.Parameters["public_key"]); _lastLoginToken.SsoUrl = ssoAuth.Parameters["uri"]; p.Resolve(_lastLoginToken); } else { p.Reject(ex); } }) : Promises.Resolved(_lastLoginToken); loginPromise = Promises.All(tokenPromise , PolicyToken(PolicyTokenType.connection, null, null, async)) .Continue(r => { var winCred = credentials as WindowsCredentials; if (winCred == null) { SecureToken password = null; var username = string.Empty; var explicitCred = credentials as ExplicitCredentials; if (explicitCred != null) { database = explicitCred.Database; password = explicitCred.Password; username = explicitCred.Username; } else { var anon = credentials as AnonymousCredentials; if (anon != null) { database = anon.Database; } else { throw new ArgumentException(string.Format("Login credentials must be one of the built-in types, {0} is not supported" , credentials == null, "NULL", credentials.GetType()), "credentials"); } } string encodedData; var usernameLength = (username == null ? 0 : username.Length); var passwordLength = (password == null ? 0 : password.Length); var buffer = new byte[3 + 2 * (r.Result1.Nonce.Length + database.Length + usernameLength + passwordLength)]; try { var i = Encoding.UTF8.GetBytes(r.Result1.Nonce, 0, r.Result1.Nonce.Length, buffer, 0); buffer[i++] = (byte)'|'; i += Encoding.UTF8.GetBytes(database, 0, database.Length, buffer, i); buffer[i++] = (byte)'|'; if (usernameLength > 0) i += Encoding.UTF8.GetBytes(username, 0, username.Length, buffer, i); buffer[i++] = (byte)'|'; if (passwordLength > 0) password.UseBytes<bool>((ref byte[] b) => { for (var j = 0; j < b.Length; j++) { buffer[j + i] = b[j]; } i += b.Length; return false; }); encodedData = Convert.ToBase64String(r.Result1.Encryptor.Encrypt(buffer, 0, i)); } finally { for (var j = 0; j < buffer.Length; j++) { buffer[j] = 0; } } return Query(r.Result1.Content + " " + encodedData, "ValidateUser", "<Item/>" , this.SessionPolicy , r.Result2, async); } else { // Windows authentication return Query(r.Result1.SsoUrl, r.Result1.Content, "ValidateUser", "<Item/>" , this.SessionPolicy, r.Result2, winCred.Credentials, async , req => req.SetHeader("DATABASE", winCred.Database)); } }); } loginPromise.Progress((p, m) => result.Notify(p, m)) .Done(r => { _database = database; var data = r.AsXml().DescendantsAndSelf("Result").FirstOrDefault(); _userId = data.Element("id").Value; var auth = data.Element("Authorization"); _renewalToken = new TokenCredentials(auth.Element("refresh_token").Value); _renewalToken.Database = database; SetSessionToken(auth.Element("access_token").Value , int.Parse(auth.Element("expires_in").Value)); var i18n = data.Element("i18nsessioncontext"); var context = new ServerContext(); context.DefaultLanguageCode = i18n.Element("default_language_code").Value; context.DefaultLanguageSuffix = i18n.Element("default_language_suffix").Value; context.LanguageCode = i18n.Element("language_code").Value; context.LanguageSuffix = i18n.Element("language_suffix").Value; context.Locale = i18n.Element("locale").Value; context.TimeZone = i18n.Element("time_zone").Value; _factory = new ElementFactory(context); var upload = data.Element("WriteVault") == null ? null : data.Element("WriteVault").Element("Item"); if (upload == null) { var strategy = new DefaultVaultStrategy(); strategy.Initialize(this); _writeVault = strategy.WritePriority(true).Convert(v => v.First()); } else { _writeVault = Promises.Resolved(Vault.GetVault( (IReadOnlyItem)_factory.FromXml(upload.ToString()))); } result.Resolve(_userId); }).Fail(ex => { var httpEx = ex as HttpException; if (httpEx != null && httpEx.Response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { var auth = AuthenticationScheme.Parse(httpEx.Response.Headers["WWW-Authenticate"]) .FirstOrDefault(a => a.Name == "bearer"); string msg; if (auth != null && auth.Parameters.TryGetValue("error_description", out msg)) { result.Reject(new Exception("Error logging in: " + msg)); } else { result.Reject(new Exception("Unanticipated error logging in.")); } } else { result.Reject(ex); } }); result.CancelTarget(loginPromise); return result; }
internal IPromise<string> GetResult(string action, string request, bool async) { var result = new Promise<string>(); result.CancelTarget( UploadAml(_innovatorServerUrl, "ApplyItem", request, async) .Progress((p, m) => result.Notify(p, m)) .Done(r => { var res = _factory.FromXml(r.AsString(), request, this); if (res.Exception == null) { result.Resolve(res.Value); } else { result.Reject(res.Exception); } }).Fail(ex => { result.Reject(ex); })); return result; }
public IPromise<string> Login(ICredentials credentials, bool async) { var explicitCred = credentials as ExplicitCredentials; if (explicitCred == null) throw new NotSupportedException("This connection implementation only supports explicit credentials"); _httpDatabase = explicitCred.Database; _httpUsername = explicitCred.Username; _httpPassword = explicitCred.Password == null ? _httpPassword : explicitCred.Password.UseBytes<string>((ref byte[] b) => CalcMd5(ref b).ToLowerInvariant()); _lastCredentials = credentials; var result = new Promise<string>(); result.CancelTarget( Process(new Command("<Item/>").WithAction(CommandAction.ValidateUser), async) .Progress((p, m) => result.Notify(p, m)) .Done(r => { string xml; using (var reader = new StreamReader(r)) { xml = reader.ReadToEnd(); } var data = XElement.Parse(xml).DescendantsAndSelf("Result").FirstOrDefault(); if (data == null) { var res = ElementFactory.Local.FromXml(xml); var ex = res.Exception ?? ElementFactory.Local.ServerException("Failed to login"); ex.SetDetails(_httpDatabase, "<Item/>"); _httpDatabase = null; _httpUsername = null; _httpPassword = null; result.Reject(ex); } else { foreach (var elem in data.Elements()) { switch (elem.Name.LocalName) { case "id": _userId = elem.Value; break; case "i18nsessioncontext": var context = new ServerContext(); _context.DefaultLanguageCode = elem.Element("default_language_code").Value; _context.DefaultLanguageSuffix = elem.Element("default_language_suffix").Value; _context.LanguageCode = elem.Element("language_code").Value; _context.LanguageSuffix = elem.Element("language_suffix").Value; _context.Locale = elem.Element("locale").Value; _context.TimeZone = elem.Element("time_zone").Value; break; case "ServerInfo": foreach (var info in elem.Elements()) { if (info.Name.LocalName == "Version") _arasVersion = int.Parse(info.Value.Substring(0, info.Value.IndexOf('.'))); if (!string.IsNullOrEmpty(elem.Value)) _serverInfo.Add(new KeyValuePair<string, string>("ServerInfo/" + elem.Name.LocalName, elem.Value)); } break; default: if (!string.IsNullOrEmpty(elem.Value)) _serverInfo.Add(new KeyValuePair<string, string>(elem.Name.LocalName, elem.Value)); break; } } _vaultConn.VaultStrategy.Initialize(this); result.Resolve(_userId); } }).Fail(ex => { _httpDatabase = null; _httpUsername = null; _httpPassword = null; result.Reject(ex); })); return result; }