diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-03-11 20:22:40 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-03-11 20:22:40 -0700 |
commit | 0b7f0bf7f67d1d80c8a8d4ed9ee3ddae50b89e70 (patch) | |
tree | 0498754c0d9959b05d98d274e65f6ef266fcff94 /src | |
parent | 6b055f20dd61a845c4486066601a7f820905ff64 (diff) | |
download | DotNetOpenAuth-0b7f0bf7f67d1d80c8a8d4ed9ee3ddae50b89e70.zip DotNetOpenAuth-0b7f0bf7f67d1d80c8a8d4ed9ee3ddae50b89e70.tar.gz DotNetOpenAuth-0b7f0bf7f67d1d80c8a8d4ed9ee3ddae50b89e70.tar.bz2 |
Added support for classic ASP RPs to use the sreg extension.
Diffstat (limited to 'src')
9 files changed, 209 insertions, 27 deletions
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs index 3444192..7fd3476 100644 --- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs +++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs @@ -246,7 +246,7 @@ namespace DotNetOpenAuth.Test.ChannelElements { HttpMethods = scheme, }; - DirectWebResponse rawResponse = null; + CachedDirectWebResponse rawResponse = null; this.webRequestHandler.Callback = (req) => { Assert.IsNotNull(req); HttpRequestInfo reqInfo = ConvertToRequestInfo(req, this.webRequestHandler.RequestEntityStream); @@ -264,9 +264,8 @@ namespace DotNetOpenAuth.Test.ChannelElements { { "Location", request.Location.AbsoluteUri }, { "Timestamp", XmlConvert.ToString(request.Timestamp, XmlDateTimeSerializationMode.Utc) }, }; - rawResponse = new CachedDirectWebResponse { - Body = MessagingUtilities.CreateQueryString(responseFields), - }; + rawResponse = new CachedDirectWebResponse(); + rawResponse.SetResponse(MessagingUtilities.CreateQueryString(responseFields)); return rawResponse; }; diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 0750cc0..e3e6c0c 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -296,6 +296,7 @@ <Compile Include="OpenId\Identifier.cs" /> <Compile Include="OpenId\IdentifierContract.cs" /> <Compile Include="OpenId\Interop\AuthenticationResponseShim.cs" /> + <Compile Include="OpenId\Interop\ClaimsResponseShim.cs" /> <Compile Include="OpenId\Interop\OpenIdRelyingPartyShim.cs" /> <Compile Include="OpenId\Messages\CheckAuthenticationRequest.cs" /> <Compile Include="OpenId\Messages\CheckAuthenticationResponse.cs" /> @@ -460,4 +461,4 @@ </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" /> -</Project> +</Project>
\ No newline at end of file diff --git a/src/DotNetOpenAuth/Messaging/CachedDirectWebResponse.cs b/src/DotNetOpenAuth/Messaging/CachedDirectWebResponse.cs index c1d2d76..4cf9639 100644 --- a/src/DotNetOpenAuth/Messaging/CachedDirectWebResponse.cs +++ b/src/DotNetOpenAuth/Messaging/CachedDirectWebResponse.cs @@ -15,7 +15,7 @@ namespace DotNetOpenAuth.Messaging { /// <summary> /// Cached details on the response from a direct web request to a remote party. /// </summary> - [DebuggerDisplay("{Status} {ContentType.MediaType}: {Body.Substring(4,50)}")] + [DebuggerDisplay("{Status} {ContentType.MediaType}, length: {ResponseStream.Length}")] internal class CachedDirectWebResponse : DirectWebResponse { /// <summary> /// A seekable, repeatable response stream. @@ -60,14 +60,6 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> - /// Gets or sets the body of the response as a string. - /// </summary> - public string Body { - get { return this.ResponseStream != null ? this.GetResponseReader().ReadToEnd() : null; } - set { this.SetResponse(value); } - } - - /// <summary> /// Gets a value indicating whether the cached response stream was /// truncated to a maximum allowable length. /// </summary> @@ -103,6 +95,21 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Gets the body of the response as a string. + /// </summary> + /// <returns>The entire body of the response.</returns> + internal string GetResponseString() { + if (this.ResponseStream != null) { + StreamReader reader = this.GetResponseReader(); + string value = this.GetResponseReader().ReadToEnd(); + this.ResponseStream.Seek(0, SeekOrigin.Begin); + return value; + } else { + return null; + } + } + + /// <summary> /// Gets an offline snapshot version of this instance. /// </summary> /// <param name="maximumBytesToCache">The maximum bytes from the response stream to cache.</param> diff --git a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs index 827bca2..c8100cf 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs @@ -244,8 +244,7 @@ TimeZone = '{8}'"; /// the OpenId specification for field names, omitting the 'openid.sreg' prefix. /// </param> /// <param name="requestLevel">The none/request/require state of the listed fields.</param> - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by messaging framework via reflection.")] - private void SetProfileRequestFromList(ICollection<string> fieldNames, DemandLevel requestLevel) { + internal void SetProfileRequestFromList(IEnumerable<string> fieldNames, DemandLevel requestLevel) { foreach (string field in fieldNames) { switch (field) { case Constants.nickname: @@ -276,7 +275,7 @@ TimeZone = '{8}'"; this.TimeZone = requestLevel; break; default: - Logger.WarnFormat("OpenIdProfileRequest.SetProfileRequestFromList: Unrecognized field name '{0}'.", field); + Logger.WarnFormat("ClaimsRequest.SetProfileRequestFromList: Unrecognized field name '{0}'.", field); break; } } diff --git a/src/DotNetOpenAuth/OpenId/Interop/AuthenticationResponseShim.cs b/src/DotNetOpenAuth/OpenId/Interop/AuthenticationResponseShim.cs index 79dbdb6..a5926d9 100644 --- a/src/DotNetOpenAuth/OpenId/Interop/AuthenticationResponseShim.cs +++ b/src/DotNetOpenAuth/OpenId/Interop/AuthenticationResponseShim.cs @@ -7,9 +7,11 @@ namespace DotNetOpenAuth.OpenId.Interop { using System; using System.Diagnostics.CodeAnalysis; + using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Web; using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> @@ -17,7 +19,7 @@ namespace DotNetOpenAuth.OpenId.Interop { /// </summary> [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "It's only creatable on the inside. It must be ComVisible for ASP to see it.")] [ComVisible(true), Obsolete("This class acts as a COM Server and should not be called directly from .NET code.")] - public class AuthenticationResponseShim { + public sealed class AuthenticationResponseShim { /// <summary> /// The response read in by the Relying Party. /// </summary> @@ -28,9 +30,14 @@ namespace DotNetOpenAuth.OpenId.Interop { /// </summary> /// <param name="response">The response.</param> internal AuthenticationResponseShim(IAuthenticationResponse response) { + Contract.Requires(response != null); ErrorUtilities.VerifyArgumentNotNull(response, "response"); this.response = response; + var claimsResponse = this.response.GetExtension<ClaimsResponse>(); + if (claimsResponse != null) { + this.ClaimsResponse = new ClaimsResponseShim(claimsResponse); + } } /// <summary> @@ -93,6 +100,11 @@ namespace DotNetOpenAuth.OpenId.Interop { } /// <summary> + /// Gets the Simple Registration response. + /// </summary> + public ClaimsResponseShim ClaimsResponse { get; private set; } + + /// <summary> /// Gets details regarding a failed authentication attempt, if available. /// </summary> public string ExceptionMessage { diff --git a/src/DotNetOpenAuth/OpenId/Interop/ClaimsResponseShim.cs b/src/DotNetOpenAuth/OpenId/Interop/ClaimsResponseShim.cs new file mode 100644 index 0000000..ef5e79d --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/Interop/ClaimsResponseShim.cs @@ -0,0 +1,109 @@ +//----------------------------------------------------------------------- +// <copyright file="ClaimsResponseShim.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Interop { + using System; + using System.Diagnostics.CodeAnalysis; + using System.Diagnostics.Contracts; + using System.Runtime.InteropServices; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + + /// <summary> + /// A struct storing Simple Registration field values describing an + /// authenticating user. + /// </summary> + [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "It's only creatable on the inside. It must be ComVisible for ASP to see it.")] + [ComVisible(true), Obsolete("This class acts as a COM Server and should not be called directly from .NET code.")] + [ContractVerification(true)] + public sealed class ClaimsResponseShim { + /// <summary> + /// The Simple Registration claims response message that this shim wraps. + /// </summary> + private readonly ClaimsResponse response; + + /// <summary> + /// Initializes a new instance of the <see cref="ClaimsResponseShim"/> class. + /// </summary> + /// <param name="response">The Simple Registration response to wrap.</param> + internal ClaimsResponseShim(ClaimsResponse response) + { + Contract.Requires(response != null); + ErrorUtilities.VerifyArgumentNotNull(response, "response"); + + this.response = response; + } + + /// <summary> + /// Gets the nickname the user goes by. + /// </summary> + public string Nickname { + get { return this.response.Nickname; } + } + + /// <summary> + /// Gets the user's email address. + /// </summary> + public string Email { + get { return this.response.Email; } + } + + /// <summary> + /// Gets the full name of a user as a single string. + /// </summary> + public string FullName { + get { return this.response.FullName; } + } + + /// <summary> + /// Gets the raw birth date string given by the extension. + /// </summary> + /// <value>A string in the format yyyy-MM-dd.</value> + public string BirthDate { + get { return this.response.BirthDateRaw; } + } + + /// <summary> + /// Gets the gender of the user. + /// </summary> + public string Gender { + get { + if (this.response.Gender.HasValue) { + return this.response.Gender.Value == Extensions.SimpleRegistration.Gender.Male ? Constants.Genders.Male : Constants.Genders.Female; + } + return null; + } + } + + /// <summary> + /// Gets the zip code / postal code of the user. + /// </summary> + public string PostalCode { + get { return this.response.PostalCode; } + } + + /// <summary> + /// Gets the country of the user. + /// </summary> + public string Country { + get { return this.response.Country; } + } + + /// <summary> + /// Gets the primary/preferred language of the user. + /// </summary> + public string Language { + get { return this.response.Language; } + } + + /// <summary> + /// Gets the user's timezone. + /// </summary> + public string TimeZone { + get { return this.response.TimeZone; } + } + } +}
\ No newline at end of file diff --git a/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs b/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs index 2a76ea5..0f05318 100644 --- a/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs +++ b/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs @@ -12,13 +12,14 @@ namespace DotNetOpenAuth.OpenId.Interop { using System.Text; using System.Web; using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// The COM interface describing the DotNetOpenId functionality available to /// COM client relying parties. /// </summary> - [Guid("00462F34-21BE-456c-B986-B6DDE4DC5CA8")] + [Guid("56BD3DB0-EE0D-4191-ADFC-1F3705CD2636")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IOpenIdRelyingParty { /// <summary> @@ -45,6 +46,26 @@ namespace DotNetOpenAuth.OpenId.Interop { string CreateRequest(string userSuppliedIdentifier, string realm, string returnToUrl); /// <summary> + /// Creates an authentication request to verify that a user controls + /// some given 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="returnToUrl">The URL of the login page, or the page prepared to receive authentication + /// responses from the OpenID Provider.</param> + /// <param name="optionalSreg">A comma-delimited list of simple registration fields to request as optional.</param> + /// <param name="requiredSreg">A comma-delimited list of simple registration fields to request as required.</param> + /// <returns> + /// An authentication request object that describes the HTTP response to + /// send to the user agent to initiate the authentication. + /// </returns> + /// <exception cref="ProtocolException">Thrown if no OpenID endpoint could be found.</exception> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sreg", Justification = "Accepted acronym")] + string CreateRequestWithSimpleRegistration(string userSuppliedIdentifier, string realm, string returnToUrl, string optionalSreg, string requiredSreg); + + /// <summary> /// Gets the result of a user agent's visit to his OpenId provider in an /// authentication attempt. Null if no response is available. /// </summary> @@ -60,11 +81,11 @@ namespace DotNetOpenAuth.OpenId.Interop { /// Implementation of <see cref="IOpenIdRelyingParty"/>, providing a subset of the /// functionality available to .NET clients. /// </summary> - [Guid("4D6FB236-1D66-4311-B761-972C12BB85E8")] + [Guid("8F97A798-B4C5-4da5-9727-EE7DD96A8CD9")] [ProgId("DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty")] [ComVisible(true), Obsolete("This class acts as a COM Server and should not be called directly from .NET code.", true)] [ClassInterface(ClassInterfaceType.None)] - public class OpenIdRelyingPartyShim : IOpenIdRelyingParty { + public sealed class OpenIdRelyingPartyShim : IOpenIdRelyingParty { /// <summary> /// Creates an authentication request to verify that a user controls /// some given Identifier. @@ -89,8 +110,41 @@ namespace DotNetOpenAuth.OpenId.Interop { [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "COM requires primitive types")] public string CreateRequest(string userSuppliedIdentifier, string realm, string returnToUrl) { OpenIdRelyingParty rp = new OpenIdRelyingParty(null); - UserAgentResponse response = rp.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)).RedirectingResponse; - return response.DirectUriRequest.AbsoluteUri; + var request = rp.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)); + return request.RedirectingResponse.DirectUriRequest.AbsoluteUri; + } + + /// <summary> + /// Creates an authentication request to verify that a user controls + /// some given 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="returnToUrl">The URL of the login page, or the page prepared to receive authentication + /// responses from the OpenID Provider.</param> + /// <param name="optionalSreg">A comma-delimited list of simple registration fields to request as optional.</param> + /// <param name="requiredSreg">A comma-delimited list of simple registration fields to request as required.</param> + /// <returns> + /// An authentication request object that describes the HTTP response to + /// send to the user agent to initiate the authentication. + /// </returns> + /// <exception cref="ProtocolException">Thrown if no OpenID endpoint could be found.</exception> + [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "COM requires primitive types")] + public string CreateRequestWithSimpleRegistration(string userSuppliedIdentifier, string realm, string returnToUrl, string optionalSreg, string requiredSreg) { + OpenIdRelyingParty rp = new OpenIdRelyingParty(null); + var request = rp.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)); + + ClaimsRequest sreg = new ClaimsRequest(); + if (!string.IsNullOrEmpty(optionalSreg)) { + sreg.SetProfileRequestFromList(optionalSreg.Split(','), DemandLevel.Request); + } + if (!string.IsNullOrEmpty(requiredSreg)) { + sreg.SetProfileRequestFromList(requiredSreg.Split(','), DemandLevel.Require); + } + request.AddExtension(sreg); + return request.RedirectingResponse.DirectUriRequest.AbsoluteUri; } /// <summary> diff --git a/src/DotNetOpenAuth/Yadis/DiscoveryResult.cs b/src/DotNetOpenAuth/Yadis/DiscoveryResult.cs index 9b77215..90495e2 100644 --- a/src/DotNetOpenAuth/Yadis/DiscoveryResult.cs +++ b/src/DotNetOpenAuth/Yadis/DiscoveryResult.cs @@ -27,11 +27,11 @@ namespace DotNetOpenAuth.Yadis { this.NormalizedUri = initialResponse.FinalUri; if (finalResponse == null) { this.ContentType = initialResponse.ContentType; - this.ResponseText = initialResponse.Body; + this.ResponseText = initialResponse.GetResponseString(); this.IsXrds = ContentType.MediaType == ContentTypes.Xrds; } else { this.ContentType = finalResponse.ContentType; - this.ResponseText = finalResponse.Body; + this.ResponseText = finalResponse.GetResponseString(); this.IsXrds = true; if (initialResponse != finalResponse) { this.YadisLocation = finalResponse.RequestUri; diff --git a/src/DotNetOpenAuth/Yadis/Yadis.cs b/src/DotNetOpenAuth/Yadis/Yadis.cs index 6253aa0..b7d1482 100644 --- a/src/DotNetOpenAuth/Yadis/Yadis.cs +++ b/src/DotNetOpenAuth/Yadis/Yadis.cs @@ -77,7 +77,7 @@ namespace DotNetOpenAuth.Yadis { } } if (url == null && response.ContentType.MediaType == ContentTypes.Html) { - url = FindYadisDocumentLocationInHtmlMetaTags(response.Body); + url = FindYadisDocumentLocationInHtmlMetaTags(response.GetResponseString()); if (url != null) { Logger.DebugFormat("{0} found in HTML Http-Equiv tag. Preparing to pull XRDS from {1}", HeaderName, url); } @@ -158,7 +158,8 @@ namespace DotNetOpenAuth.Yadis { if (response.ContentType.MediaType == ContentTypes.Xml) { // This COULD be an XRDS document with an imprecise content-type. - XmlReader reader = XmlReader.Create(new StringReader(response.Body)); + response.ResponseStream.Seek(0, SeekOrigin.Begin); + XmlReader reader = XmlReader.Create(response.ResponseStream); while (reader.Read() && reader.NodeType != XmlNodeType.Element) { // intentionally blank } |