/// <summary>
        /// Creates a credentials object from a file in the following format:
        ///
        ///     subscription=&lt;subscription-id&gt;
        ///     tenant=&lt;tenant-id&gt;
        ///     client=&lt;client-id&gt;
        ///     key=&lt;client-key&gt;
        ///     managementURI=&lt;management-URI&gt;
        ///     baseURL=&lt;base-URL&gt;
        ///     authURL=&lt;authentication-URL&gt;
        /// </summary>
        /// <param name="authFile">the path to the file</param>
        /// <returns>an authenticated credentials object</returns>
        public virtual AzureCredentials FromFile(string authFile)
        {
            var config = new Dictionary <string, string>()
            {
                { "authurl", AzureEnvironment.AzureGlobalCloud.AuthenticationEndpoint },
                { "baseurl", AzureEnvironment.AzureGlobalCloud.ResourceManagerEndpoint },
                { "managementuri", AzureEnvironment.AzureGlobalCloud.ManagementEndpoint },
                { "graphurl", AzureEnvironment.AzureGlobalCloud.GraphEndpoint }
            };

            var lines = File.ReadLines(authFile);

            if (lines.First().Trim().StartsWith("{"))
            {
                string   json       = string.Join("", lines);
                AuthFile jsonConfig = Rest.Serialization.SafeJsonConvert.DeserializeObject <AuthFile>(json);
                jsonConfig.GetType()
                .GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
                .ToList()
                .ForEach(info => config[info.Name] = (string)info.GetValue(jsonConfig));
            }
            else
            {
                lines.All(line =>
                {
                    if (line.Trim().StartsWith("#"))
                    {
                        return(true);    // Ignore comments
                    }
                    var keyVal = line.Trim().Split(new char[] { '=' }, 2);
                    if (keyVal.Length < 2)
                    {
                        return(true);    // Ignore lines that don't look like $$$=$$$
                    }
                    config[keyVal[0].ToLowerInvariant()] = keyVal[1];
                    return(true);
                });
            }


            var env = new AzureEnvironment()
            {
                AuthenticationEndpoint  = config["authurl"].Replace("\\", ""),
                ManagementEndpoint      = config["managementuri"].Replace("\\", ""),
                ResourceManagerEndpoint = config["baseurl"].Replace("\\", ""),
                GraphEndpoint           = config["graphurl"].Replace("\\", "")
            };

            AzureCredentials credentials;

            if (config.ContainsKey("key") && config["key"] != null)
            {
                credentials = FromServicePrincipal(config["client"], config["key"], config["tenant"], env);
            }
            else if (config.ContainsKey("certificate") && config["certificate"] != null)
            {
                string certificatePath = config["certificate"].Replace("\\:", ":").Replace("\\\\", "\\");
                if (!File.Exists(certificatePath))
                {
                    certificatePath = Path.Combine(Path.GetDirectoryName(authFile), certificatePath);
                }
                credentials = FromServicePrincipal(config["client"], certificatePath,
                                                   config.ContainsKey("certificatepassword") ? config["certificatepassword"] : "", config["tenant"], env);
            }
            else
            {
                throw new ValidationException("Please specify either a client key or a client certificate.");
            }
            credentials.WithDefaultSubscription(config["subscription"]);
            return(credentials);
        }