コード例 #1
0
        public static async Task <string> GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse)
        {
            StringBuilder sb = StringBuilderCache.Acquire();

            // It is mandatory for servers to implement sha-256 per RFC 7616
            // Keep MD5 for backward compatibility.
            string algorithm;
            bool   isAlgorithmSpecified = digestResponse.Parameters.TryGetValue(Algorithm, out algorithm);

            if (isAlgorithmSpecified)
            {
                if (!algorithm.Equals(Sha256, StringComparison.OrdinalIgnoreCase) &&
                    !algorithm.Equals(Md5, StringComparison.OrdinalIgnoreCase) &&
                    !algorithm.Equals(Sha256Sess, StringComparison.OrdinalIgnoreCase) &&
                    !algorithm.Equals(MD5Sess, StringComparison.OrdinalIgnoreCase))
                {
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Error(digestResponse, "Algorithm not supported: {algorithm}");
                    }
                    return(null);
                }
            }
            else
            {
                algorithm = Md5;
            }

            // Check if nonce is there in challenge
            string nonce;

            if (!digestResponse.Parameters.TryGetValue(Nonce, out nonce))
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(digestResponse, "Nonce missing");
                }
                return(null);
            }

            // opaque token may or may not exist
            string opaque;

            digestResponse.Parameters.TryGetValue(Opaque, out opaque);

            string realm;

            if (!digestResponse.Parameters.TryGetValue(Realm, out realm))
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(digestResponse, "Realm missing");
                }
                return(null);
            }

            // Add username
            string userhash;

            if (digestResponse.Parameters.TryGetValue(UserHash, out userhash) && userhash == "true")
            {
                sb.AppendKeyValue(Username, ComputeHash(credential.UserName + ":" + realm, algorithm));
                sb.AppendKeyValue(UserHash, userhash, includeQuotes: false);
            }
            else
            {
                if (HeaderUtilities.ContainsNonAscii(credential.UserName))
                {
                    string usernameStar = HeaderUtilities.Encode5987(credential.UserName);
                    sb.AppendKeyValue(UsernameStar, usernameStar, includeQuotes: false);
                }
                else
                {
                    sb.AppendKeyValue(Username, credential.UserName);
                }
            }

            // Add realm
            if (realm != string.Empty)
            {
                sb.AppendKeyValue(Realm, realm);
            }

            // Add nonce
            sb.AppendKeyValue(Nonce, nonce);

            // Add uri
            sb.AppendKeyValue(Uri, request.RequestUri.PathAndQuery);

            // Set qop, default is auth
            string qop            = Auth;
            bool   isQopSpecified = digestResponse.Parameters.ContainsKey(Qop);

            if (isQopSpecified)
            {
                // Check if auth-int present in qop string
                int index1 = digestResponse.Parameters[Qop].IndexOf(AuthInt, StringComparison.Ordinal);
                if (index1 != -1)
                {
                    // Get index of auth if present in qop string
                    int index2 = digestResponse.Parameters[Qop].IndexOf(Auth, StringComparison.Ordinal);

                    // If index2 < index1, auth option is available
                    // If index2 == index1, check if auth option available later in string after auth-int.
                    if (index2 == index1)
                    {
                        index2 = digestResponse.Parameters[Qop].IndexOf(Auth, index1 + AuthInt.Length, StringComparison.Ordinal);
                        if (index2 == -1)
                        {
                            qop = AuthInt;
                        }
                    }
                }
            }

            // Set cnonce
            string cnonce = GetRandomAlphaNumericString();

            // Calculate response
            string a1 = credential.UserName + ":" + realm + ":" + credential.Password;

            if (algorithm.EndsWith("sess", StringComparison.OrdinalIgnoreCase))
            {
                a1 = ComputeHash(a1, algorithm) + ":" + nonce + ":" + cnonce;
            }

            string a2 = request.Method.Method + ":" + request.RequestUri.PathAndQuery;

            if (qop == AuthInt)
            {
                string content = request.Content == null ? string.Empty : await request.Content.ReadAsStringAsync().ConfigureAwait(false);

                a2 = a2 + ":" + ComputeHash(content, algorithm);
            }

            string response;

            if (isQopSpecified)
            {
                response = ComputeHash(ComputeHash(a1, algorithm) + ":" +
                                       nonce + ":" +
                                       DigestResponse.NonceCount + ":" +
                                       cnonce + ":" +
                                       qop + ":" +
                                       ComputeHash(a2, algorithm), algorithm);
            }
            else
            {
                response = ComputeHash(ComputeHash(a1, algorithm) + ":" +
                                       nonce + ":" +
                                       ComputeHash(a2, algorithm), algorithm);
            }

            // Add response
            sb.AppendKeyValue(Response, response, includeComma: opaque != null || isAlgorithmSpecified || isQopSpecified);

            // Add opaque
            if (opaque != null)
            {
                sb.AppendKeyValue(Opaque, opaque, includeComma: isAlgorithmSpecified || isQopSpecified);
            }

            if (isAlgorithmSpecified)
            {
                // Add algorithm
                sb.AppendKeyValue(Algorithm, algorithm, includeQuotes: false, includeComma: isQopSpecified);
            }

            if (isQopSpecified)
            {
                // Add qop
                sb.AppendKeyValue(Qop, qop, includeQuotes: false);

                // Add nc
                sb.AppendKeyValue(NC, DigestResponse.NonceCount, includeQuotes: false);

                // Add cnonce
                sb.AppendKeyValue(CNonce, cnonce, includeComma: false);
            }

            return(StringBuilderCache.GetStringAndRelease(sb));
        }