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;
    }
Exemple #3
0
        /// <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);
        }
Exemple #4
0
    /// <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;
    }