Example #1
0
        //////////////////////////////////////////////////////////////////////////
        // Construction
        //////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Parse a List of AuthSchemes such as a List of 'challenge'
        /// productions for the WWW-Authentication header per RFC 7235.
        /// </summary>
        public static AuthMsg[] ListFromStr(string s)
        {
            string[]  toks = SplitList(s);
            AuthMsg[] arr  = new AuthMsg[toks.Length];
            for (int i = 0; i < toks.Length; ++i)
            {
                arr[i] = AuthMsg.FromStr(toks[i]);
            }
            return(arr);
        }
        /// <summary>
        ///   Attempt standard authentication
        /// </summary>
        /// <param name="resp"> The response to the hello message </param>
        /// <returns>
        ///   true if haystack authentciation was used, false if the
        ///   server does not appear to implement RFC 7235.
        /// </returns>
        private bool OpenStd(HttpWebResponse resp)
        {
            // must be 401 challenge with WWW-Authenticate header
            if (resp.StatusCode != HttpStatusCode.Unauthorized)
            {
                return(false);
            }
            var wwwAuth = ResHeader(resp, "WWW-Authenticate");

            // don't Use this mechanism for Basic which we
            // handle as a non-standard scheme because the headers
            // don't fit nicely into our restricted AuthMsg format
            if (string.IsNullOrEmpty(wwwAuth) || wwwAuth.ToLower().StartsWith("basic", StringComparison.Ordinal))
            {
                return(false);
            }
            // process res/req messages until we have 200 or non-401 failure
            AuthScheme scheme = null;

            for (var loopCount = 0; ; ++loopCount)
            {
                // sanity check that we don't loop too many times
                if (loopCount > 5)
                {
                    throw new AuthException("Loop count exceeded");
                }

                // parse the WWW-Auth header and Use the first scheme
                var       header  = ResHeader(resp, "WWW-Authenticate");
                AuthMsg[] resMsgs = AuthMsg.ListFromStr(header);
                var       resMsg  = resMsgs[0];
                scheme = AuthScheme.Find(resMsg.scheme);

                // let scheme handle message
                var reqMsg = scheme.OnClient(this, resMsg);
                // send request back to the server
                resp = GetAuth(reqMsg);
                try
                {
                    DumpRes(resp, false);
                }
                catch (Exception e)
                {
                    e.ToString();
                }
                // 200 means we are done, 401 means keep looping,
                // consider anything else a failure
                if (resp.StatusCode == HttpStatusCode.OK)
                {
                    break;
                }
                if (resp.StatusCode == HttpStatusCode.Unauthorized)
                {
                    continue;
                }
                throw new AuthException((int)resp.StatusCode + " " + resp.GetResponseStream());
            }
            // init the bearer token
            var     authInfo    = ResHeader(resp, "Authentication-Info");
            AuthMsg authInfoMsg = AuthMsg.FromStr("bearer " + authInfo);

            // callback to scheme for client Success
            scheme.OnClientSuccess(this, authInfoMsg);

            // only keep authToken parameter for Authorization header
            authInfoMsg = new AuthMsg("bearer", new[]
            {
                "authToken",
                authInfoMsg.Param("authToken")
            });
            headers["Authorization"] = authInfoMsg.ToString();

            // we did it!
            return(true);
        }