/// <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);
        }
Example #3
0
        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();
        }
Example #4
0
        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();
        }
Example #5
0
        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.");
        }
Example #6
0
        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.");
        }
Example #7
0
        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();
        }
Example #8
0
        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();
        }
Example #9
0
        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.");
        }
Example #10
0
        /// <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()));
            }
        }
Example #11
0
        /// <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()));
            }
        }