Example #1
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 #2
0
        public void AssociateRenegotiateLimitedByRPSecuritySettings()
        {
            Protocol          protocol    = Protocol.V20;
            OpenIdCoordinator coordinator = new OpenIdCoordinator(
                rp => {
                rp.SecuritySettings.MinimumHashBitLength = 256;
                var association = rp.AssociationManager.GetOrCreateAssociation(new ProviderEndpointDescription(OPUri, protocol.Version));
                Assert.IsNull(association, "No association should have been created when RP and OP could not agree on association strength.");
            },
                op => {
                op.SecuritySettings.MaximumHashBitLength = 160;
                AutoProvider(op);
            });

            coordinator.Run();
        }
 public void UnsolicitedAssertion()
 {
     this.MockResponder.RegisterMockRPDiscovery();
     OpenIdCoordinator coordinator = new OpenIdCoordinator(
         rp => {
             rp.Channel.WebRequestHandler = this.MockResponder.MockWebRequestHandler;
             IAuthenticationResponse response = rp.GetResponse();
             Assert.AreEqual(AuthenticationStatus.Authenticated, response.Status);
         },
         op => {
             op.Channel.WebRequestHandler = this.MockResponder.MockWebRequestHandler;
             Identifier id = GetMockIdentifier(ProtocolVersion.V20);
             op.SendUnsolicitedAssertion(OPUri, RPRealmUri, id, OPLocalIdentifiers[0]);
             AutoProvider(op); // handle check_auth
         });
     coordinator.Run();
 }
Example #4
0
        public void OPRejectsHttpNoEncryptionAssociateRequests()
        {
            Protocol          protocol    = Protocol.V20;
            OpenIdCoordinator coordinator = new OpenIdCoordinator(
                rp => {
                // We have to formulate the associate request manually,
                // since the DNOI RP won't voluntarily suggest no encryption at all.
                var request             = new AssociateUnencryptedRequestNoSslCheck(protocol.Version, OPUri);
                request.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256;
                request.SessionType     = protocol.Args.SessionType.NoEncryption;
                var response            = rp.Channel.Request <DirectErrorResponse>(request);
                Assert.IsNotNull(response);
            },
                AutoProvider);

            coordinator.Run();
        }
Example #5
0
        public void ExtensionOnlyChannelLevel()
        {
            Protocol protocol = Protocol.V20;
            AuthenticationRequestMode mode = AuthenticationRequestMode.Setup;

            var coordinator = new OpenIdCoordinator(
                rp => {
                var request = new SignedResponseRequest(protocol.Version, OPUri, mode);
                rp.Channel.Respond(request);
            },
                op => {
                var request = op.Channel.ReadFromRequest <SignedResponseRequest>();
                Assert.IsNotInstanceOf <CheckIdRequest>(request);
            });

            coordinator.Run();
        }
Example #6
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 #7
0
        public void AssociateDiffieHellmanOverHttps()
        {
            Protocol          protocol    = Protocol.V20;
            OpenIdCoordinator coordinator = new OpenIdCoordinator(
                rp => {
                // We have to formulate the associate request manually,
                // since the DNOI RP won't voluntarily use DH on HTTPS.
                AssociateDiffieHellmanRequest request = new AssociateDiffieHellmanRequest(protocol.Version, new Uri("https://Provider"));
                request.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256;
                request.SessionType     = protocol.Args.SessionType.DH_SHA256;
                request.InitializeRequest();
                var response = rp.Channel.Request <AssociateSuccessfulResponse>(request);
                Assert.IsNotNull(response);
                Assert.AreEqual(request.AssociationType, response.AssociationType);
                Assert.AreEqual(request.SessionType, response.SessionType);
            },
                AutoProvider);

            coordinator.Run();
        }
Example #8
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 #9
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 #10
0
        public void ExtensionOnlyFacadeLevel()
        {
            Protocol protocol    = Protocol.V20;
            var      coordinator = new OpenIdCoordinator(
                rp => {
                var request = rp.CreateRequest(GetMockIdentifier(protocol.ProtocolVersion), RPRealmUri, RPUri);

                request.IsExtensionOnly = true;
                rp.Channel.Respond(request.RedirectingResponse.OriginalMessage);
                IAuthenticationResponse response = rp.GetResponse();
                Assert.AreEqual(AuthenticationStatus.ExtensionsOnly, response.Status);
            },
                op => {
                var assocRequest = op.GetRequest();
                op.Respond(assocRequest);

                var request        = (IAnonymousRequest)op.GetRequest();
                request.IsApproved = true;
                Assert.IsNotInstanceOf <CheckIdRequest>(request);
                op.Respond(request);
            });

            coordinator.Run();
        }
Example #11
0
        private void ParameterizedAuthenticationTest(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper)
        {
            Requires.True(!statelessRP || !sharedAssociation, null, "The RP cannot be stateless while sharing an association with the OP.");
            Requires.True(positive || !tamper, null, "Cannot tamper with a negative response.");
            var         securitySettings = new ProviderSecuritySettings();
            var         cryptoKeyStore   = new MemoryCryptoKeyStore();
            var         associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
            Association association      = sharedAssociation ? HmacShaAssociationProvider.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, associationStore, securitySettings) : null;
            var         coordinator      = new OpenIdCoordinator(
                rp => {
                var request = new CheckIdRequest(protocol.Version, OPUri, immediate ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup);

                if (association != null)
                {
                    StoreAssociation(rp, OPUri, association);
                    request.AssociationHandle = association.Handle;
                }

                request.ClaimedIdentifier = "http://claimedid";
                request.LocalIdentifier   = "http://localid";
                request.ReturnTo          = RPUri;
                request.Realm             = RPUri;
                rp.Channel.Respond(request);
                if (positive)
                {
                    if (tamper)
                    {
                        try {
                            rp.Channel.ReadFromRequest <PositiveAssertionResponse>();
                            Assert.Fail("Expected exception {0} not thrown.", typeof(InvalidSignatureException).Name);
                        } catch (InvalidSignatureException) {
                            TestLogger.InfoFormat("Caught expected {0} exception after tampering with signed data.", typeof(InvalidSignatureException).Name);
                        }
                    }
                    else
                    {
                        var response = rp.Channel.ReadFromRequest <PositiveAssertionResponse>();
                        Assert.IsNotNull(response);
                        Assert.AreEqual(request.ClaimedIdentifier, response.ClaimedIdentifier);
                        Assert.AreEqual(request.LocalIdentifier, response.LocalIdentifier);
                        Assert.AreEqual(request.ReturnTo, response.ReturnTo);

                        // Attempt to replay the message and verify that it fails.
                        // Because in various scenarios and protocol versions different components
                        // notice the replay, we can get one of two exceptions thrown.
                        // When the OP notices the replay we get a generic InvalidSignatureException.
                        // When the RP notices the replay we get a specific ReplayMessageException.
                        try {
                            CoordinatingChannel channel = (CoordinatingChannel)rp.Channel;
                            channel.Replay(response);
                            Assert.Fail("Expected ProtocolException was not thrown.");
                        } catch (ProtocolException ex) {
                            Assert.IsTrue(ex is ReplayedMessageException || ex is InvalidSignatureException, "A {0} exception was thrown instead of the expected {1} or {2}.", ex.GetType(), typeof(ReplayedMessageException).Name, typeof(InvalidSignatureException).Name);
                        }
                    }
                }
                else
                {
                    var response = rp.Channel.ReadFromRequest <NegativeAssertionResponse>();
                    Assert.IsNotNull(response);
                    if (immediate)
                    {
                        // Only 1.1 was required to include user_setup_url
                        if (protocol.Version.Major < 2)
                        {
                            Assert.IsNotNull(response.UserSetupUrl);
                        }
                    }
                    else
                    {
                        Assert.IsNull(response.UserSetupUrl);
                    }
                }
            },
                op => {
                if (association != null)
                {
                    var key = cryptoKeyStore.GetCurrentKey(ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
                    op.CryptoKeyStore.StoreKey(ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
                }

                var request = op.Channel.ReadFromRequest <CheckIdRequest>();
                Assert.IsNotNull(request);
                IProtocolMessage response;
                if (positive)
                {
                    response = new PositiveAssertionResponse(request);
                }
                else
                {
                    response = new NegativeAssertionResponse(request, op.Channel);
                }
                op.Channel.Respond(response);

                if (positive && (statelessRP || !sharedAssociation))
                {
                    var checkauthRequest      = op.Channel.ReadFromRequest <CheckAuthenticationRequest>();
                    var checkauthResponse     = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
                    checkauthResponse.IsValid = checkauthRequest.IsValid;
                    op.Channel.Respond(checkauthResponse);

                    if (!tamper)
                    {
                        // Respond to the replay attack.
                        checkauthRequest          = op.Channel.ReadFromRequest <CheckAuthenticationRequest>();
                        checkauthResponse         = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
                        checkauthResponse.IsValid = checkauthRequest.IsValid;
                        op.Channel.Respond(checkauthResponse);
                    }
                }
            });

            if (tamper)
            {
                coordinator.IncomingMessageFilter = message => {
                    var assertion = message as PositiveAssertionResponse;
                    if (assertion != null)
                    {
                        // Alter the Local Identifier between the Provider and the Relying Party.
                        // If the signature binding element does its job, this should cause the RP
                        // to throw.
                        assertion.LocalIdentifier = "http://victim";
                    }
                };
            }
            if (statelessRP)
            {
                coordinator.RelyingParty = new OpenIdRelyingParty(null);
            }

            coordinator.Run();
        }
Example #12
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()));
            }
        }