コード例 #1
0
ファイル: IPCServer.cs プロジェクト: radtek/Filter-Windows
        /// <summary>
        /// Notifies clients of the current authentication state.
        /// </summary>
        /// <param name="action">
        /// The authentication command which reflects the current auth state.
        /// </param>
        public void NotifyAuthenticationStatus(AuthenticationAction action, string username = null, AuthenticationResultObject authenticationResult = null)
        {
            // KF - I edited this function to take two arguments instead of one and then refactored all the code that calls it to pass in an AuthenticationResultObject
            switch (m_waitingForAuth)
            {
            case true:
            {
                m_waitingForAuth = action == AuthenticationAction.Authenticated ? false : true;
            }
            break;

            case false:
            {
                m_waitingForAuth = action == AuthenticationAction.Required;
            }
            break;
            }


            var authResult = new AuthenticationResultObject();

            if (authenticationResult != null)
            {
                authResult = authenticationResult;
            }

            var msg = new AuthenticationMessage(action, authResult, username); // KF - Also added a constructor to AuthenticationMessage);

            PushMessage(msg);
        }
コード例 #2
0
 /// <summary>
 /// Constructs a new AuthenticationMessage instance. Used by the IPC server to return more detailed information about the
 /// </summary>
 /// <param name="action">
 /// The action directive of this message.
 /// </param>
 /// <param name="authenticationResult">
 /// The authentication result returned by the web server to the service.
 /// </param>
 public AuthenticationMessage(AuthenticationAction action, AuthenticationResultObject authenticationResult)
 {
     Action               = action;
     Username             = string.Empty;
     Password             = new byte[0];
     AuthenticationResult = authenticationResult;
 }
コード例 #3
0
 /// <summary>
 /// Constructs a new AuthenticationMessage instance. Used by the IPC server to return more detailed information about the
 /// </summary>
 /// <param name="action">
 /// The action directive of this message.
 /// </param>
 /// <param name="authenticationResult">
 /// The authentication result returned by the web server to the service.
 /// </param>
 public AuthenticationMessage(AuthenticationAction action, AuthenticationResultObject authenticationResult, string username = null)
 {
     Action               = action;
     Username             = username;
     Password             = new byte[0];
     AuthenticationResult = authenticationResult;
 }
コード例 #4
0
        public AuthenticationResultObject Authenticate(string username, byte[] unencryptedPassword)
        {
            m_logger.Error(nameof(Authenticate));

            AuthenticationResultObject ret = new AuthenticationResultObject();

            // Enforce parameters are valid.
            Debug.Assert(StringExtensions.Valid(username));

            if (!StringExtensions.Valid(username))
            {
                throw new ArgumentException("Supplied username cannot be null, empty or whitespace.", nameof(username));
            }

            Debug.Assert(unencryptedPassword != null && unencryptedPassword.Length > 0);

            if (unencryptedPassword == null || unencryptedPassword.Length <= 0)
            {
                throw new ArgumentException("Supplied password byte array cannot be null and must have a length greater than zero.", nameof(unencryptedPassword));
            }
            //

            // Don't bother if we don't have internet.
            var hasInternet = NetworkStatus.Default.HasIpv4InetConnection || NetworkStatus.Default.HasIpv6InetConnection;

            if (hasInternet == false)
            {
                m_logger.Info("Aborting authentication attempt because no internet connection could be detected.");
                ret.AuthenticationResult  = AuthenticationResult.ConnectionFailed;
                ret.AuthenticationMessage = "Aborting authentication attempt because no internet connection could be detected.";
                return(ret);
            }

            // Will be set if we get any sort of web exception.
            bool connectionFailure = false;

            // Try to send the device name as well. Helps distinguish between clients under the same account.
            string deviceName = string.Empty;

            byte[] formData = null;

            try
            {
                deviceName = Environment.MachineName;
            }
            catch
            {
                deviceName = "Unknown";
            }

            HttpWebRequest authRequest = null;

            try
            {
                authRequest = GetApiBaseRequest(m_namedResourceMap[ServiceResource.GetToken], new ResourceOptions());

                // Build out username and password as post form data. We need to ensure that we mop
                // up any decrypted forms of our password when we're done, and ASAP.
                formData = System.Text.Encoding.UTF8.GetBytes(string.Format("email={0}&identifier={1}&device_id={2}", username, FingerprintService.Default.Value, deviceName));

                // Don't forget to the set the content length to the total length of our form POST data!
                authRequest.ContentLength = formData.Length;

                authRequest.ContentType = "application/x-www-form-urlencoded";

                // XXX TODO - This is naughty, because we're putting our password into a string, so
                // it will linger in memory. However, it appears that the provided API doesn't give
                // us any choice.
                // KF NOTE: Why System.String is insecure. https://stackoverflow.com/questions/1166952/net-secure-memory-structures
                var encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + Encoding.UTF8.GetString(unencryptedPassword)));
                authRequest.Headers.Add("Authorization", "Basic " + encoded);

                // Grab the request stream so we can POST our login form data to it.
                using (var requestStream = authRequest.GetRequestStream())
                {
                    // Write and close.
                    requestStream.Write(formData, 0, formData.Length);
                    requestStream.Close();
                }

                // Now that our login form data has been POST'ed, get a response.
                using (var response = (HttpWebResponse)authRequest.GetResponse())
                {
                    // Get the response code as an int so we can range check it.
                    var code = (int)response.StatusCode;

                    // Check if the response status code is outside the "success" range of codes
                    // defined in HTTP. If so, we failed. We include redirect codes (3XX) as success,
                    // since our server side will just redirect us if we're already authed.
                    if (code > 199 && code < 299)
                    {
                        using (var tr = new StreamReader(response.GetResponseStream()))
                        {
                            WebServiceUtil.Default.AuthToken = tr.ReadToEnd();
                            WebServiceUtil.Default.UserEmail = username;
                        }

                        response.Close();
                        authRequest.Abort();
                        ret.AuthenticationResult = AuthenticationResult.Success;
                        return(ret);
                    }
                    else
                    {
                        if (code == 401 || code == 403)
                        {
                            m_logger.Info("Authentication failed with code: {0}.", code);
                            WebServiceUtil.Default.AuthToken = string.Empty;
                            ret.AuthenticationResult         = AuthenticationResult.Failure;
                            return(ret);
                        }
                        else if (code > 399 && code < 499)
                        {
                            m_logger.Info("Authentication failed with code: {0}.", code);
                            ret.AuthenticationResult = AuthenticationResult.Failure;
                            return(ret);
                        }
                    }
                }
            }
            catch (WebException e)
            {
                // XXX TODO - Is this sufficient?
                if (e.Status == WebExceptionStatus.Timeout)
                {
                    m_logger.Info("Authentication failed due to timeout.");
                    connectionFailure = true;
                }

                try
                {
                    using (WebResponse response = e.Response)
                    {
                        HttpWebResponse httpResponse = (HttpWebResponse)response;
                        m_logger.Error("Error code: {0}", httpResponse.StatusCode);

                        string errorText = string.Empty;

                        using (Stream data = response.GetResponseStream())
                            using (var reader = new StreamReader(data))
                            {
                                errorText = reader.ReadToEnd();

                                // GS Just cleans up the punctuation at the end of string
                                string excpList  = "$@*!.";
                                var    chRemoved = errorText
                                                   .Select(ch => excpList.Contains(ch) ? (char?)null : ch);
                                errorText = string.Concat(chRemoved.ToArray()) + "!";

                                m_logger.Error("Stream errorText: " + errorText);
                            }

                        int code = (int)httpResponse.StatusCode;

                        if (code == 401 || code == 403)
                        {
                            AuthToken = string.Empty;
                        }

                        if (code > 399 && code < 499)
                        {
                            m_logger.Info("Authentication failed with code: {0}.", code);
                            m_logger.Info("Athentication failure text: {0}", errorText);
                            ret.AuthenticationMessage = errorText;
                            ret.AuthenticationResult  = AuthenticationResult.Failure;
                            return(ret);
                        }
                    }
                }
                catch (Exception iex)
                {
                    LoggerUtil.RecursivelyLogException(m_logger, iex);
                }

                // Log the exception.
                m_logger.Error(e.Message);
                m_logger.Error(e.StackTrace);
            }
            catch (Exception e)
            {
                while (e != null)
                {
                    m_logger.Error(e.Message);
                    m_logger.Error(e.StackTrace);
                    e = e.InnerException;
                }

                m_logger.Info("Authentication failed due to a failure to process the request and response. Attempted URL {0}", authRequest?.RequestUri);
                WebServiceUtil.Default.AuthToken = string.Empty;
                ret.AuthenticationResult         = AuthenticationResult.Failure;
                return(ret);
            }
            finally
            {
                // This finally block is guaranteed TM to be run, so this is where we're going to
                // clean up any decrypted versions of the user's password held in memory.
                if (unencryptedPassword != null && unencryptedPassword.Length > 0)
                {
                    Array.Clear(unencryptedPassword, 0, unencryptedPassword.Length);
                }

                if (formData != null && formData.Length > 0)
                {
                    Array.Clear(formData, 0, formData.Length);
                }
            }

            m_logger.Info("Authentication failed due to a complete failure to process the request and response. Past-catch attempted url {0}", authRequest?.RequestUri);

            // If we had success, we should/would have returned by now.
            if (!connectionFailure)
            {
                WebServiceUtil.Default.AuthToken = string.Empty;
            }

            ret.AuthenticationResult = connectionFailure ? AuthenticationResult.ConnectionFailed : AuthenticationResult.Failure;
            return(ret);
        }