diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-09-14 09:01:44 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-09-14 09:01:44 -0700 |
commit | 40d87d3af4dd5a9238fe838a5baf3b533b012359 (patch) | |
tree | d8bf9d7ba6f21e2af1e685b64249f8a91104f9d5 | |
parent | b83cf113f074c8b3887991413b8472056f2caa32 (diff) | |
parent | 07235e4d3aa03c3ea3597ad3f21e1cd265b81702 (diff) | |
download | DotNetOpenAuth-40d87d3af4dd5a9238fe838a5baf3b533b012359.zip DotNetOpenAuth-40d87d3af4dd5a9238fe838a5baf3b533b012359.tar.gz DotNetOpenAuth-40d87d3af4dd5a9238fe838a5baf3b533b012359.tar.bz2 |
Merge branch 'v3.2'
Conflicts:
src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs
src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdTextBox.cs
src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs
src/version.txt
15 files changed, 289 insertions, 37 deletions
diff --git a/doc/specs/ICAM_OpenID20Profile.pdf b/doc/specs/ICAM_OpenID20Profile.pdf Binary files differnew file mode 100644 index 0000000..8b502b6 --- /dev/null +++ b/doc/specs/ICAM_OpenID20Profile.pdf diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln index 4c41496..f8d9b8f 100644 --- a/src/DotNetOpenAuth.sln +++ b/src/DotNetOpenAuth.sln @@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specs", "Specs", "{CD57219F-24F4-4136-8741-6063D0D7A031}" ProjectSection(SolutionItems) = preProject + ..\doc\specs\ICAM_OpenID20Profile.pdf = ..\doc\specs\ICAM_OpenID20Profile.pdf ..\doc\specs\OAuth Core 1.0.htm = ..\doc\specs\OAuth Core 1.0.htm ..\doc\specs\OAuth Core 1.0a (Draft 3).htm = ..\doc\specs\OAuth Core 1.0a (Draft 3).htm ..\doc\specs\OpenID OAuth Extension.htm = ..\doc\specs\OpenID OAuth Extension.htm diff --git a/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs index b53e1f6..a500e3b 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs @@ -37,6 +37,21 @@ namespace DotNetOpenAuth.OpenId.Provider { this.positiveResponse = new IndirectSignedResponse(request); } + #region HostProcessedRequest members + + /// <summary> + /// Gets or sets the provider endpoint. + /// </summary> + /// <value> + /// The default value is the URL that the request came in on from the relying party. + /// </value> + public override Uri ProviderEndpoint { + get { return this.positiveResponse.ProviderEndpoint; } + set { this.positiveResponse.ProviderEndpoint = value; } + } + + #endregion + #region IAnonymousRequest Members /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs index 56e73da..a5d936b 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs @@ -48,6 +48,21 @@ namespace DotNetOpenAuth.OpenId.Provider { this.IsDelegatedIdentifier = this.ClaimedIdentifier != null && this.ClaimedIdentifier != this.LocalIdentifier; } + #region HostProcessedRequest members + + /// <summary> + /// Gets or sets the provider endpoint. + /// </summary> + /// <value> + /// The default value is the URL that the request came in on from the relying party. + /// </value> + public override Uri ProviderEndpoint { + get { return this.positiveResponse.ProviderEndpoint; } + set { this.positiveResponse.ProviderEndpoint = value; } + } + + #endregion + /// <summary> /// Gets a value indicating whether the response is ready to be created and sent. /// </summary> diff --git a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs index 6e61376..301f150 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs @@ -66,6 +66,14 @@ namespace DotNetOpenAuth.OpenId.Provider { get { return this.RequestMessage.Realm; } } + /// <summary> + /// Gets or sets the provider endpoint. + /// </summary> + /// <value> + /// The default value is the URL that the request came in on from the relying party. + /// </value> + public abstract Uri ProviderEndpoint { get; set; } + #endregion /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs index 5256fdd..345ba52 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs @@ -33,6 +33,16 @@ namespace DotNetOpenAuth.OpenId.Provider { bool Immediate { get; } /// <summary> + /// Gets or sets the provider endpoint claimed in the positive assertion. + /// </summary> + /// <value> + /// The default value is the URL that the request came in on from the relying party. + /// This value MUST match the value for the OP Endpoint in the discovery results for the + /// claimed identifier being asserted in a positive response. + /// </value> + Uri ProviderEndpoint { get; set; } + + /// <summary> /// Attempts to perform relying party discovery of the return URL claimed by the Relying Party. /// </summary> /// <param name="provider">The OpenIdProvider that is performing the RP discovery.</param> @@ -76,6 +86,24 @@ namespace DotNetOpenAuth.OpenId.Provider { get { throw new System.NotImplementedException(); } } + /// <summary> + /// Gets or sets the provider endpoint. + /// </summary> + /// <value> + /// The default value is the URL that the request came in on from the relying party. + /// </value> + Uri IHostProcessedRequest.ProviderEndpoint { + get { + Contract.Ensures(Contract.Result<Uri>() != null); + throw new NotImplementedException(); + } + + set { + Contract.Requires(value != null); + throw new NotImplementedException(); + } + } + #endregion #region IRequest Members diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs index ff7741a..d7345ac 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs @@ -189,17 +189,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="arguments">The arguments to add to the request's return_to URI.</param> /// <remarks> - /// <para>Note that these values are NOT protected against tampering in transit. No - /// security-sensitive data should be stored using this method.</para> + /// <para>Note that these values are NOT protected against eavesdropping in transit. No + /// privacy-sensitive data should be stored using this method.</para> /// <para>The values stored here can be retrieved using - /// <see cref="IAuthenticationResponse.GetCallbackArguments"/>.</para> + /// <see cref="IAuthenticationResponse.GetCallbackArguments"/>, which will only return the value + /// if it hasn't been tampered with in transit.</para> /// <para>Since the data set here is sent in the querystring of the request and some /// servers place limits on the size of a request URL, this data should be kept relatively /// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para> /// </remarks> public void AddCallbackArguments(IDictionary<string, string> arguments) { ErrorUtilities.VerifyArgumentNotNull(arguments, "arguments"); - ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name); foreach (var pair in arguments) { ErrorUtilities.VerifyArgument(!string.IsNullOrEmpty(pair.Key), MessagingStrings.UnexpectedNullOrEmptyKey); @@ -215,10 +215,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="key">The parameter name.</param> /// <param name="value">The value of the argument.</param> /// <remarks> - /// <para>Note that these values are NOT protected against tampering in transit. No - /// security-sensitive data should be stored using this method.</para> + /// <para>Note that these values are NOT protected against eavesdropping in transit. No + /// privacy-sensitive data should be stored using this method.</para> /// <para>The value stored here can be retrieved using - /// <see cref="IAuthenticationResponse.GetCallbackArgument"/>.</para> + /// <see cref="IAuthenticationResponse.GetCallbackArgument"/>, which will only return the value + /// if it hasn't been tampered with in transit.</para> /// <para>Since the data set here is sent in the querystring of the request and some /// servers place limits on the size of a request URL, this data should be kept relatively /// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para> @@ -226,7 +227,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public void AddCallbackArguments(string key, string value) { ErrorUtilities.VerifyNonZeroLength(key, "key"); ErrorUtilities.VerifyArgumentNotNull(value, "value"); - ErrorUtilities.VerifyOperation(this.RelyingParty.CanSignCallbackArguments, OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name); this.returnToArgs.Add(key, value); } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs index d94af14..45f7f54 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/FailedAuthenticationResponse.cs @@ -128,7 +128,23 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <para>Note that these values are NOT protected against tampering in transit.</para> /// </remarks> public IDictionary<string, string> GetCallbackArguments() { - return new Dictionary<string, string>(); + return EmptyDictionary<string, string>.Instance; + } + + /// <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 even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public IDictionary<string, string> GetUntrustedCallbackArguments() { + return EmptyDictionary<string, string>.Instance; } /// <summary> @@ -150,6 +166,24 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> + /// Gets a callback argument's value that was previously added using + /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>. + /// </summary> + /// <param name="key">The name of the parameter whose value is sought.</param> + /// <returns> + /// The value of the argument, or null if the named parameter could not be found. + /// </returns> + /// <remarks> + /// Callback parameters are only available even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public string GetUntrustedCallbackArgument(string key) { + return null; + } + + /// <summary> /// Tries to get an OpenID extension that may be present in the response. /// </summary> /// <typeparam name="T">The type of extension to look for in the response message.</typeparam> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs index 27daa46..5559899 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs @@ -98,10 +98,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="arguments">The arguments to add to the request's return_to URI. Values must not be null.</param> /// <remarks> - /// <para>Note that these values are NOT protected against tampering in transit. No - /// security-sensitive data should be stored using this method.</para> + /// <para>Note that these values are NOT protected against eavesdropping in transit. No + /// privacy-sensitive data should be stored using this method.</para> /// <para>The values stored here can be retrieved using - /// <see cref="IAuthenticationResponse.GetCallbackArguments"/>.</para> + /// <see cref="IAuthenticationResponse.GetCallbackArgument"/>, which will only return the value + /// if it can be verified as untampered with in transit.</para> /// <para>Since the data set here is sent in the querystring of the request and some /// servers place limits on the size of a request URL, this data should be kept relatively /// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para> @@ -114,10 +115,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="key">The parameter name.</param> /// <param name="value">The value of the argument. Must not be null.</param> /// <remarks> - /// <para>Note that these values are NOT protected against tampering in transit. No - /// security-sensitive data should be stored using this method.</para> + /// <para>Note that these values are NOT protected against eavesdropping in transit. No + /// privacy-sensitive data should be stored using this method.</para> /// <para>The value stored here can be retrieved using - /// <see cref="IAuthenticationResponse.GetCallbackArgument"/>.</para> + /// <see cref="IAuthenticationResponse.GetCallbackArgument"/>, which will only return the value + /// if it can be verified as untampered with in transit.</para> /// <para>Since the data set here is sent in the querystring of the request and some /// servers place limits on the size of a request URL, this data should be kept relatively /// small to ensure successful authentication. About 1.5KB is about all that should be stored.</para> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs index cc94de0..fd35a6b 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationResponse.cs @@ -104,27 +104,60 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The value of the argument, or null if the named parameter could not be found. /// </returns> /// <remarks> - /// <para>This may return any argument on the querystring that came with the authentication response, - /// which may include parameters not explicitly added using - /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.</para> - /// <para>Note that these values are NOT protected against tampering in transit.</para> + /// 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 <c>null</c> is always + /// returned since the callback arguments could not be signed to protect against + /// tampering. /// </remarks> string GetCallbackArgument(string key); /// <summary> + /// Gets a callback argument's value that was previously added using + /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>. + /// </summary> + /// <param name="key">The name of the parameter whose value is sought.</param> + /// <returns> + /// The value of the argument, or null if the named parameter could not be found. + /// </returns> + /// <remarks> + /// Callback parameters are only available even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + string GetUntrustedCallbackArgument(string key); + + /// <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> + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Historically an expensive operation.")] + IDictionary<string, string> GetCallbackArguments(); + + /// <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> - /// <para>This MAY return any argument on the querystring that came with the authentication response, - /// which may include parameters not explicitly added using - /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.</para> - /// <para>Note that these values are NOT protected against tampering in transit.</para> + /// Callback parameters are only available even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. /// </remarks> [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Historically an expensive operation.")] - IDictionary<string, string> GetCallbackArguments(); // TODO: change this to a property, and return a cached ReadOnlyDictionary + IDictionary<string, string> GetUntrustedCallbackArguments(); /// <summary> /// Tries to get an OpenID extension that may be present in the response. diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs index e66ac28..5aa2e24 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/NegativeAuthenticationResponse.cs @@ -159,6 +159,24 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> + /// Gets a callback argument's value that was previously added using + /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>. + /// </summary> + /// <param name="key">The name of the parameter whose value is sought.</param> + /// <returns> + /// The value of the argument, or null if the named parameter could not be found. + /// </returns> + /// <remarks> + /// Callback parameters are only available even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public string GetUntrustedCallbackArgument(string key) { + return null; + } + + /// <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. @@ -175,6 +193,22 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <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 even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public IDictionary<string, string> GetUntrustedCallbackArguments() { + return EmptyDictionary<string, string>.Instance; + } + + /// <summary> /// Tries to get an OpenID extension that may be present in the response. /// </summary> /// <typeparam name="T">The type of extension to look for in the response message.</typeparam> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdMobileTextBox.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdMobileTextBox.cs index a56f257..f3539cb 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdMobileTextBox.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdMobileTextBox.cs @@ -635,7 +635,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { var response = this.RelyingParty.GetResponse(); if (response != null) { - string persistentString = response.GetCallbackArgument(UsePersistentCookieCallbackKey); + string persistentString = response.GetUntrustedCallbackArgument(UsePersistentCookieCallbackKey); bool persistentBool; if (persistentString != null && bool.TryParse(persistentString, out persistentBool)) { this.UsePersistentCookie = persistentBool; diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs index 68dd039..1cc69ec 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs @@ -623,7 +623,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { if (response == null) { return; } - string persistentString = response.GetCallbackArgument(UsePersistentCookieCallbackKey); + string persistentString = response.GetUntrustedCallbackArgument(UsePersistentCookieCallbackKey); if (persistentString != null) { this.UsePersistentCookie = (LogOnPersistence)Enum.Parse(typeof(LogOnPersistence), persistentString); } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs index 13eb1a2..baf30da 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs @@ -154,13 +154,32 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </remarks> public string GetCallbackArgument(string key) { if (this.response.ReturnToParametersSignatureValidated) { - return this.response.GetReturnToArgument(key); + return this.GetUntrustedCallbackArgument(key); } else { + Logger.OpenId.WarnFormat(OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name); return null; } } /// <summary> + /// Gets a callback argument's value that was previously added using + /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>. + /// </summary> + /// <param name="key">The name of the parameter whose value is sought.</param> + /// <returns> + /// The value of the argument, or null if the named parameter could not be found. + /// </returns> + /// <remarks> + /// Callback parameters are only available even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public string GetUntrustedCallbackArgument(string key) { + return this.response.GetReturnToArgument(key); + } + + /// <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. @@ -175,22 +194,40 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </remarks> public IDictionary<string, string> GetCallbackArguments() { if (this.response.ReturnToParametersSignatureValidated) { - 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; + return this.GetUntrustedCallbackArguments(); } else { + Logger.OpenId.WarnFormat(OpenIdStrings.CallbackArgumentsRequireSecretStore, typeof(IAssociationStore<Uri>).Name, typeof(OpenIdRelyingParty).Name); return EmptyDictionary<string, string>.Instance; } } /// <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; + } + + /// <summary> /// Tries to get an OpenID extension that may be present in the response. /// </summary> /// <typeparam name="T">The type of extension to look for in the response message.</typeparam> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs index 04a403c..e5bd22f 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs @@ -23,6 +23,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private IDictionary<string, string> callbackArguments; /// <summary> + /// The untrusted callback arguments that came with the authentication response. + /// </summary> + private IDictionary<string, string> untrustedCallbackArguments; + + /// <summary> /// Initializes a new instance of the <see cref="PositiveAuthenticationResponseSnapshot"/> class. /// </summary> /// <param name="copyFrom">The authentication response to copy from.</param> @@ -34,6 +39,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.Status = copyFrom.Status; this.Provider = copyFrom.Provider; this.callbackArguments = copyFrom.GetCallbackArguments(); + this.untrustedCallbackArguments = copyFrom.GetUntrustedCallbackArguments(); } #region IAuthenticationResponse Members @@ -229,6 +235,23 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <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 even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public IDictionary<string, string> GetUntrustedCallbackArguments() { + // Return a copy so that the caller cannot change the contents. + return new Dictionary<string, string>(this.untrustedCallbackArguments); + } + + /// <summary> /// Gets a callback argument's value that was previously added using /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>. /// </summary> @@ -250,6 +273,28 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { return value; } + /// <summary> + /// Gets a callback argument's value that was previously added using + /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>. + /// </summary> + /// <param name="key">The name of the parameter whose value is sought.</param> + /// <returns> + /// The value of the argument, or null if the named parameter could not be found. + /// </returns> + /// <remarks> + /// Callback parameters are only available even if the RP is in stateless mode, + /// or the callback parameters are otherwise unverifiable as untampered with. + /// Therefore, use this method only when the callback argument is not to be + /// used to make a security-sensitive decision. + /// </remarks> + public string GetUntrustedCallbackArgument(string key) { + ErrorUtilities.VerifyArgumentNotNull(key, "key"); + + string value; + this.untrustedCallbackArguments.TryGetValue(key, out value); + return value; + } + #endregion } } |