/// <summary> /// Performs identifier discovery and 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> internal static IEnumerable <AuthenticationRequest> Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded) { // We have a long data validation and preparation process if (userSuppliedIdentifier == null) { throw new ArgumentNullException("userSuppliedIdentifier"); } if (relyingParty == null) { throw new ArgumentNullException("relyingParty"); } if (realm == null) { throw new ArgumentNullException("realm"); } userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment(); if (relyingParty.Settings.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.ShouldParameterBeStrippedFromReturnToUrl(key)) { Logger.WarnFormat("OpenId argument \"{0}\" found in return_to URL. This can corrupt an OpenID response.", key); break; } } } // 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. if (!realm.Contains(returnToUrl)) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.ReturnToNotUnderRealm, returnToUrl, realm)); } // Perform discovery right now (not deferred). var serviceEndpoints = userSuppliedIdentifier.Discover(); // Call another method that defers request generation. return(CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded)); }
/// <summary> /// Gets a value indicating whether verification of the return URL claimed by the Relying Party /// succeeded. /// </summary> /// <param name="provider">The OpenIdProvider that is performing the RP discovery.</param> /// <returns>Result of realm discovery.</returns> private RelyingPartyDiscoveryResult IsReturnUrlDiscoverableCore(OpenIdProvider provider) { Contract.Requires <ArgumentNullException>(provider != null); ErrorUtilities.VerifyInternal(this.Realm != null, "Realm should have been read or derived by now."); try { if (this.SecuritySettings.RequireSsl && this.Realm.Scheme != Uri.UriSchemeHttps) { Logger.OpenId.WarnFormat("RP discovery failed because RequireSsl is true and RP discovery would begin at insecure URL {0}.", this.Realm); return(RelyingPartyDiscoveryResult.NoServiceDocument); } var returnToEndpoints = this.Realm.DiscoverReturnToEndpoints(provider.Channel.WebRequestHandler, false); if (returnToEndpoints == null) { return(RelyingPartyDiscoveryResult.NoServiceDocument); } foreach (var returnUrl in returnToEndpoints) { Realm discoveredReturnToUrl = returnUrl.ReturnToEndpoint; // The spec requires that the return_to URLs given in an RPs XRDS doc // do not contain wildcards. if (discoveredReturnToUrl.DomainWildcard) { Logger.Yadis.WarnFormat("Realm {0} contained return_to URL {1} which contains a wildcard, which is not allowed.", Realm, discoveredReturnToUrl); continue; } // Use the same rules as return_to/realm matching to check whether this // URL fits the return_to URL we were given. if (discoveredReturnToUrl.Contains(this.RequestMessage.ReturnTo)) { // no need to keep looking after we find a match return(RelyingPartyDiscoveryResult.Success); } } } catch (ProtocolException ex) { // Don't do anything else. We quietly fail at return_to verification and return false. Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex); return(RelyingPartyDiscoveryResult.NoServiceDocument); } catch (WebException ex) { // Don't do anything else. We quietly fail at return_to verification and return false. Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex); return(RelyingPartyDiscoveryResult.NoServiceDocument); } return(RelyingPartyDiscoveryResult.NoMatchingReturnTo); }
/// <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)); }
/// <summary> /// Performs identifier discovery and 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> internal static IEnumerable <AuthenticationRequest> Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded) { // We have a long data validation and preparation process if (userSuppliedIdentifier == null) { throw new ArgumentNullException("userSuppliedIdentifier"); } if (relyingParty == null) { throw new ArgumentNullException("relyingParty"); } if (realm == null) { throw new ArgumentNullException("realm"); } userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment(); if (relyingParty.Settings.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); } //Logger.InfoFormat("Creating authentication request for user supplied Identifier: {0}", // userSuppliedIdentifier); //Logger.DebugFormat("Realm: {0}", realm); //Logger.DebugFormat("Return To: {0}", returnToUrl); //Logger.DebugFormat("RequireSsl: {0}", userSuppliedIdentifier.IsDiscoverySecureEndToEnd); // 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. if (!realm.Contains(returnToUrl)) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.ReturnToNotUnderRealm, returnToUrl, realm)); } // Perform discovery right now (not deferred). var serviceEndpoints = userSuppliedIdentifier.Discover(); // Call another method that defers request generation. return(CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded)); }
/// <summary> /// Performs identifier discovery and 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> internal static IEnumerable<AuthenticationRequest> Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded) { // We have a long data validation and preparation process if (userSuppliedIdentifier == null) throw new ArgumentNullException("userSuppliedIdentifier"); if (relyingParty == null) throw new ArgumentNullException("relyingParty"); if (realm == null) throw new ArgumentNullException("realm"); userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment(); if (relyingParty.Settings.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.ShouldParameterBeStrippedFromReturnToUrl(key)) { Logger.WarnFormat("OpenId argument \"{0}\" found in return_to URL. This can corrupt an OpenID response.", key); break; } } } // 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. if (!realm.Contains(returnToUrl)) throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.ReturnToNotUnderRealm, returnToUrl, realm)); // Perform discovery right now (not deferred). var serviceEndpoints = userSuppliedIdentifier.Discover(); // Call another method that defers request generation. return CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded); }
internal static AuthenticationRequest Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl) { if (userSuppliedIdentifier == null) throw new ArgumentNullException("userSuppliedIdentifier"); if (relyingParty == null) throw new ArgumentNullException("relyingParty"); if (realm == null) throw new ArgumentNullException("realm"); userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment(); if (relyingParty.Settings.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); } Logger.InfoFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); Logger.DebugFormat("Realm: {0}", realm); Logger.DebugFormat("Return To: {0}", returnToUrl); if (Logger.IsWarnEnabled && returnToUrl.Query != null) { NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUrl.Query); foreach (string key in returnToArgs) { if (OpenIdRelyingParty.ShouldParameterBeStrippedFromReturnToUrl(key)) { Logger.WarnFormat("OpenId argument \"{0}\" found in return_to URL. This can corrupt an OpenID response.", key); break; } } } var endpoints = new List<ServiceEndpoint>(userSuppliedIdentifier.Discover()); ServiceEndpoint endpoint = selectEndpoint(endpoints.AsReadOnly(), relyingParty); if (endpoint == null) throw new OpenIdException(Strings.OpenIdEndpointNotFound); Logger.DebugFormat("Discovered provider endpoint: {0}", endpoint); // 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. if (!realm.Contains(returnToUrl)) throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.ReturnToNotUnderRealm, returnToUrl, realm)); string token = new Token(endpoint).Serialize(relyingParty.Store); // Retrieve the association, but don't create one, as a creation was already // attempted by the selectEndpoint method. Association association = relyingParty.Store != null ? getAssociation(relyingParty, endpoint, false) : null; return new AuthenticationRequest( token, association, endpoint, realm, returnToUrl, relyingParty); }
/// <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. /// Never null, but may be empty. /// </returns> internal static IEnumerable<AuthenticationRequest> Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded) { Contract.Requires<ArgumentNullException>(userSuppliedIdentifier != null); Contract.Requires<ArgumentNullException>(relyingParty != null); Contract.Requires<ArgumentNullException>(realm != null); Contract.Ensures(Contract.Result<IEnumerable<AuthenticationRequest>>() != null); // 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 results = relyingParty.Discover(userSuppliedIdentifier).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 CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded); }
/// <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)); }
/// <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. /// Never null, but may be empty. /// </returns> internal static IEnumerable<AuthenticationRequest> Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded) { Contract.Requires(userSuppliedIdentifier != null); Contract.Requires(relyingParty != null); Contract.Requires(realm != null); Contract.Ensures(Contract.Result<IEnumerable<AuthenticationRequest>>() != null); // 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. 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<ServiceEndpoint> serviceEndpoints; try { serviceEndpoints = userSuppliedIdentifier.Discover(relyingParty.WebRequestHandler); } catch (ProtocolException ex) { Logger.Yadis.ErrorFormat("Error while performing discovery on: \"{0}\": {1}", userSuppliedIdentifier, ex); serviceEndpoints = EmptyList<ServiceEndpoint>.Instance; } // Filter disallowed endpoints. serviceEndpoints = relyingParty.SecuritySettings.FilterEndpoints(serviceEndpoints); // Call another method that defers request generation. return CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded); }
internal CheckIdRequest(OpenIdProvider provider) : base(provider) { // handle the mandatory protocol fields string mode = Util.GetRequiredArg(Query, Protocol.openid.mode); if (Protocol.Args.Mode.checkid_immediate.Equals(mode, StringComparison.Ordinal)) { Immediate = true; } else if (Protocol.Args.Mode.checkid_setup.Equals(mode, StringComparison.Ordinal)) { Immediate = false; // implied } else { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidOpenIdQueryParameterValue, Protocol.openid.mode, mode), Query); } // The spec says claimed_id and identity can both be either present or // absent. But for now we don't have or support extensions that don't // use these parameters, so we require them. In the future that may change. if (Protocol.Version.Major >= 2) { claimedIdentifier = Util.GetRequiredIdentifierArg(Query, Protocol.openid.claimed_id); } localIdentifier = Util.GetRequiredIdentifierArg(Query, Protocol.openid.identity); // The spec says return_to is optional, but what good is authenticating // a user if the user won't be sent back? ReturnTo = Util.GetRequiredUriArg(Query, Protocol.openid.return_to); Realm = Util.GetOptionalRealmArg(Query, Protocol.openid.Realm) ?? ReturnTo; AssociationHandle = Util.GetOptionalArg(Query, Protocol.openid.assoc_handle); if (!Realm.Contains(ReturnTo)) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.ReturnToNotUnderRealm, ReturnTo.AbsoluteUri, Realm), Query); } if (Protocol.Version.Major >= 2) { if (LocalIdentifier == Protocol.ClaimedIdentifierForOPIdentifier ^ ClaimedIdentifier == Protocol.ClaimedIdentifierForOPIdentifier) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.MatchingArgumentsExpected, Protocol.openid.claimed_id, Protocol.openid.identity, Protocol.ClaimedIdentifierForOPIdentifier), Query); } } if (ClaimedIdentifier == Protocol.ClaimedIdentifierForOPIdentifier && Protocol.ClaimedIdentifierForOPIdentifier != null) { // Force the OP to deal with identifier_select by nulling out the two identifiers. IsDirectedIdentity = true; claimedIdentifier = null; localIdentifier = null; } // URL delegation is only detectable from 2.0 RPs, since openid.claimed_id isn't included from 1.0 RPs. // If the openid.claimed_id is present, and if it's different than the openid.identity argument, then // the RP has discovered a claimed identifier that has delegated authentication to this Provider. IsDelegatedIdentifier = ClaimedIdentifier != null && ClaimedIdentifier != LocalIdentifier; }