diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2008-08-25 10:52:28 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2008-08-25 10:52:28 -0700 |
commit | f7ecfb404d0ed190dbbc78d524dc0b942fe01522 (patch) | |
tree | 67bdb7385ecb9014d043f874f123cdfac94f2e5f | |
parent | 9de8bb14896a815939807553df50b51663184fe9 (diff) | |
parent | d2c725d8714b2dac8401b5af269b30b551031968 (diff) | |
download | DotNetOpenAuth-f7ecfb404d0ed190dbbc78d524dc0b942fe01522.zip DotNetOpenAuth-f7ecfb404d0ed190dbbc78d524dc0b942fe01522.tar.gz DotNetOpenAuth-f7ecfb404d0ed190dbbc78d524dc0b942fe01522.tar.bz2 |
Merge branch 'master' into ajax
18 files changed, 198 insertions, 53 deletions
diff --git a/samples/RelyingPartyPortal/loginProgrammatic.aspx.cs b/samples/RelyingPartyPortal/loginProgrammatic.aspx.cs index 24a8b9c..0bec51f 100644 --- a/samples/RelyingPartyPortal/loginProgrammatic.aspx.cs +++ b/samples/RelyingPartyPortal/loginProgrammatic.aspx.cs @@ -51,6 +51,16 @@ public partial class loginProgrammatic : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) {
openIdBox.Focus();
+ // For debugging/testing, we allow remote clearing of all associations...
+ // NOT a good idea on a production site.
+ if (Request.QueryString["clearAssociations"] == "1") {
+ Application.Remove("DotNetOpenId.RelyingParty.RelyingParty.AssociationStore");
+ // Force a redirect now to prevent the user from logging in while associations
+ // are constantly being cleared.
+ UriBuilder builder = new UriBuilder(Request.Url);
+ builder.Query = null;
+ Response.Redirect(builder.Uri.AbsoluteUri);
+ }
OpenIdRelyingParty openid = createRelyingParty();
if (openid.Response != null) {
diff --git a/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs b/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs index 9da4360..fb36e71 100644 --- a/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs +++ b/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs @@ -204,6 +204,7 @@ namespace DotNetOpenId.Test.RelyingParty { string xrds = @"<?xml version='1.0' encoding='UTF-8'?>
<XRD xmlns='xri://$xrd*($v*2.0)'>
<Query>=MultipleEndpoint</Query>
+ <Status cid='verified' code='100' />
<ProviderID>=!91F2.8153.F600.AE24</ProviderID>
<CanonicalID>=!91F2.8153.F600.AE24</CanonicalID>
<Service>
@@ -237,7 +238,6 @@ namespace DotNetOpenId.Test.RelyingParty { </XRD>";
MockHttpRequest.RegisterMockXrdsResponses(new Dictionary<string, string> {
{"https://xri.net/=MultipleEndpoint?_xrd_r=application/xrd%2Bxml;sep=false", xrds},
- {"https://xri.net/=!91F2.8153.F600.AE24?_xrd_r=application/xrd%2Bxml;sep=false", xrds},
});
OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null);
Realm realm = new Realm("http://somerealm");
diff --git a/src/DotNetOpenId.Test/XriIdentifierTests.cs b/src/DotNetOpenId.Test/XriIdentifierTests.cs index 77f65f4..6eaae26 100644 --- a/src/DotNetOpenId.Test/XriIdentifierTests.cs +++ b/src/DotNetOpenId.Test/XriIdentifierTests.cs @@ -359,19 +359,10 @@ uEyb50RJ7DWmXctSC0b3eymZ2lSXxAWNOsNy </XRD>";
MockHttpRequest.RegisterMockXrdsResponses(new Dictionary<string, string> {
{ "https://xri.net/@llli?_xrd_r=application/xrd%2Bxml;sep=false", llliResponse},
- { "https://xri.net/@!72CD.A072.157E.A9C6?_xrd_r=application/xrd%2Bxml;sep=false", llliResponse},
-
{ "https://xri.net/@llli*area?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaResponse},
- { "https://xri.net/@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaResponse},
-
{ "https://xri.net/@llli*area*canada.unattached?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedResponse},
- { "https://xri.net/@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedResponse},
-
{ "https://xri.net/@llli*area*canada.unattached*ada?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedAdaResponse},
- { "https://xri.net/@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedAdaResponse},
-
{ "https://xri.net/=Web?_xrd_r=application/xrd%2Bxml;sep=false", webResponse},
- { "https://xri.net/=!91F2.8153.F600.AE24?_xrd_r=application/xrd%2Bxml;sep=false", webResponse},
});
verifyCanonicalId("@llli", "@!72CD.A072.157E.A9C6");
verifyCanonicalId("@llli*area", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C");
diff --git a/src/DotNetOpenId/HmacShaAssociation.cs b/src/DotNetOpenId/HmacShaAssociation.cs index 107aa1c..daa7c07 100644 --- a/src/DotNetOpenId/HmacShaAssociation.cs +++ b/src/DotNetOpenId/HmacShaAssociation.cs @@ -1,7 +1,6 @@ using System;
-using System.Security.Cryptography;
-using System.Collections.Generic;
using System.Diagnostics;
+using System.Security.Cryptography;
namespace DotNetOpenId {
internal class HmacShaAssociation : Association {
@@ -103,6 +102,24 @@ namespace DotNetOpenId { return false;
}
+ internal static bool IsDHSessionCompatible(Protocol protocol, string associationType, string sessionType) {
+ // Under HTTPS, no DH encryption is required regardless of association type.
+ if (string.Equals(sessionType, protocol.Args.SessionType.NoEncryption, StringComparison.Ordinal)) {
+ return true;
+ }
+ // When there _is_ a DH session, it must match in hash length with the association type.
+ foreach (HmacSha sha in HmacShaAssociationTypes) {
+ if (string.Equals(associationType, sha.GetAssociationType(protocol), StringComparison.Ordinal)) {
+ int hashSizeInBits = sha.SecretLength * 8;
+ string matchingSessionName = DiffieHellmanUtil.GetNameForSize(protocol, hashSizeInBits);
+ if (string.Equals(sessionType, matchingSessionName, StringComparison.Ordinal)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
HmacShaAssociation(HmacSha typeIdentity, string handle, byte[] secret, TimeSpan totalLifeLength)
: base(handle, secret, totalLifeLength, DateTime.UtcNow) {
if (typeIdentity == null) throw new ArgumentNullException("typeIdentity");
diff --git a/src/DotNetOpenId/Protocol.cs b/src/DotNetOpenId/Protocol.cs index 42d5e04..3f0f219 100644 --- a/src/DotNetOpenId/Protocol.cs +++ b/src/DotNetOpenId/Protocol.cs @@ -112,13 +112,21 @@ namespace DotNetOpenId { }
/// <summary>
/// Attempts to detect the right OpenID protocol version based on the contents
- /// of an incoming query string.
+ /// of an incoming OpenID <i>indirect</i> message or <i>direct request</i>.
/// </summary>
internal static Protocol Detect(IDictionary<string, string> Query) {
if (Query == null) throw new ArgumentNullException("Query");
return Query.ContainsKey(v20.openid.ns) ? v20 : v11;
}
/// <summary>
+ /// Attempts to detect the right OpenID protocol version based on the contents
+ /// of an incoming OpenID <i>direct</i> response message.
+ /// </summary>
+ internal static Protocol DetectFromDirectResponse(IDictionary<string, string> Query) {
+ if (Query == null) throw new ArgumentNullException("Query");
+ return Query.ContainsKey(v20.openidnp.ns) ? v20 : v11;
+ }
+ /// <summary>
/// Attemps to detect the highest OpenID protocol version supported given a set
/// of XRDS Service Type URIs included for some service.
/// </summary>
diff --git a/src/DotNetOpenId/RelyingParty/AssociateRequest.cs b/src/DotNetOpenId/RelyingParty/AssociateRequest.cs index 0985770..b2d4751 100644 --- a/src/DotNetOpenId/RelyingParty/AssociateRequest.cs +++ b/src/DotNetOpenId/RelyingParty/AssociateRequest.cs @@ -1,8 +1,8 @@ using System;
using System.Collections.Generic;
-using System.Text;
-using Org.Mentalis.Security.Cryptography;
using System.Diagnostics;
+using System.Globalization;
+using Org.Mentalis.Security.Cryptography;
namespace DotNetOpenId.RelyingParty {
[DebuggerDisplay("Mode: {Args[\"openid.mode\"]}, {Args[\"openid.assoc_type\"]}, OpenId: {Protocol.Version}")]
@@ -28,7 +28,7 @@ namespace DotNetOpenId.RelyingParty { if (HmacShaAssociation.TryFindBestAssociation(provider.Protocol,
relyingParty.Settings.MinimumHashBitLength, relyingParty.Settings.MaximumHashBitLength,
true, out assoc_type, out session_type)) {
- return Create(relyingParty, provider, assoc_type, session_type);
+ return Create(relyingParty, provider, assoc_type, session_type, true);
} else {
// There are no associations that meet all requirements.
Logger.Warn("Security requirements and protocol combination knock out all possible association types. Dumb mode forced.");
@@ -36,7 +36,7 @@ namespace DotNetOpenId.RelyingParty { }
}
- public static AssociateRequest Create(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, string assoc_type, string session_type) {
+ public static AssociateRequest Create(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, string assoc_type, string session_type, bool allowNoSession) {
if (relyingParty == null) throw new ArgumentNullException("relyingParty");
if (provider == null) throw new ArgumentNullException("provider");
if (assoc_type == null) throw new ArgumentNullException("assoc_type");
@@ -44,6 +44,11 @@ namespace DotNetOpenId.RelyingParty { Debug.Assert(Array.IndexOf(provider.Protocol.Args.SignatureAlgorithm.All, assoc_type) >= 0);
Debug.Assert(Array.IndexOf(provider.Protocol.Args.SessionType.All, session_type) >= 0);
+ if (!HmacShaAssociation.IsDHSessionCompatible(provider.Protocol, assoc_type, session_type)) {
+ throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
+ Strings.IncompatibleAssociationAndSessionTypes, assoc_type, session_type));
+ }
+
var args = new Dictionary<string, string>();
Protocol protocol = provider.Protocol;
@@ -52,7 +57,7 @@ namespace DotNetOpenId.RelyingParty { DiffieHellman dh = null;
- if (provider.ProviderEndpoint.Scheme == Uri.UriSchemeHttps) {
+ if (provider.ProviderEndpoint.Scheme == Uri.UriSchemeHttps && allowNoSession) {
Logger.InfoFormat("Requesting association with {0} (assoc_type = '{1}', session_type = '{2}').",
provider.ProviderEndpoint, assoc_type, protocol.Args.SessionType.NoEncryption);
args.Add(protocol.openid.session_type, protocol.Args.SessionType.NoEncryption);
diff --git a/src/DotNetOpenId/RelyingParty/AssociateResponse.cs b/src/DotNetOpenId/RelyingParty/AssociateResponse.cs index 5b17473..c555f8c 100644 --- a/src/DotNetOpenId/RelyingParty/AssociateResponse.cs +++ b/src/DotNetOpenId/RelyingParty/AssociateResponse.cs @@ -23,7 +23,7 @@ namespace DotNetOpenId.RelyingParty { if (Array.IndexOf(Protocol.Args.SignatureAlgorithm.All, assoc_type) >= 0 &&
Array.IndexOf(Protocol.Args.SessionType.All, session_type) >= 0 &&
RelyingParty.Settings.IsAssociationInPermittedRange(Protocol, assoc_type)) {
- SecondAttempt = AssociateRequest.Create(RelyingParty, Provider, assoc_type, session_type);
+ SecondAttempt = AssociateRequest.Create(RelyingParty, Provider, assoc_type, session_type, false);
}
}
}
diff --git a/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs index 8d740ef..fccd786 100644 --- a/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs +++ b/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs @@ -199,17 +199,17 @@ namespace DotNetOpenId.RelyingParty { if (assoc != null) {
if (!string.Equals(
req.Args[provider.Protocol.openid.assoc_type],
- req.Response.Args[provider.Protocol.openidnp.assoc_type],
+ Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.assoc_type),
StringComparison.Ordinal) ||
!string.Equals(
req.Args[provider.Protocol.openid.session_type],
- req.Response.Args[provider.Protocol.openidnp.session_type],
+ Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.session_type),
StringComparison.Ordinal)) {
Logger.ErrorFormat("Provider responded with contradicting association parameters. Requested [{0}, {1}] but got [{2}, {3}] back.",
req.Args[provider.Protocol.openid.assoc_type],
req.Args[provider.Protocol.openid.session_type],
- req.Response.Args[provider.Protocol.openidnp.assoc_type],
- req.Response.Args[provider.Protocol.openidnp.session_type]);
+ Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.assoc_type),
+ Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.session_type));
assoc = null;
}
diff --git a/src/DotNetOpenId/RelyingParty/DirectMessageHttpChannel.cs b/src/DotNetOpenId/RelyingParty/DirectMessageHttpChannel.cs index 960cd6d..781228d 100644 --- a/src/DotNetOpenId/RelyingParty/DirectMessageHttpChannel.cs +++ b/src/DotNetOpenId/RelyingParty/DirectMessageHttpChannel.cs @@ -15,6 +15,7 @@ namespace DotNetOpenId.RelyingParty { byte[] body = ProtocolMessages.Http.GetBytes(fields);
IDictionary<string, string> args;
UntrustedWebResponse resp = null;
+ string fullResponseText = null;
try {
resp = UntrustedWebRequest.Request(provider.ProviderEndpoint, body);
// If an internal server error occurred, there won't be any KV-form stream
@@ -25,10 +26,15 @@ namespace DotNetOpenId.RelyingParty { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
Strings.ProviderRespondedWithError, errorStream));
}
+ if (Logger.IsDebugEnabled) {
+ fullResponseText = resp.ReadResponseString();
+ }
args = ProtocolMessages.KeyValueForm.GetDictionary(resp.ResponseStream);
Logger.DebugFormat("Received direct response from {0}: {1}{2}", provider.ProviderEndpoint,
Environment.NewLine, Util.ToString(args));
} catch (ArgumentException e) {
+ Logger.DebugFormat("Full response from provider (where KVF was expected):{0}{1}",
+ Environment.NewLine, fullResponseText);
throw new OpenIdException("Failure decoding Key-Value Form response from provider.", e);
} catch (WebException e) {
throw new OpenIdException("Failure while connecting to provider.", e);
diff --git a/src/DotNetOpenId/RelyingParty/DirectResponse.cs b/src/DotNetOpenId/RelyingParty/DirectResponse.cs index 300898b..09e49c8 100644 --- a/src/DotNetOpenId/RelyingParty/DirectResponse.cs +++ b/src/DotNetOpenId/RelyingParty/DirectResponse.cs @@ -18,11 +18,12 @@ namespace DotNetOpenId.RelyingParty { // Make sure that the OP fulfills the required OpenID version.
// We don't use Provider.Protocol here because that's just a cache of
// what we _thought_ the OP would support, and our purpose is to double-check this.
- if (Protocol.Detect(args).ProtocolVersion < relyingParty.Settings.MinimumRequiredOpenIdVersion) {
+ ProtocolVersion detectedProtocol = Protocol.DetectFromDirectResponse(args).ProtocolVersion;
+ if (detectedProtocol < relyingParty.Settings.MinimumRequiredOpenIdVersion) {
throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
Strings.MinimumOPVersionRequirementNotMet,
Protocol.Lookup(relyingParty.Settings.MinimumRequiredOpenIdVersion).Version,
- provider.Protocol.Version));
+ Protocol.Lookup(detectedProtocol).Version));
}
if (Logger.IsErrorEnabled) {
diff --git a/src/DotNetOpenId/RelyingParty/IXrdsProviderEndpoint.cs b/src/DotNetOpenId/RelyingParty/IXrdsProviderEndpoint.cs index bc25747..78c873f 100644 --- a/src/DotNetOpenId/RelyingParty/IXrdsProviderEndpoint.cs +++ b/src/DotNetOpenId/RelyingParty/IXrdsProviderEndpoint.cs @@ -8,6 +8,10 @@ namespace DotNetOpenId.RelyingParty { [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xrds")]
public interface IXrdsProviderEndpoint : IProviderEndpoint {
/// <summary>
+ /// Checks for the presence of a given Type URI in an XRDS service.
+ /// </summary>
+ bool IsTypeUriPresent(string typeUri);
+ /// <summary>
/// Gets the priority associated with this service that may have been given
/// in the XRDS document.
/// </summary>
diff --git a/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs index 3e46a59..ef96ffd 100644 --- a/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs +++ b/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs @@ -325,10 +325,13 @@ namespace DotNetOpenId.RelyingParty { [EditorBrowsable(EditorBrowsableState.Advanced)]
public static Comparison<IXrdsProviderEndpoint> DefaultEndpointOrder {
get {
- // Sort first by Service/@priority, then by Service/Uri/@priority
+ // Sort first by service type (OpenID 2.0, 1.1, 1.0),
+ // then by Service/@priority, then by Service/Uri/@priority
return (se1, se2) => {
+ int result = getEndpointPrecedenceOrderByServiceType(se1).CompareTo(getEndpointPrecedenceOrderByServiceType(se2));
+ if (result != 0) return result;
if (se1.ServicePriority.HasValue && se2.ServicePriority.HasValue) {
- int result = se1.ServicePriority.Value.CompareTo(se2.ServicePriority.Value);
+ result = se1.ServicePriority.Value.CompareTo(se2.ServicePriority.Value);
if (result != 0) return result;
if (se1.UriPriority.HasValue && se2.UriPriority.HasValue) {
return se1.UriPriority.Value.CompareTo(se2.UriPriority.Value);
@@ -361,6 +364,24 @@ namespace DotNetOpenId.RelyingParty { }
}
+ static double getEndpointPrecedenceOrderByServiceType(IXrdsProviderEndpoint endpoint) {
+ // The numbers returned from this method only need to compare against other numbers
+ // from this method, which makes them arbitrary but relational to only others here.
+ if (endpoint.IsTypeUriPresent(Protocol.v20.OPIdentifierServiceTypeURI)) {
+ return 0;
+ }
+ if (endpoint.IsTypeUriPresent(Protocol.v20.ClaimedIdentifierServiceTypeURI)) {
+ return 1;
+ }
+ if (endpoint.IsTypeUriPresent(Protocol.v11.ClaimedIdentifierServiceTypeURI)) {
+ return 2;
+ }
+ if (endpoint.IsTypeUriPresent(Protocol.v10.ClaimedIdentifierServiceTypeURI)) {
+ return 3;
+ }
+ return 10;
+ }
+
/// <summary>
/// Provides a way to optionally filter the providers that may be used in authenticating a user.
/// </summary>
diff --git a/src/DotNetOpenId/RelyingParty/ServiceEndpoint.cs b/src/DotNetOpenId/RelyingParty/ServiceEndpoint.cs index ea0e23f..7cafbea 100644 --- a/src/DotNetOpenId/RelyingParty/ServiceEndpoint.cs +++ b/src/DotNetOpenId/RelyingParty/ServiceEndpoint.cs @@ -162,6 +162,10 @@ namespace DotNetOpenId.RelyingParty { }
}
+ public bool IsTypeUriPresent(string typeUri) {
+ return IsExtensionSupported(typeUri);
+ }
+
public bool IsExtensionSupported(string extensionUri) {
if (ProviderSupportedServiceTypeUris == null)
throw new InvalidOperationException("Cannot lookup extension support on a rehydrated ServiceEndpoint.");
diff --git a/src/DotNetOpenId/Strings.Designer.cs b/src/DotNetOpenId/Strings.Designer.cs index 0bd9784..3ab0f8d 100644 --- a/src/DotNetOpenId/Strings.Designer.cs +++ b/src/DotNetOpenId/Strings.Designer.cs @@ -88,6 +88,15 @@ namespace DotNetOpenId { }
/// <summary>
+ /// Looks up a localized string similar to XRI CanonicalID verification failed..
+ /// </summary>
+ internal static string CIDVerificationFailed {
+ get {
+ return ResourceManager.GetString("CIDVerificationFailed", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The ClaimedIdentifier property must be set first..
/// </summary>
internal static string ClaimedIdentifierMustBeSetFirst {
@@ -223,6 +232,15 @@ namespace DotNetOpenId { }
/// <summary>
+ /// Looks up a localized string similar to The Provider requested association type '{0}' and session type '{1}', which are not compatible with each other..
+ /// </summary>
+ internal static string IncompatibleAssociationAndSessionTypes {
+ get {
+ return ResourceManager.GetString("IncompatibleAssociationAndSessionTypes", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Inconsistent setting of application state. Authentication request was sent with application state available, but authentication response was received without it available. This makes it impossible to validate the token's signature and will cause assertion verification failure..
/// </summary>
internal static string InconsistentAppState {
@@ -603,5 +621,23 @@ namespace DotNetOpenId { return ResourceManager.GetString("WebRequestFailed", resourceCulture);
}
}
+
+ /// <summary>
+ /// Looks up a localized string similar to XRI resolution failed..
+ /// </summary>
+ internal static string XriResolutionFailed {
+ get {
+ return ResourceManager.GetString("XriResolutionFailed", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Could not find XRI resolution Status tag or code attribute was invalid..
+ /// </summary>
+ internal static string XriResolutionStatusMissing {
+ get {
+ return ResourceManager.GetString("XriResolutionStatusMissing", resourceCulture);
+ }
+ }
}
}
diff --git a/src/DotNetOpenId/Strings.resx b/src/DotNetOpenId/Strings.resx index 48577ac..b894015 100644 --- a/src/DotNetOpenId/Strings.resx +++ b/src/DotNetOpenId/Strings.resx @@ -126,6 +126,9 @@ <data name="BadAssociationPrivateData" xml:space="preserve">
<value>The private data supplied does not meet the requirements of any known Association type. Its length may be too short, or it may have been corrupted.</value>
</data>
+ <data name="CIDVerificationFailed" xml:space="preserve">
+ <value>XRI CanonicalID verification failed.</value>
+ </data>
<data name="ClaimedIdentifierMustBeSetFirst" xml:space="preserve">
<value>The ClaimedIdentifier property must be set first.</value>
</data>
@@ -171,6 +174,9 @@ <data name="IdentifierSelectRequiresMatchingIdentifiers" xml:space="preserve">
<value>ClaimedIdentifier and LocalIdentifier must be the same when IsIdentifierSelect is true.</value>
</data>
+ <data name="IncompatibleAssociationAndSessionTypes" xml:space="preserve">
+ <value>The Provider requested association type '{0}' and session type '{1}', which are not compatible with each other.</value>
+ </data>
<data name="InconsistentAppState" xml:space="preserve">
<value>Inconsistent setting of application state. Authentication request was sent with application state available, but authentication response was received without it available. This makes it impossible to validate the token's signature and will cause assertion verification failure.</value>
</data>
@@ -301,4 +307,10 @@ Discovered endpoint info: <data name="WebRequestFailed" xml:space="preserve">
<value>Web request to '{0}' failed.</value>
</data>
+ <data name="XriResolutionFailed" xml:space="preserve">
+ <value>XRI resolution failed.</value>
+ </data>
+ <data name="XriResolutionStatusMissing" xml:space="preserve">
+ <value>Could not find XRI resolution Status tag or code attribute was invalid.</value>
+ </data>
</root>
\ No newline at end of file diff --git a/src/DotNetOpenId/XriIdentifier.cs b/src/DotNetOpenId/XriIdentifier.cs index 9b49f87..51072d4 100644 --- a/src/DotNetOpenId/XriIdentifier.cs +++ b/src/DotNetOpenId/XriIdentifier.cs @@ -22,7 +22,7 @@ namespace DotNetOpenId { if (requireSsl) {
// Indicate to xri.net that we require SSL to be used for delegated resolution
// of community i-names.
- xriResolverProxy += "&ssl=true";
+ xriResolverProxy += ";https=true";
}
OriginalXri = xri;
CanonicalXri = canonicalizeXri(xri);
@@ -52,6 +52,7 @@ namespace DotNetOpenId { /// Takes any valid form of XRI string and returns the canonical form of the same XRI.
/// </summary>
static string canonicalizeXri(string xri) {
+ xri = xri.Trim();
if (xri.StartsWith(xriScheme, StringComparison.OrdinalIgnoreCase))
xri = xri.Substring(xriScheme.Length);
return xri;
@@ -81,11 +82,15 @@ namespace DotNetOpenId { XrdsDocument downloadXrds() {
var xrdsResponse = UntrustedWebRequest.Request(XrdsUrl);
- return new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream));
+ XrdsDocument doc = new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream));
+ if (!doc.IsXrdResolutionSuccessful) {
+ throw new OpenIdException(Strings.XriResolutionFailed);
+ }
+ return doc;
}
internal override IEnumerable<ServiceEndpoint> Discover() {
- return downloadXrds().CreateServiceEndpoints(this, this);
+ return downloadXrds().CreateServiceEndpoints(this);
}
/// <summary>
@@ -93,7 +98,7 @@ namespace DotNetOpenId { /// instances that treat another given identifier as the user-supplied identifier.
/// </summary>
internal IEnumerable<ServiceEndpoint> Discover(XriIdentifier userSuppliedIdentifier) {
- return downloadXrds().CreateServiceEndpoints(this, userSuppliedIdentifier);
+ return downloadXrds().CreateServiceEndpoints(userSuppliedIdentifier);
}
internal override Identifier TrimFragment() {
diff --git a/src/DotNetOpenId/Yadis/XrdElement.cs b/src/DotNetOpenId/Yadis/XrdElement.cs index d690298..5665f58 100644 --- a/src/DotNetOpenId/Yadis/XrdElement.cs +++ b/src/DotNetOpenId/Yadis/XrdElement.cs @@ -22,6 +22,28 @@ namespace DotNetOpenId.Yadis { }
}
+
+ int XriResolutionStatusCode {
+ get {
+ var n = Node.SelectSingleNode("xrd:Status", XmlNamespaceResolver);
+ string codeString;
+ if (n == null || string.IsNullOrEmpty(codeString = n.GetAttribute("code", ""))) {
+ throw new OpenIdException(Strings.XriResolutionStatusMissing);
+ }
+ int code;
+ if (!int.TryParse(codeString, out code) || code < 100 || code > 399) {
+ throw new OpenIdException(Strings.XriResolutionStatusMissing);
+ }
+ return code;
+ }
+ }
+
+ public bool IsXriResolutionSuccessful {
+ get {
+ return XriResolutionStatusCode == 100;
+ }
+ }
+
public string CanonicalID {
get {
var n = Node.SelectSingleNode("xrd:CanonicalID", XmlNamespaceResolver);
@@ -29,6 +51,13 @@ namespace DotNetOpenId.Yadis { }
}
+ public bool IsCanonicalIdVerified {
+ get {
+ var n = Node.SelectSingleNode("xrd:Status", XmlNamespaceResolver);
+ return n != null && string.Equals(n.GetAttribute("cid", ""), "verified", StringComparison.Ordinal);
+ }
+ }
+
IEnumerable<ServiceElement> searchForServiceTypeUris(Util.Func<Protocol, string> p) {
var xpath = new StringBuilder();
xpath.Append("xrd:Service[");
diff --git a/src/DotNetOpenId/Yadis/XrdsDocument.cs b/src/DotNetOpenId/Yadis/XrdsDocument.cs index 7fe7feb..88966b3 100644 --- a/src/DotNetOpenId/Yadis/XrdsDocument.cs +++ b/src/DotNetOpenId/Yadis/XrdsDocument.cs @@ -46,13 +46,13 @@ namespace DotNetOpenId.Yadis { return endpoints;
}
- internal IEnumerable<ServiceEndpoint> CreateServiceEndpoints(XriIdentifier discoveredIdentifier, XriIdentifier userSuppliedIdentifier) {
+ internal IEnumerable<ServiceEndpoint> CreateServiceEndpoints(XriIdentifier userSuppliedIdentifier) {
List<ServiceEndpoint> endpoints = new List<ServiceEndpoint>();
endpoints.AddRange(generateOPIdentifierServiceEndpoints(userSuppliedIdentifier));
// If any OP Identifier service elements were found, we must not proceed
// to return any Claimed Identifier services.
if (endpoints.Count == 0) {
- endpoints.AddRange(generateClaimedIdentifierServiceEndpoints(discoveredIdentifier, userSuppliedIdentifier));
+ endpoints.AddRange(generateClaimedIdentifierServiceEndpoints(userSuppliedIdentifier));
}
return endpoints;
}
@@ -78,7 +78,7 @@ namespace DotNetOpenId.Yadis { }
}
- IEnumerable<ServiceEndpoint> generateClaimedIdentifierServiceEndpoints(XriIdentifier claimedIdentifier, XriIdentifier userSuppliedIdentifier) {
+ IEnumerable<ServiceEndpoint> generateClaimedIdentifierServiceEndpoints(XriIdentifier userSuppliedIdentifier) {
foreach (var service in findClaimedIdentifierServices()) {
foreach (var uri in service.UriElements) {
// spec section 7.3.2.3 on Claimed Id -> CanonicalID substitution
@@ -86,24 +86,11 @@ namespace DotNetOpenId.Yadis { Logger.WarnFormat(Strings.MissingCanonicalIDElement, userSuppliedIdentifier);
break; // skip on to next service
}
- // In the case of XRI names, the ClaimedId is actually the CanonicalID.
- // Per http://dev.inames.net/wiki/XRI_CanonicalID_Verification as of 6/20/08,
- // we need to perform CanonicalId verification when using xri.net as our proxy resolver
- // to protect ourselves against a security vulnerability.
- // We do this by asking the proxy to resolve again, based on the CanonicalId that we
- // just got from the XRI i-name. We SHOULD get the same document back, but in case
- // of the attack it would be a different document, and the second document would be
- // the reliable one.
- if (performCIDVerification && claimedIdentifier != service.Xrd.CanonicalID) {
- Logger.InfoFormat("Performing XRI CanonicalID verification on user supplied identifier {0}, canonical id {1}.", userSuppliedIdentifier, service.Xrd.CanonicalID);
- XriIdentifier canonicalId = new XriIdentifier(service.Xrd.CanonicalID);
- foreach (var endpoint in canonicalId.Discover(userSuppliedIdentifier)) {
- yield return endpoint;
- }
- yield break;
- } else {
- claimedIdentifier = new XriIdentifier(service.Xrd.CanonicalID);
+ if (!service.Xrd.IsCanonicalIdVerified) {
+ throw new OpenIdException(Strings.CIDVerificationFailed, userSuppliedIdentifier);
}
+ // In the case of XRI names, the ClaimedId is actually the CanonicalID.
+ var claimedIdentifier = new XriIdentifier(service.Xrd.CanonicalID);
yield return ServiceEndpoint.CreateForClaimedIdentifier(
claimedIdentifier, userSuppliedIdentifier, service.ProviderLocalIdentifier,
uri.Uri, service.TypeElementUris, service.Priority, uri.Priority);
@@ -111,8 +98,6 @@ namespace DotNetOpenId.Yadis { }
}
- const bool performCIDVerification = true;
-
internal IEnumerable<RelyingPartyReceivingEndpoint> FindRelyingPartyReceivingEndpoints() {
foreach (var service in findReturnToServices()) {
foreach (var uri in service.UriElements) {
@@ -148,5 +133,16 @@ namespace DotNetOpenId.Yadis { }
}
}
+
+ internal bool IsXrdResolutionSuccessful {
+ get {
+ foreach (var xrd in XrdElements) {
+ if (!xrd.IsXriResolutionSuccessful) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
}
}
|