/// <summary> /// Analyzes an incoming request message payload to discover what kind of /// message is embedded in it and returns the type, or null if no match is found. /// </summary> /// <param name="request">The message that was sent as a request that resulted in the response.</param> /// <param name="fields">The name/value pairs that make up the message payload.</param> /// <returns> /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can /// deserialize to. Null if the request isn't recognized as a valid protocol message. /// </returns> public IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary <string, string> fields) { DirectResponseBase message = null; // Discern the OpenID version of the message. Protocol protocol = Protocol.V11; string ns; if (fields.TryGetValue(Protocol.V20.openidnp.ns, out ns)) { ErrorUtilities.VerifyProtocol(string.Equals(ns, Protocol.OpenId2Namespace, StringComparison.Ordinal), MessagingStrings.UnexpectedMessagePartValue, Protocol.V20.openidnp.ns, ns); protocol = Protocol.V20; } // Handle error messages generally. if (fields.ContainsKey(protocol.openidnp.error)) { message = new DirectErrorResponse(protocol.Version, request); } var associateRequest = request as AssociateRequest; if (associateRequest != null) { if (protocol.Version.Major >= 2 && fields.ContainsKey(protocol.openidnp.error_code)) { // This is a special recognized error case that we create a special message for. message = new AssociateUnsuccessfulResponse(protocol.Version, associateRequest); } else if (message == null) { var associateDiffieHellmanRequest = request as AssociateDiffieHellmanRequest; var associateUnencryptedRequest = request as AssociateUnencryptedRequest; if (associateDiffieHellmanRequest != null) { message = new AssociateDiffieHellmanResponse(protocol.Version, associateDiffieHellmanRequest); } if (associateUnencryptedRequest != null) { message = new AssociateUnencryptedResponse(protocol.Version, associateUnencryptedRequest); } } } var checkAuthenticationRequest = request as CheckAuthenticationRequest; if (checkAuthenticationRequest != null && message == null) { message = new CheckAuthenticationResponse(protocol.Version, checkAuthenticationRequest); } if (message != null) { message.SetAsIncoming(); } return(message); }
public override void SetUp() { base.SetUp(); var request = new AssociateUnencryptedRequest(Protocol.V20.Version, new Uri("http://host")); this.response = new AssociateUnsuccessfulResponse(request.Version, request); }
public void RPOnlyRenegotiatesOnce() { Protocol protocol = Protocol.V20; OpenIdCoordinator coordinator = new OpenIdCoordinator( rp => { var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version)); Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves."); }, op => { // Receive initial request. var request = op.Channel.ReadFromRequest <AssociateRequest>(); // Send a renegotiate response AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1; renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA1; op.Channel.Respond(renegotiateResponse); // Receive second-try request = op.Channel.ReadFromRequest <AssociateRequest>(); // Send ANOTHER renegotiate response, at which point the DNOI RP should give up. renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256; renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256; op.Channel.Respond(renegotiateResponse); }); coordinator.Run(); }
public void AssociateRenegotiateBitLength() { Protocol protocol = Protocol.V20; // The strategy is to make a simple request of the RP to establish an association, // and to more carefully observe the Provider-side of things to make sure that both // the OP and RP are behaving as expected. OpenIdCoordinator coordinator = new OpenIdCoordinator( rp => { var opDescription = new ProviderEndpointDescription(OPUri, protocol.Version); Association association = rp.AssociationManager.GetOrCreateAssociation(opDescription); Assert.IsNotNull(association, "Association failed to be created."); Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA1, association.GetAssociationType(protocol)); }, op => { op.SecuritySettings.MaximumHashBitLength = 160; // Force OP to reject HMAC-SHA256 // Receive initial request for an HMAC-SHA256 association. AutoResponsiveRequest req = (AutoResponsiveRequest)op.GetRequest(); AutoResponsiveRequest_Accessor reqAccessor = AutoResponsiveRequest_Accessor.AttachShadow(req); AssociateRequest associateRequest = (AssociateRequest)reqAccessor.RequestMessage; Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA256, associateRequest.AssociationType); // Ensure that the response is a suggestion that the RP try again with HMAC-SHA1 AssociateUnsuccessfulResponse renegotiateResponse = (AssociateUnsuccessfulResponse)reqAccessor.ResponseMessage; Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA1, renegotiateResponse.AssociationType); op.SendResponse(req); // Receive second attempt request for an HMAC-SHA1 association. req = (AutoResponsiveRequest)op.GetRequest(); reqAccessor = AutoResponsiveRequest_Accessor.AttachShadow(req); associateRequest = (AssociateRequest)reqAccessor.RequestMessage; Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA1, associateRequest.AssociationType); // Ensure that the response is a success response. AssociateSuccessfulResponse successResponse = (AssociateSuccessfulResponse)reqAccessor.ResponseMessage; Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA1, successResponse.AssociationType); op.SendResponse(req); }); coordinator.Run(); }
public async Task RPRejectsMismatchingAssociationAndSessionBitLengths() { Protocol protocol = Protocol.V20; this.HandleProvider( async(op, req) => { // Receive initial request. var request = await op.Channel.ReadFromRequestAsync <AssociateRequest>(req, CancellationToken.None); // Send a mismatched response AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1; renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256; return(await op.Channel.PrepareResponseAsync(renegotiateResponse)); }); var rp = this.CreateRelyingParty(); var association = await rp.AssociationManager.GetOrCreateAssociationAsync(new ProviderEndpointDescription(OPUri, protocol.Version), CancellationToken.None); Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves."); }
public async Task RPRejectsUnrecognizedAssociationType() { Protocol protocol = Protocol.V20; HandleProvider( async(op, req) => { // Receive initial request. var request = await op.Channel.ReadFromRequestAsync <AssociateRequest>(req, CancellationToken.None); // Send a response that suggests a foreign association type. var renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = "HMAC-UNKNOWN"; renegotiateResponse.SessionType = "DH-UNKNOWN"; return(await op.Channel.PrepareResponseAsync(renegotiateResponse)); }); var rp = this.CreateRelyingParty(); var association = await rp.AssociationManager.GetOrCreateAssociationAsync(new ProviderEndpointDescription(OPUri, protocol.Version), CancellationToken.None); Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves."); }
public void RPRejectsMismatchingAssociationAndSessionBitLengths() { Protocol protocol = Protocol.V20; OpenIdCoordinator coordinator = new OpenIdCoordinator( rp => { var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version)); Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves."); }, op => { // Receive initial request. var request = op.Channel.ReadFromRequest <AssociateRequest>(); // Send a mismatched response AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1; renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256; op.Channel.Respond(renegotiateResponse); }); coordinator.Run(); }
public void RPRejectsUnrecognizedAssociationType() { Protocol protocol = Protocol.V20; OpenIdCoordinator coordinator = new OpenIdCoordinator( rp => { var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version)); Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves."); }, op => { // Receive initial request. var request = op.Channel.ReadFromRequest <AssociateRequest>(); // Send a response that suggests a foreign association type. AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = "HMAC-UNKNOWN"; renegotiateResponse.SessionType = "DH-UNKNOWN"; op.Channel.Respond(renegotiateResponse); }); coordinator.Run(); }
public async Task RPOnlyRenegotiatesOnce() { Protocol protocol = Protocol.V20; int opStep = 0; HandleProvider( async(op, req) => { switch (++opStep) { case 1: // Receive initial request. var request = await op.Channel.ReadFromRequestAsync <AssociateRequest>(req, CancellationToken.None); // Send a renegotiate response var renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1; renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA1; return(await op.Channel.PrepareResponseAsync(renegotiateResponse, CancellationToken.None)); case 2: // Receive second-try request = await op.Channel.ReadFromRequestAsync <AssociateRequest>(req, CancellationToken.None); // Send ANOTHER renegotiate response, at which point the DNOI RP should give up. renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request); renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256; renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256; return(await op.Channel.PrepareResponseAsync(renegotiateResponse, CancellationToken.None)); default: throw Assumes.NotReachable(); } }); var rp = this.CreateRelyingParty(); var association = await rp.AssociationManager.GetOrCreateAssociationAsync(new ProviderEndpointDescription(OPUri, protocol.Version), CancellationToken.None); Assert.IsNull(association, "The RP should quietly give up when the OP misbehaves."); }
/// <summary> /// Runs a parameterized association flow test. /// </summary> /// <param name="opDescription"> /// The description of the Provider that the relying party uses to formulate the request. /// The specific host is not used, but the scheme is significant. /// </param> /// <param name="expectedAssociationType"> /// The value of the openid.assoc_type parameter expected, /// or null if a failure is anticipated. /// </param> private void ParameterizedAssociationTest( ProviderEndpointDescription opDescription, string expectedAssociationType) { Protocol protocol = Protocol.Lookup(Protocol.Lookup(opDescription.Version).ProtocolVersion); bool expectSuccess = expectedAssociationType != null; bool expectDiffieHellman = !opDescription.Uri.IsTransportSecure(); Association rpAssociation = null, opAssociation; AssociateSuccessfulResponse associateSuccessfulResponse = null; AssociateUnsuccessfulResponse associateUnsuccessfulResponse = null; OpenIdCoordinator coordinator = new OpenIdCoordinator( rp => { rp.SecuritySettings = this.RelyingPartySecuritySettings; rpAssociation = rp.AssociationManager.GetOrCreateAssociation(opDescription); }, op => { op.SecuritySettings = this.ProviderSecuritySettings; IRequest req = op.GetRequest(); Assert.IsNotNull(req, "Expected incoming request but did not receive it."); Assert.IsTrue(req.IsResponseReady); op.Respond(req); }); coordinator.IncomingMessageFilter = message => { Assert.AreSame(opDescription.Version, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, Protocol.Lookup(opDescription.Version).ProtocolVersion); var associateSuccess = message as AssociateSuccessfulResponse; var associateFailed = message as AssociateUnsuccessfulResponse; if (associateSuccess != null) { associateSuccessfulResponse = associateSuccess; } if (associateFailed != null) { associateUnsuccessfulResponse = associateFailed; } }; coordinator.OutgoingMessageFilter = message => { Assert.AreEqual(opDescription.Version, message.Version, "The message was for version {0} but was expected to be for {1}.", message.Version, opDescription.Version); }; coordinator.Run(); if (expectSuccess) { Assert.IsNotNull(rpAssociation); Association actual = coordinator.RelyingParty.AssociationManager.AssociationStoreTestHook.GetAssociation(opDescription.Uri, rpAssociation.Handle); Assert.AreEqual(rpAssociation, actual); opAssociation = coordinator.Provider.AssociationStore.Deserialize(new TestSignedDirectedMessage(), false, rpAssociation.Handle); Assert.IsNotNull(opAssociation, "The Provider could not decode the association handle."); Assert.AreEqual(opAssociation.Handle, rpAssociation.Handle); Assert.AreEqual(expectedAssociationType, rpAssociation.GetAssociationType(protocol)); Assert.AreEqual(expectedAssociationType, opAssociation.GetAssociationType(protocol)); Assert.IsTrue(Math.Abs(opAssociation.SecondsTillExpiration - rpAssociation.SecondsTillExpiration) < 60); Assert.IsTrue(MessagingUtilities.AreEquivalent(opAssociation.SecretKey, rpAssociation.SecretKey)); if (expectDiffieHellman) { Assert.IsInstanceOf <AssociateDiffieHellmanResponse>(associateSuccessfulResponse); var diffieHellmanResponse = (AssociateDiffieHellmanResponse)associateSuccessfulResponse; Assert.IsFalse(MessagingUtilities.AreEquivalent(diffieHellmanResponse.EncodedMacKey, rpAssociation.SecretKey), "Key should have been encrypted."); } else { Assert.IsInstanceOf <AssociateUnencryptedResponse>(associateSuccessfulResponse); var unencryptedResponse = (AssociateUnencryptedResponse)associateSuccessfulResponse; } } else { Assert.IsNull(coordinator.RelyingParty.AssociationManager.AssociationStoreTestHook.GetAssociation(opDescription.Uri, new RelyingPartySecuritySettings())); } }
/// <summary> /// Runs a parameterized association flow test. /// </summary> /// <param name="opDescription"> /// The description of the Provider that the relying party uses to formulate the request. /// The specific host is not used, but the scheme is significant. /// </param> /// <param name="expectedAssociationType"> /// The value of the openid.assoc_type parameter expected, /// or null if a failure is anticipated. /// </param> private async Task ParameterizedAssociationTestAsync( ProviderEndpointDescription opDescription, string expectedAssociationType) { Protocol protocol = Protocol.Lookup(Protocol.Lookup(opDescription.Version).ProtocolVersion); bool expectSuccess = expectedAssociationType != null; bool expectDiffieHellman = !opDescription.Uri.IsTransportSecure(); Association rpAssociation = null, opAssociation; AssociateSuccessfulResponse associateSuccessfulResponse = null; AssociateUnsuccessfulResponse associateUnsuccessfulResponse = null; var relyingParty = new OpenIdRelyingParty(new MemoryCryptoKeyAndNonceStore(), this.HostFactories); var provider = new OpenIdProvider(new MemoryCryptoKeyAndNonceStore(), this.HostFactories) { SecuritySettings = this.ProviderSecuritySettings }; Handle(opDescription.Uri).By( async(request, ct) => { IRequest req = await provider.GetRequestAsync(request, ct); Assert.IsNotNull(req, "Expected incoming request but did not receive it."); Assert.IsTrue(req.IsResponseReady); return(await provider.PrepareResponseAsync(req, ct)); }); relyingParty.Channel.IncomingMessageFilter = message => { Assert.AreSame(opDescription.Version, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, Protocol.Lookup(opDescription.Version).ProtocolVersion); var associateSuccess = message as AssociateSuccessfulResponse; var associateFailed = message as AssociateUnsuccessfulResponse; if (associateSuccess != null) { associateSuccessfulResponse = associateSuccess; } if (associateFailed != null) { associateUnsuccessfulResponse = associateFailed; } }; relyingParty.Channel.OutgoingMessageFilter = message => { Assert.AreEqual(opDescription.Version, message.Version, "The message was for version {0} but was expected to be for {1}.", message.Version, opDescription.Version); }; relyingParty.SecuritySettings = this.RelyingPartySecuritySettings; rpAssociation = await relyingParty.AssociationManager.GetOrCreateAssociationAsync(opDescription, CancellationToken.None); if (expectSuccess) { Assert.IsNotNull(rpAssociation); Association actual = relyingParty.AssociationManager.AssociationStoreTestHook.GetAssociation(opDescription.Uri, rpAssociation.Handle); Assert.AreEqual(rpAssociation, actual); opAssociation = provider.AssociationStore.Deserialize(new TestSignedDirectedMessage(), false, rpAssociation.Handle); Assert.IsNotNull(opAssociation, "The Provider could not decode the association handle."); Assert.AreEqual(opAssociation.Handle, rpAssociation.Handle); Assert.AreEqual(expectedAssociationType, rpAssociation.GetAssociationType(protocol)); Assert.AreEqual(expectedAssociationType, opAssociation.GetAssociationType(protocol)); Assert.IsTrue(Math.Abs(opAssociation.SecondsTillExpiration - rpAssociation.SecondsTillExpiration) < 60); Assert.IsTrue(MessagingUtilities.AreEquivalent(opAssociation.SecretKey, rpAssociation.SecretKey)); if (expectDiffieHellman) { Assert.IsInstanceOf <AssociateDiffieHellmanResponse>(associateSuccessfulResponse); var diffieHellmanResponse = (AssociateDiffieHellmanResponse)associateSuccessfulResponse; Assert.IsFalse(MessagingUtilities.AreEquivalent(diffieHellmanResponse.EncodedMacKey, rpAssociation.SecretKey), "Key should have been encrypted."); } else { Assert.IsInstanceOf <AssociateUnencryptedResponse>(associateSuccessfulResponse); var unencryptedResponse = (AssociateUnencryptedResponse)associateSuccessfulResponse; } } else { Assert.IsNull(relyingParty.AssociationManager.AssociationStoreTestHook.GetAssociation(opDescription.Uri, new RelyingPartySecuritySettings())); } }