internal static UriBuilder GetResolvedRealm(Page page, string realm, HttpRequestBase requestContext)
        {
            Requires.NotNull(page, "page");
            Requires.NotNull(requestContext, "requestContext");

            // Allow for *. realm notation, as well as ASP.NET ~/ shortcuts.

            // We have to temporarily remove the *. notation if it's there so that
            // the rest of our URL manipulation will succeed.
            bool foundWildcard = false;

            // Note: we don't just use string.Replace because poorly written URLs
            // could potentially have multiple :// sequences in them.
            MatchEvaluator matchDelegate = delegate(Match m) {
                foundWildcard = true;
                return(m.Groups[1].Value);
            };
            string realmNoWildcard = Regex.Replace(realm, @"^(\w+://)\*\.", matchDelegate);

            UriBuilder fullyQualifiedRealm = new UriBuilder(
                new Uri(requestContext.GetPublicFacingUrl(), page.ResolveUrl(realmNoWildcard)));

            if (foundWildcard)
            {
                fullyQualifiedRealm.Host = "*." + fullyQualifiedRealm.Host;
            }

            // Is it valid?
            new Realm(fullyQualifiedRealm);             // throws if not valid

            return(fullyQualifiedRealm);
        }
Пример #2
0
        /// <summary>
        /// Generates the authentication requests that can satisfy the requirements of some OpenID Identifier.
        /// </summary>
        /// <param name="userSuppliedIdentifier">The Identifier supplied by the user.  This may be a URL, an XRI or i-name.</param>
        /// <param name="realm">The shorest URL that describes this relying party web site's address.
        /// For example, if your login page is found at https://www.example.com/login.aspx,
        /// your realm would typically be https://www.example.com/.</param>
        /// <param name="requestContext">The request context.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// A sequence of authentication requests, any of which constitutes a valid identity assertion on the Claimed Identifier.
        /// Never null, but may be empty.
        /// </returns>
        /// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current">HttpContext.Current</see> == <c>null</c>.</exception>
        /// <remarks>
        ///   <para>Any individual generated request can satisfy the authentication.
        /// The generated requests are sorted in preferred order.
        /// Each request is generated as it is enumerated to.  Associations are created only as
        ///   <see cref="IAuthenticationRequest.GetRedirectingResponseAsync" /> is called.</para>
        ///   <para>No exception is thrown if no OpenID endpoints were discovered.
        /// An empty enumerable is returned instead.</para>
        ///   <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para>
        /// </remarks>
        public async Task <IEnumerable <IAuthenticationRequest> > CreateRequestsAsync(Identifier userSuppliedIdentifier, Realm realm, HttpRequestBase requestContext = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            RequiresEx.ValidState(requestContext != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired);
            Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier");
            Requires.NotNull(realm, "realm");

            requestContext = requestContext ?? this.channel.GetRequestFromContext();

            // This next code contract is a BAD idea, because it causes each authentication request to be generated
            // at least an extra time.
            ////
            // Build the return_to URL
            UriBuilder returnTo = new UriBuilder(requestContext.GetPublicFacingUrl());

            // Trim off any parameters with an "openid." prefix, and a few known others
            // to avoid carrying state from a prior login attempt.
            returnTo.Query = string.Empty;
            NameValueCollection queryParams = requestContext.GetQueryStringBeforeRewriting();
            var returnToParams = new Dictionary <string, string>(queryParams.Count);

            foreach (string key in queryParams)
            {
                if (!IsOpenIdSupportingParameter(key) && key != null)
                {
                    returnToParams.Add(key, queryParams[key]);
                }
            }

            returnTo.AppendQueryArgs(returnToParams);

            return(await this.CreateRequestsAsync(userSuppliedIdentifier, realm, returnTo.Uri, cancellationToken));
        }
Пример #3
0
        /// <summary>
        /// Records statistics collected from incoming requests.
        /// </summary>
        /// <param name="request">The request.</param>
        internal static void RecordRequestStatistics(HttpRequestBase request)
        {
            Contract.Requires(request != null);

            // In release builds, just quietly return.
            if (request == null)
            {
                return;
            }

            if (Enabled)
            {
                if (Configuration.IncludeCultures)
                {
                    observedCultures.Add(Thread.CurrentThread.CurrentCulture.Name);
                }

                if (Configuration.IncludeLocalRequestUris && !observedRequests.IsFull)
                {
                    var requestBuilder = new UriBuilder(request.GetPublicFacingUrl());
                    requestBuilder.Query    = null;
                    requestBuilder.Fragment = null;
                    observedRequests.Add(requestBuilder.Uri.AbsoluteUri);
                }

                Touch();
            }
        }
Пример #4
0
        /// <summary>
        /// Gets the protocol message that may be embedded in the given HTTP request.
        /// </summary>
        /// <param name="request">The request to search for an embedded message.</param>
        /// <returns>
        /// The deserialized message, if one is found.  Null otherwise.
        /// </returns>
        protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request)
        {
            var fields = request.GetQueryStringBeforeRewriting().ToDictionary();

            // Also read parameters from the fragment, if it's available.
            // Typically the fragment is not available because the browser doesn't send it to a web server
            // but this request may have been fabricated by an installed desktop app, in which case
            // the fragment is available.
            string fragment = request.GetPublicFacingUrl().Fragment;

            if (!string.IsNullOrEmpty(fragment))
            {
                foreach (var pair in HttpUtility.ParseQueryString(fragment.Substring(1)).ToDictionary())
                {
                    fields.Add(pair.Key, pair.Value);
                }
            }

            MessageReceivingEndpoint recipient;

            try
            {
                recipient = request.GetRecipient();
            }
            catch (ArgumentException)
            {
                return(null);
            }

            return((IDirectedProtocolMessage)this.Receive(fields, recipient));
        }
Пример #5
0
        /// <summary>
        /// Processes the authorization response from an authorization server, if available.
        /// </summary>
        /// <param name="request">The incoming HTTP request that may carry an authorization response.</param>
        /// <returns>The authorization state that contains the details of the authorization.</returns>
        public IAuthorizationState ProcessUserAuthorization(HttpRequestBase request = null)
        {
            Requires.ValidState(!string.IsNullOrEmpty(this.ClientIdentifier), Strings.RequiredPropertyNotYetPreset, "ClientIdentifier");
            Requires.ValidState(this.ClientCredentialApplicator != null, Strings.RequiredPropertyNotYetPreset, "ClientCredentialApplicator");

            if (request == null)
            {
                request = this.Channel.GetRequestFromContext();
            }

            IMessageWithClientState response;

            if (this.Channel.TryReadFromRequest <IMessageWithClientState>(request, out response))
            {
                Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.GetPublicFacingUrl(), this.Channel.MessageDescriptions.Get(response));
                IAuthorizationState authorizationState;
                if (this.AuthorizationTracker != null)
                {
                    authorizationState = this.AuthorizationTracker.GetAuthorizationState(callback, response.ClientState);
                    ErrorUtilities.VerifyProtocol(authorizationState != null, ClientStrings.AuthorizationResponseUnexpectedMismatch);
                }
                else
                {
                    var context = this.Channel.GetHttpContext();
                    if (context.Session != null)
                    {
                        ErrorUtilities.VerifyProtocol(string.Equals(response.ClientState, context.Session.SessionID, StringComparison.Ordinal), ClientStrings.AuthorizationResponseUnexpectedMismatch);
                    }
                    else
                    {
                        Logger.OAuth.WarnFormat("No request context discovered, so no client state parameter could be checked to mitigate XSRF attacks.");
                    }

                    authorizationState = new AuthorizationState {
                        Callback = callback
                    };
                }
                var success = response as EndUserAuthorizationSuccessAuthCodeResponse;
                var failure = response as EndUserAuthorizationFailedResponse;
                ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany);
                if (success != null)
                {
                    this.UpdateAuthorizationWithResponse(authorizationState, success);
                }
                else                     // failure
                {
                    Logger.OAuth.Info("User refused to grant the requested authorization at the Authorization Server.");
                    authorizationState.Delete();
                }

                return(authorizationState);
            }

            return(null);
        }
Пример #6
0
        /// <summary>
        /// Processes the authorization response from an authorization server, if available.
        /// </summary>
        /// <param name="request">The incoming HTTP request that may carry an authorization response.</param>
        /// <returns>The authorization state that contains the details of the authorization.</returns>
        public IAuthorizationState ProcessUserAuthorization(HttpRequestBase request = null)
        {
            if (request == null)
            {
                request = this.Channel.GetRequestFromContext();
            }

            IMessageWithClientState response;

            if (this.Channel.TryReadFromRequest <IMessageWithClientState>(request, out response))
            {
                Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.GetPublicFacingUrl(), this.Channel.MessageDescriptions.Get(response));
                IAuthorizationState authorizationState;
                if (this.AuthorizationTracker != null)
                {
                    authorizationState = this.AuthorizationTracker.GetAuthorizationState(callback, response.ClientState);
                    ErrorUtilities.VerifyProtocol(authorizationState != null, ClientStrings.AuthorizationResponseUnexpectedMismatch);
                }
                else
                {
                    var context = this.Channel.GetHttpContext();
                    if (context.Session != null)
                    {
                        ErrorUtilities.VerifyProtocol(string.Equals(response.ClientState, context.Session.SessionID, StringComparison.Ordinal), ClientStrings.AuthorizationResponseUnexpectedMismatch);
                    }
                    else
                    {
                    }

                    authorizationState = new AuthorizationState {
                        Callback = callback
                    };
                }
                var success = response as EndUserAuthorizationSuccessAuthCodeResponse;
                var failure = response as EndUserAuthorizationFailedResponse;
                ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany);
                if (success != null)
                {
                    this.UpdateAuthorizationWithResponse(authorizationState, success);
                }
                else
                { // failure
                    authorizationState.Delete();
                }

                return(authorizationState);
            }

            return(null);
        }
Пример #7
0
        /// <summary>
        /// Searches an incoming HTTP request for data that could be used to assemble
        /// a protocol request message.
        /// </summary>
        /// <param name="request">The HTTP request to search.</param>
        /// <returns>The deserialized message, if one is found.  Null otherwise.</returns>
        protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request)
        {
            // First search the Authorization header.
            string authorization = request.Headers[HttpRequestHeaders.Authorization];
            var    fields        = MessagingUtilities.ParseAuthorizationHeader(Protocol.AuthorizationHeaderScheme, authorization).ToDictionary();

            fields.Remove("realm");             // ignore the realm parameter, since we don't use it, and it must be omitted from signature base string.

            // Scrape the entity
            if (!string.IsNullOrEmpty(request.Headers[HttpRequestHeaders.ContentType]))
            {
                var contentType = new ContentType(request.Headers[HttpRequestHeaders.ContentType]);
                if (string.Equals(contentType.MediaType, HttpFormUrlEncoded, StringComparison.Ordinal))
                {
                    foreach (string key in request.Form)
                    {
                        if (key != null)
                        {
                            fields.Add(key, request.Form[key]);
                        }
                        else
                        {
                            Logger.OAuth.WarnFormat("Ignoring query string parameter '{0}' since it isn't a standard name=value parameter.", request.Form[key]);
                        }
                    }
                }
            }

            // Scrape the query string
            var qs = request.GetQueryStringBeforeRewriting();

            foreach (string key in qs)
            {
                if (key != null)
                {
                    fields.Add(key, qs[key]);
                }
                else
                {
                    Logger.OAuth.WarnFormat("Ignoring query string parameter '{0}' since it isn't a standard name=value parameter.", qs[key]);
                }
            }

            MessageReceivingEndpoint recipient;

            try {
                recipient = request.GetRecipient();
            } catch (ArgumentException ex) {
                Logger.OAuth.WarnFormat("Unrecognized HTTP request: " + ex.ToString());
                return(null);
            }

            // Deserialize the message using all the data we've collected.
            var message = (IDirectedProtocolMessage)this.Receive(fields, recipient);

            // Add receiving HTTP transport information required for signature generation.
            var signedMessage = message as ITamperResistantOAuthMessage;

            if (signedMessage != null)
            {
                signedMessage.Recipient  = request.GetPublicFacingUrl();
                signedMessage.HttpMethod = request.HttpMethod;
            }

            return(message);
        }
        /// <summary>
        /// Gets the incoming OpenID request if there is one, or null if none was detected.
        /// </summary>
        /// <param name="httpRequestInfo">The incoming HTTP request to extract the message from.</param>
        /// <returns>
        /// The request that the hosting Provider should process and then transmit the response for.
        /// Null if no valid OpenID request was detected in the given HTTP request.
        /// </returns>
        /// <remarks>
        /// Requests may be infrastructural to OpenID and allow auto-responses, or they may
        /// be authentication requests where the Provider site has to make decisions based
        /// on its own user database and policies.
        /// </remarks>
        /// <exception cref="ProtocolException">Thrown if the incoming message is recognized
        /// but deviates from the protocol specification irrecoverably.</exception>
        public IRequest GetRequest(HttpRequestBase httpRequestInfo)
        {
            Requires.NotNull(httpRequestInfo, "httpRequestInfo");
            IDirectedProtocolMessage incomingMessage = null;

            try {
                incomingMessage = this.Channel.ReadFromRequest(httpRequestInfo);
                if (incomingMessage == null)
                {
                    // If the incoming request does not resemble an OpenID message at all,
                    // it's probably a user who just navigated to this URL, and we should
                    // just return null so the host can display a message to the user.
                    if (httpRequestInfo.HttpMethod == "GET" && !httpRequestInfo.GetPublicFacingUrl().QueryStringContainPrefixedParameters(Protocol.Default.openid.Prefix))
                    {
                        return(null);
                    }

                    ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany);
                }

                IRequest result = null;

                var checkIdMessage = incomingMessage as CheckIdRequest;
                if (checkIdMessage != null)
                {
                    result = new AuthenticationRequest(this, checkIdMessage);
                }

                if (result == null)
                {
                    var extensionOnlyRequest = incomingMessage as SignedResponseRequest;
                    if (extensionOnlyRequest != null)
                    {
                        result = new AnonymousRequest(this, extensionOnlyRequest);
                    }
                }

                if (result == null)
                {
                    var checkAuthMessage = incomingMessage as CheckAuthenticationRequest;
                    if (checkAuthMessage != null)
                    {
                        result = new AutoResponsiveRequest(incomingMessage, new CheckAuthenticationResponseProvider(checkAuthMessage, this), this.SecuritySettings);
                    }
                }

                if (result == null)
                {
                    var associateMessage = incomingMessage as IAssociateRequestProvider;
                    if (associateMessage != null)
                    {
                        result = new AutoResponsiveRequest(incomingMessage, AssociateRequestProviderTools.CreateResponse(associateMessage, this.AssociationStore, this.SecuritySettings), this.SecuritySettings);
                    }
                }

                if (result != null)
                {
                    foreach (var behavior in this.Behaviors)
                    {
                        if (behavior.OnIncomingRequest(result))
                        {
                            // This behavior matched this request.
                            break;
                        }
                    }

                    return(result);
                }

                throw ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany);
            } catch (ProtocolException ex) {
                IRequest errorResponse = this.GetErrorResponse(ex, httpRequestInfo, incomingMessage);
                if (errorResponse == null)
                {
                    throw;
                }

                return(errorResponse);
            }
        }