/// <summary>
        /// Performs identifier discovery, creates associations and generates authentication requests
        /// on-demand for as long as new ones can be generated based on the results of Identifier discovery.
        /// </summary>
        /// <param name="userSuppliedIdentifier">The user supplied identifier.</param>
        /// <param name="relyingParty">The relying party.</param>
        /// <param name="realm">The realm.</param>
        /// <param name="returnToUrl">The return_to base URL.</param>
        /// <param name="createNewAssociationsAsNeeded">if set to <c>true</c>, associations that do not exist between this Relying Party and the asserting Providers are created before the authentication request is created.</param>
        /// <returns>A sequence of authentication requests, any of which constitutes a valid identity assertion on the Claimed Identifier.</returns>
        internal static IEnumerable <AuthenticationRequest> Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded)
        {
            // We have a long data validation and preparation process
            ErrorUtilities.VerifyArgumentNotNull(userSuppliedIdentifier, "userSuppliedIdentifier");
            ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");
            ErrorUtilities.VerifyArgumentNotNull(realm, "realm");

            // Normalize the portion of the return_to path that correlates to the realm for capitalization.
            // (so that if a web app base path is /MyApp/, but the URL of this request happens to be
            // /myapp/login.aspx, we bump up the return_to Url to use /MyApp/ so it matches the realm.
            UriBuilder returnTo = new UriBuilder(returnToUrl);

            if (returnTo.Path.StartsWith(realm.AbsolutePath, StringComparison.OrdinalIgnoreCase) &&
                !returnTo.Path.StartsWith(realm.AbsolutePath, StringComparison.Ordinal))
            {
                returnTo.Path = realm.AbsolutePath + returnTo.Path.Substring(realm.AbsolutePath.Length);
                returnToUrl   = returnTo.Uri;
            }

            userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment();
            if (relyingParty.SecuritySettings.RequireSsl)
            {
                // Rather than check for successful SSL conversion at this stage,
                // We'll wait for secure discovery to fail on the new identifier.
                userSuppliedIdentifier.TryRequireSsl(out userSuppliedIdentifier);
            }

            if (Logger.IsWarnEnabled && returnToUrl.Query != null)
            {
                NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUrl.Query);
                foreach (string key in returnToArgs)
                {
                    if (OpenIdRelyingParty.IsOpenIdSupportingParameter(key))
                    {
                        Logger.WarnFormat("OpenID argument \"{0}\" found in return_to URL.  This can corrupt an OpenID response.", key);
                    }
                }
            }

            // Throw an exception now if the realm and the return_to URLs don't match
            // as required by the provider.  We could wait for the provider to test this and
            // fail, but this will be faster and give us a better error message.
            ErrorUtilities.VerifyProtocol(realm.Contains(returnToUrl), OpenIdStrings.ReturnToNotUnderRealm, returnToUrl, realm);

            // Perform discovery right now (not deferred).
            var serviceEndpoints = userSuppliedIdentifier.Discover(relyingParty.WebRequestHandler);

            // Call another method that defers request generation.
            return(CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets all the callback arguments that were previously added using
        /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/> or as a natural part
        /// of the return_to URL.
        /// </summary>
        /// <returns>A name-value dictionary.  Never null.</returns>
        /// <remarks>
        /// Callback parameters are only available if they are complete and untampered with
        /// since the original request message (as proven by a signature).
        /// If the relying party is operating in stateless mode an empty dictionary is always
        /// returned since the callback arguments could not be signed to protect against
        /// tampering.
        /// </remarks>
        public IDictionary <string, string> GetUntrustedCallbackArguments()
        {
            var args = new Dictionary <string, string>();

            // Return all the return_to arguments, except for the OpenID-supporting ones.
            // The only arguments that should be returned here are the ones that the host
            // web site adds explicitly.
            foreach (string key in this.response.GetReturnToParameterNames().Where(key => !OpenIdRelyingParty.IsOpenIdSupportingParameter(key)))
            {
                args[key] = this.response.GetReturnToArgument(key);
            }

            return(args);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Performs identifier discovery, creates associations and generates authentication requests
        /// on-demand for as long as new ones can be generated based on the results of Identifier discovery.
        /// </summary>
        /// <param name="userSuppliedIdentifier">The user supplied identifier.</param>
        /// <param name="relyingParty">The relying party.</param>
        /// <param name="realm">The realm.</param>
        /// <param name="returnToUrl">The return_to base URL.</param>
        /// <param name="createNewAssociationsAsNeeded">if set to <c>true</c>, associations that do not exist between this Relying Party and the asserting Providers are created before the authentication request is created.</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>
        internal static async Task <IEnumerable <AuthenticationRequest> > CreateAsync(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded, CancellationToken cancellationToken)
        {
            Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier");
            Requires.NotNull(relyingParty, "relyingParty");
            Requires.NotNull(realm, "realm");

            // Normalize the portion of the return_to path that correlates to the realm for capitalization.
            // (so that if a web app base path is /MyApp/, but the URL of this request happens to be
            // /myapp/login.aspx, we bump up the return_to Url to use /MyApp/ so it matches the realm.
            UriBuilder returnTo = new UriBuilder(returnToUrl);

            if (returnTo.Path.StartsWith(realm.AbsolutePath, StringComparison.OrdinalIgnoreCase) &&
                !returnTo.Path.StartsWith(realm.AbsolutePath, StringComparison.Ordinal))
            {
                returnTo.Path = realm.AbsolutePath + returnTo.Path.Substring(realm.AbsolutePath.Length);
                returnToUrl   = returnTo.Uri;
            }

            userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment();
            if (relyingParty.SecuritySettings.RequireSsl)
            {
                // Rather than check for successful SSL conversion at this stage,
                // We'll wait for secure discovery to fail on the new identifier.
                if (!userSuppliedIdentifier.TryRequireSsl(out userSuppliedIdentifier))
                {
                    // But at least log the failure.
                    Logger.OpenId.WarnFormat("RequireSsl mode is on, so discovery on insecure identifier {0} will yield no results.", userSuppliedIdentifier);
                }
            }

            if (Logger.OpenId.IsWarnEnabled && returnToUrl.Query != null)
            {
                NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUrl.Query);
                foreach (string key in returnToArgs)
                {
                    if (OpenIdRelyingParty.IsOpenIdSupportingParameter(key))
                    {
                        Logger.OpenId.WarnFormat("OpenID argument \"{0}\" found in return_to URL.  This can corrupt an OpenID response.", key);
                    }
                }
            }

            // Throw an exception now if the realm and the return_to URLs don't match
            // as required by the provider.  We could wait for the provider to test this and
            // fail, but this will be faster and give us a better error message.
            ErrorUtilities.VerifyProtocol(realm.Contains(returnToUrl), OpenIdStrings.ReturnToNotUnderRealm, returnToUrl, realm);

            // Perform discovery right now (not deferred).
            IEnumerable <IdentifierDiscoveryResult> serviceEndpoints;

            try {
                var identifierDiscoveryResults = await relyingParty.DiscoverAsync(userSuppliedIdentifier, cancellationToken);

                var results = identifierDiscoveryResults.CacheGeneratedResults();

                // If any OP Identifier service elements were found, we must not proceed
                // to use any Claimed Identifier services, per OpenID 2.0 sections 7.3.2.2 and 11.2.
                // For a discussion on this topic, see
                // http://groups.google.com/group/dotnetopenid/browse_thread/thread/4b5a8c6b2210f387/5e25910e4d2252c8
                // Usually the Discover method we called will automatically filter this for us, but
                // just to be sure, we'll do it here as well since the RP may be configured to allow
                // these dual identifiers for assertion verification purposes.
                var opIdentifiers      = results.Where(result => result.ClaimedIdentifier == result.Protocol.ClaimedIdentifierForOPIdentifier).CacheGeneratedResults();
                var claimedIdentifiers = results.Where(result => result.ClaimedIdentifier != result.Protocol.ClaimedIdentifierForOPIdentifier);
                serviceEndpoints = opIdentifiers.Any() ? opIdentifiers : claimedIdentifiers;
            } catch (ProtocolException ex) {
                Logger.Yadis.ErrorFormat("Error while performing discovery on: \"{0}\": {1}", userSuppliedIdentifier, ex);
                serviceEndpoints = Enumerable.Empty <IdentifierDiscoveryResult>();
            }

            // Filter disallowed endpoints.
            serviceEndpoints = relyingParty.SecuritySettings.FilterEndpoints(serviceEndpoints);

            // Call another method that defers request generation.
            return(await CreateInternalAsync(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded, cancellationToken));
        }