public HttpBearerChallenge this[Uri url]
        {
            get
            {
                if ( url == null )
                    throw new ArgumentNullException( "url" );

                HttpBearerChallenge value = null;

                lock ( _cacheLock )
                {
                    _cache.TryGetValue( url.FullAuthority(), out value );
                }

                return value;
            }
            set
            {
                if ( url == null )
                    throw new ArgumentNullException( "url" );

                if ( value != null && string.Compare( url.FullAuthority(), value.SourceAuthority, StringComparison.OrdinalIgnoreCase ) != 0 )
                    throw new ArgumentException( "Source URL and Challenge URL do not match" );

                lock ( _cacheLock )
                {
                    if ( value == null )
                        _cache.Remove( url.FullAuthority() );
                    else
                        _cache[url.FullAuthority()] = value;
                }
            }
        }
        protected ObjectIdentifier(string collection, string identifier)
        {
            if (string.IsNullOrEmpty(collection))
                throw new ArgumentNullException("collection");

            if (string.IsNullOrEmpty(identifier))
                throw new ArgumentNullException("identifier");

            Uri baseUri = new Uri(identifier, UriKind.Absolute);

            // We expect and identifier with either 3 or 4 segments: host + collection + name [+ version]
            if (baseUri.Segments.Length != 3 && baseUri.Segments.Length != 4)
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, 
                    "Invalid SecretIdentifier URL: {0}. Bad number of segments: {1}", identifier, baseUri.Segments.Length));

            if (!string.Equals(baseUri.Segments[1], collection + "/"))
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, 
                    "Invalid SecretIdentifier URL: {0}. segment [1] should be '{1}/', found '{2}'", identifier, collection, baseUri.Segments[1]));

            _name = baseUri.Segments[2].Substring(0, baseUri.Segments[2].Length).TrimEnd('/');

            if (baseUri.Segments.Length == 4)
                _version = baseUri.Segments[3].Substring(0, baseUri.Segments[3].Length).TrimEnd('/');

            _vault = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", baseUri.Scheme, baseUri.FullAuthority());

            _baseIdentifier = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", _vault, collection, _name);
            _identifier = string.IsNullOrEmpty(_version) ? _name : string.Format(CultureInfo.InvariantCulture, "{0}/{1}", _name, _version);
            _identifier = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", _vault, collection, _identifier);
        }
        public void SetChallengeForURL(Uri url, HttpBearerChallenge value)
        {
            if (url == null)
                throw new ArgumentNullException("url");

            if (value == null)
                throw new ArgumentNullException("value");

            if (string.Compare(url.FullAuthority(), value.SourceAuthority, StringComparison.OrdinalIgnoreCase) != 0)
                throw new ArgumentException("Source URL and Challenge URL do not match");

            lock (_cacheLock)
            {
                _cache[url.FullAuthority()] = value;
            }
        }
        public void RemoveChallengeForURL(Uri url)
        {
            if (url == null)
                throw new ArgumentNullException("url");

            lock (_cacheLock)
            {
                _cache.Remove(url.FullAuthority());
            }
        }
        public HttpBearerChallenge GetChallengeForURL(Uri url)
        {
            if (url == null)
                throw new ArgumentNullException("url");

            HttpBearerChallenge value = null;

            lock (_cacheLock)
            {
                _cache.TryGetValue(url.FullAuthority(), out value);
            }

            return value;
        }
        protected ObjectIdentifier(string vault, string collection, string name, string version = null)
        {
            if (string.IsNullOrEmpty(vault))
                throw new ArgumentNullException("vault");

            if (string.IsNullOrEmpty(collection))
                throw new ArgumentNullException("collection");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("keyName");

            var baseUri = new Uri(vault, UriKind.Absolute);

            _name = name;
            _version = version;
            _vault = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", baseUri.Scheme, baseUri.FullAuthority());
            _vaultWithoutScheme = baseUri.Authority;
            _baseIdentifier = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", _vault, collection, _name);
            _identifier = string.IsNullOrEmpty(_version) ? _name : string.Format(CultureInfo.InvariantCulture, "{0}/{1}", _name, _version);
            _identifier = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", _vault, collection, _identifier);
        }
        private static string ValidateRequestURI(Uri requestUri)
        {
            if (null == requestUri)
                throw new ArgumentNullException("requestUri");

            if (!requestUri.IsAbsoluteUri)
                throw new ArgumentException("The requestUri must be an absolute URI", "requestUri");

            if (!requestUri.Scheme.Equals("http", StringComparison.CurrentCultureIgnoreCase) 
                && !requestUri.Scheme.Equals("https", StringComparison.CurrentCultureIgnoreCase))
                throw new ArgumentException("The requestUri must be HTTP or HTTPS", "requestUri");

            return requestUri.FullAuthority();
        }