/// <summary>
        /// Initializes a new instance of the <see cref="ProviderSigningBindingElement"/> class.
        /// </summary>
        /// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal ProviderSigningBindingElement(IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(associationStore, "associationStore");
            Requires.NotNull(securitySettings, "securitySettings");

            this.opAssociations     = associationStore;
            this.opSecuritySettings = securitySettings;
        }
Exemple #2
0
        /// <summary>
        /// Creates the association at the provider side after the association request has been received.
        /// </summary>
        /// <param name="request">The association request.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>The newly created association.</returns>
        /// <remarks>
        /// The response message is updated to include the details of the created association by this method,
        /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.
        /// </remarks>
        protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(request, "request");
            var diffieHellmanRequest = request as AssociateDiffieHellmanRequest;

            ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, "request");
            ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");

            this.SessionType = this.SessionType ?? request.SessionType;

            // Go ahead and create the association first, complete with its secret that we're about to share.
            Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings);

            this.AssociationHandle = association.Handle;
            this.ExpiresIn         = association.SecondsTillExpiration;

            // We now need to securely communicate the secret to the relying party using Diffie-Hellman.
            // We do this by performing a DH algorithm on the secret and setting a couple of properties
            // that will be transmitted to the Relying Party.  The RP will perform an inverse operation
            // using its part of a DH secret in order to decrypt the shared secret we just invented
            // above when we created the association.
            DiffieHellman dh = new DiffieHellmanManaged(
                diffieHellmanRequest.DiffieHellmanModulus ?? AssociateDiffieHellmanRequest.DefaultMod,
                diffieHellmanRequest.DiffieHellmanGen ?? AssociateDiffieHellmanRequest.DefaultGen,
                AssociateDiffieHellmanRequest.DefaultX);
            HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(this.Protocol, this.SessionType);

            this.DiffieHellmanServerPublic = DiffieHellmanUtilities.EnsurePositive(dh.CreateKeyExchange());
            this.EncodedMacKey             = DiffieHellmanUtilities.SHAHashXorSecret(hasher, dh, diffieHellmanRequest.DiffieHellmanConsumerPublic, association.SecretKey);

            return(association);
        }
        /// <summary>
        /// Initializes a new instance of the SigningBindingElement class for use by a Provider.
        /// </summary>
        /// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal SigningBindingElement(IAssociationStore <AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings)
        {
            ErrorUtilities.VerifyArgumentNotNull(associationStore, "associationStore");
            ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings");

            this.opAssociations     = associationStore;
            this.opSecuritySettings = securitySettings;
        }
Exemple #4
0
 /// <summary>
 /// Applies a well known set of security requirements to a default set of security settings.
 /// </summary>
 /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
 /// <remarks>
 /// Care should be taken to never decrease security when applying a profile.
 /// Profiles should only enhance security requirements to avoid being
 /// incompatible with each other.
 /// </remarks>
 void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings)
 {
     // No special security to apply here.
 }
Exemple #5
0
        /// <summary>
        /// Called to create the Association based on a request previously given by the Relying Party.
        /// </summary>
        /// <param name="request">The prior request for an association.</param>
        /// <param name="associationStore">The Provider's association store.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>
        /// The created association.
        /// </returns>
        /// <remarks>
        ///   <para>The caller will update this message's
        ///   <see cref="AssociateSuccessfulResponse.ExpiresIn"/> and
        ///   <see cref="AssociateSuccessfulResponse.AssociationHandle"/>
        /// properties based on the <see cref="Association"/> returned by this method, but any other
        /// association type specific properties must be set by this method.</para>
        ///   <para>The response message is updated to include the details of the created association by this method,
        /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
        /// </remarks>
        public Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
        {
            Association association = HmacShaAssociationProvider.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings);

            this.MacKey = association.SecretKey;
            return(association);
        }
Exemple #6
0
        /// <summary>
        /// Creates a new association of a given type.
        /// </summary>
        /// <param name="protocol">The protocol.</param>
        /// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param>
        /// <param name="associationUse">A value indicating whether the new association will be used privately by the Provider for "dumb mode" authentication
        /// or shared with the Relying Party for "smart mode" authentication.</param>
        /// <param name="securitySettings">The security settings of the Provider.</param>
        /// <returns>The newly created association.</returns>
        /// <remarks>
        /// The new association is NOT automatically put into an association store.  This must be done by the caller.
        /// </remarks>
        internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, ProviderSecuritySettings securitySettings)
        {
            Contract.Requires <ArgumentNullException>(protocol != null);
            Contract.Requires <ArgumentException>(!String.IsNullOrEmpty(associationType));
            Contract.Requires <ArgumentNullException>(securitySettings != null);
            Contract.Ensures(Contract.Result <HmacShaAssociation>() != null);

            int secretLength = GetSecretLength(protocol, associationType);

            // Generate the handle.  It must be unique, and preferably unpredictable,
            // so we use a time element and a random data element to generate it.
            string uniq   = MessagingUtilities.GetCryptoRandomDataAsBase64(4);
            string handle = string.Format(
                CultureInfo.InvariantCulture,
                "{{{0}}}{{{1}}}{{{2}}}",
                DateTime.UtcNow.Ticks,
                uniq,
                secretLength);

            // Generate the secret that will be used for signing
            byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength);

            TimeSpan lifetime;

            if (associationUse == AssociationRelyingPartyType.Smart)
            {
                if (!securitySettings.AssociationLifetimes.TryGetValue(associationType, out lifetime))
                {
                    lifetime = DefaultMaximumLifetime;
                }
            }
            else
            {
                lifetime = DumbSecretLifetime;
            }

            Contract.Assert(protocol != null);             // All the way up to the method call, the condition holds, yet we get a Requires failure next
            Contract.Assert(secret != null);
            Contract.Assert(!String.IsNullOrEmpty(associationType));
            return(Create(protocol, associationType, handle, secret, lifetime));
        }
Exemple #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
 /// for use by a Provider.
 /// </summary>
 /// <param name="associationStore">The association store to use.</param>
 /// <param name="nonceStore">The nonce store to use.</param>
 /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
 /// <param name="securitySettings">The security settings.</param>
 private OpenIdChannel(IAssociationStore <AssociationRelyingPartyType> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, ProviderSecuritySettings securitySettings) :
     this(messageTypeProvider, InitializeBindingElements(associationStore, nonceStore, securitySettings, false))
 {
     Contract.Requires <ArgumentNullException>(messageTypeProvider != null);
     Contract.Requires <ArgumentNullException>(securitySettings != null);
 }
Exemple #8
0
        /// <summary>
        /// Initializes the binding elements.
        /// </summary>
        /// <param name="cryptoKeyStore">The OpenID Provider's crypto key store.</param>
        /// <param name="nonceStore">The nonce store to use.</param>
        /// <param name="securitySettings">The security settings to apply.  Must be an instance of either RelyingPartySecuritySettings or ProviderSecuritySettings.</param>
        /// <returns>
        /// An array of binding elements which may be used to construct the channel.
        /// </returns>
        private static IChannelBindingElement[] InitializeBindingElements(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(cryptoKeyStore, "cryptoKeyStore");
            Requires.NotNull(securitySettings, "securitySettings");
            Requires.NotNull(nonceStore, "nonceStore");

            SigningBindingElement signingElement;

            signingElement = new ProviderSigningBindingElement(cryptoKeyStore, securitySettings);

            var extensionFactory = OpenIdExtensionFactoryAggregator.LoadFromConfiguration();

            List <IChannelBindingElement> elements = new List <IChannelBindingElement>(8);

            elements.Add(new ExtensionsBindingElement(extensionFactory, securitySettings, true));
            elements.Add(new StandardReplayProtectionBindingElement(nonceStore, true));
            elements.Add(new StandardExpirationBindingElement());
            elements.Add(signingElement);

            return(elements.ToArray());
        }
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <param name="securitySettings">The security settings of the Provider.</param>
 /// <returns>The created association.</returns>
 /// <remarks>
 ///     <para>The caller will update this message's <see cref="ExpiresIn"/> and <see cref="AssociationHandle"/>
 /// properties based on the <see cref="Association"/> returned by this method, but any other
 /// association type specific properties must be set by this method.</para>
 ///     <para>The response message is updated to include the details of the created association by this method,
 /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
 /// </remarks>
 protected abstract Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings);
Exemple #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OpenIdProviderChannel"/> class.
 /// </summary>
 /// <param name="cryptoKeyStore">The OpenID Provider's association store or handle encoder.</param>
 /// <param name="nonceStore">The nonce store to use.</param>
 /// <param name="securitySettings">The security settings.</param>
 internal OpenIdProviderChannel(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
     : this(cryptoKeyStore, nonceStore, new OpenIdProviderMessageFactory(), securitySettings)
 {
     Requires.NotNull(cryptoKeyStore, "cryptoKeyStore");
     Requires.NotNull(securitySettings, "securitySettings");
 }
Exemple #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OpenIdProviderChannel"/> class.
 /// </summary>
 /// <param name="cryptoKeyStore">The association store to use.</param>
 /// <param name="nonceStore">The nonce store to use.</param>
 /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
 /// <param name="securitySettings">The security settings.</param>
 private OpenIdProviderChannel(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, ProviderSecuritySettings securitySettings)
     : base(messageTypeProvider, InitializeBindingElements(cryptoKeyStore, nonceStore, securitySettings))
 {
     Requires.NotNull(cryptoKeyStore, "cryptoKeyStore");
     Requires.NotNull(messageTypeProvider, "messageTypeProvider");
     Requires.NotNull(securitySettings, "securitySettings");
 }
        private async Task ParameterizedAuthenticationTestAsync(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper)
        {
            Requires.That(!statelessRP || !sharedAssociation, null, "The RP cannot be stateless while sharing an association with the OP.");
            Requires.That(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;
            int         opStep           = 0;

            HandleProvider(
                async(op, req) => {
                if (association != null)
                {
                    var key = cryptoKeyStore.GetCurrentKey(
                        ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
                    op.CryptoKeyStore.StoreKey(
                        ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
                }

                switch (++opStep)
                {
                case 1:
                    var request = await op.Channel.ReadFromRequestAsync <CheckIdRequest>(req, CancellationToken.None);
                    Assert.IsNotNull(request);
                    IProtocolMessage response;
                    if (positive)
                    {
                        response = new PositiveAssertionResponse(request);
                    }
                    else
                    {
                        response = await NegativeAssertionResponse.CreateAsync(request, CancellationToken.None, op.Channel);
                    }

                    return(await op.Channel.PrepareResponseAsync(response));

                case 2:
                    if (positive && (statelessRP || !sharedAssociation))
                    {
                        var checkauthRequest =
                            await op.Channel.ReadFromRequestAsync <CheckAuthenticationRequest>(req, CancellationToken.None);
                        var checkauthResponse     = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
                        checkauthResponse.IsValid = checkauthRequest.IsValid;
                        return(await op.Channel.PrepareResponseAsync(checkauthResponse));
                    }

                    throw Assumes.NotReachable();

                case 3:
                    if (positive && (statelessRP || !sharedAssociation))
                    {
                        if (!tamper)
                        {
                            // Respond to the replay attack.
                            var checkauthRequest =
                                await op.Channel.ReadFromRequestAsync <CheckAuthenticationRequest>(req, CancellationToken.None);
                            var checkauthResponse     = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
                            checkauthResponse.IsValid = checkauthRequest.IsValid;
                            return(await op.Channel.PrepareResponseAsync(checkauthResponse));
                        }
                    }

                    throw Assumes.NotReachable();

                default:
                    throw Assumes.NotReachable();
                }
            });

            {
                var rp = this.CreateRelyingParty(statelessRP);
                if (tamper)
                {
                    rp.Channel.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";
                        }
                    };
                }

                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;
                var redirectRequest = await rp.Channel.PrepareResponseAsync(request);

                Uri redirectResponse;
                this.HostFactories.AllowAutoRedirects = false;
                using (var httpClient = rp.Channel.HostFactories.CreateHttpClient()) {
                    using (var response = await httpClient.GetAsync(redirectRequest.Headers.Location)) {
                        Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Redirect));
                        redirectResponse = response.Headers.Location;
                    }
                }

                var assertionMessage = new HttpRequestMessage(HttpMethod.Get, redirectResponse);
                if (positive)
                {
                    if (tamper)
                    {
                        try {
                            await rp.Channel.ReadFromRequestAsync <PositiveAssertionResponse>(assertionMessage, CancellationToken.None);

                            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 =
                            await rp.Channel.ReadFromRequestAsync <PositiveAssertionResponse>(assertionMessage, CancellationToken.None);

                        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 {
                            await rp.Channel.ReadFromRequestAsync <PositiveAssertionResponse>(assertionMessage, CancellationToken.None);

                            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 =
                        await rp.Channel.ReadFromRequestAsync <NegativeAssertionResponse>(assertionMessage, CancellationToken.None);

                    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);
                    }
                }
            }
        }
        /// <summary>
        /// Creates a response that notifies the Relying Party that the requested
        /// association type is not supported by this Provider, and offers
        /// an alternative association type, if possible.
        /// </summary>
        /// <param name="requestMessage">The request message.</param>
        /// <param name="securitySettings">The security settings that apply to this Provider.</param>
        /// <returns>
        /// The response to send to the Relying Party.
        /// </returns>
        private static AssociateUnsuccessfulResponse CreateUnsuccessfulResponse(IAssociateRequestProvider requestMessage, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(requestMessage, "requestMessage");
            Requires.NotNull(securitySettings, "securitySettings");

            var unsuccessfulResponse = new AssociateUnsuccessfulResponse(requestMessage.Version, (AssociateRequest)requestMessage);

            // The strategy here is to suggest that the RP try again with the lowest
            // permissible security settings, giving the RP the best chance of being
            // able to match with a compatible request.
            bool   unencryptedAllowed = requestMessage.Recipient.IsTransportSecure();
            bool   useDiffieHellman = !unencryptedAllowed;
            var    request = (AssociateRequest)requestMessage;
            var    protocol = requestMessage.GetProtocol();
            string associationType, sessionType;

            if (HmacShaAssociation.TryFindBestAssociation(protocol, false, securitySettings, useDiffieHellman, out associationType, out sessionType))
            {
                ErrorUtilities.VerifyInternal(request.AssociationType != associationType, "The RP asked for an association that should have been allowed, but the OP is trying to suggest the same one as an alternative!");
                unsuccessfulResponse.AssociationType = associationType;
                unsuccessfulResponse.SessionType     = sessionType;
                Logger.OpenId.InfoFormat(
                    "Association requested of type '{0}' and session '{1}', which the Provider does not support.  Sending back suggested alternative of '{0}' with session '{1}'.",
                    request.AssociationType,
                    request.SessionType,
                    unsuccessfulResponse.AssociationType,
                    unsuccessfulResponse.SessionType);
            }
            else
            {
                Logger.OpenId.InfoFormat("Association requested of type '{0}' and session '{1}', which the Provider does not support.  No alternative association type qualified for suggesting back to the Relying Party.", request.AssociationType, request.SessionType);
            }

            return(unsuccessfulResponse);
        }
        /// <summary>
        /// Creates a Provider's response to an incoming association request.
        /// </summary>
        /// <param name="requestMessage">The request message.</param>
        /// <param name="associationStore">The association store.</param>
        /// <param name="securitySettings">The security settings on the Provider.</param>
        /// <returns>
        /// The appropriate association response that is ready to be sent back to the Relying Party.
        /// </returns>
        /// <remarks>
        ///   <para>If an association is created, it will be automatically be added to the provided
        /// association store.</para>
        ///   <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>.
        /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para>
        /// </remarks>
        internal static IProtocolMessage CreateResponse(IAssociateRequestProvider requestMessage, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
        {
            Requires.NotNull(requestMessage, "requestMessage");
            Requires.NotNull(associationStore, "associationStore");
            Requires.NotNull(securitySettings, "securitySettings");

            AssociateRequest request = (AssociateRequest)requestMessage;
            IProtocolMessage response;
            var protocol = requestMessage.GetProtocol();

            if (securitySettings.IsAssociationInPermittedRange(protocol, request.AssociationType) &&
                HmacShaAssociation.IsDHSessionCompatible(protocol, request.AssociationType, request.SessionType))
            {
                response = requestMessage.CreateResponseCore();

                // Create and store the association if this is a successful response.
                var successResponse = response as IAssociateSuccessfulResponseProvider;
                if (successResponse != null)
                {
                    OpenIdProviderUtilities.CreateAssociation(request, successResponse, associationStore, securitySettings);
                }
            }
            else
            {
                response = CreateUnsuccessfulResponse(requestMessage, securitySettings);
            }

            return(response);
        }
Exemple #15
0
        /// <summary>
        /// Simulates an extension request and response.
        /// </summary>
        /// <param name="protocol">The protocol to use in the roundtripping.</param>
        /// <param name="requests">The extensions to add to the request message.</param>
        /// <param name="responses">The extensions to add to the response message.</param>
        /// <remarks>
        /// This method relies on the extension objects' Equals methods to verify
        /// accurate transport.  The Equals methods should be verified by separate tests.
        /// </remarks>
        internal async Task RoundtripAsync(Protocol protocol, IEnumerable <IOpenIdMessageExtension> requests, IEnumerable <IOpenIdMessageExtension> responses)
        {
            var         securitySettings = new ProviderSecuritySettings();
            var         cryptoKeyStore   = new MemoryCryptoKeyStore();
            var         associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
            Association association      = HmacShaAssociationProvider.Create(
                protocol,
                protocol.Args.SignatureAlgorithm.Best,
                AssociationRelyingPartyType.Smart,
                associationStore,
                securitySettings);

            this.HandleProvider(
                async(op, req) => {
                ExtensionTestUtilities.RegisterExtension(op.Channel, Mocks.MockOpenIdExtension.Factory);
                var key = cryptoKeyStore.GetCurrentKey(
                    ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
                op.CryptoKeyStore.StoreKey(
                    ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
                var request          = await op.Channel.ReadFromRequestAsync <CheckIdRequest>(req, CancellationToken.None);
                var response         = new PositiveAssertionResponse(request);
                var receivedRequests = request.Extensions.Cast <IOpenIdMessageExtension>();
                CollectionAssert <IOpenIdMessageExtension> .AreEquivalentByEquality(requests.ToArray(), receivedRequests.ToArray());

                foreach (var extensionResponse in responses)
                {
                    response.Extensions.Add(extensionResponse);
                }

                return(await op.Channel.PrepareResponseAsync(response));
            });

            {
                var rp = this.CreateRelyingParty();
                ExtensionTestUtilities.RegisterExtension(rp.Channel, Mocks.MockOpenIdExtension.Factory);
                var requestBase = new CheckIdRequest(protocol.Version, OpenIdTestBase.OPUri, AuthenticationRequestMode.Immediate);
                OpenIdTestBase.StoreAssociation(rp, OpenIdTestBase.OPUri, association);
                requestBase.AssociationHandle = association.Handle;
                requestBase.ClaimedIdentifier = "http://claimedid";
                requestBase.LocalIdentifier   = "http://localid";
                requestBase.ReturnTo          = OpenIdTestBase.RPUri;

                foreach (IOpenIdMessageExtension extension in requests)
                {
                    requestBase.Extensions.Add(extension);
                }

                var redirectingRequest = await rp.Channel.PrepareResponseAsync(requestBase);

                Uri redirectingResponseUri;
                this.HostFactories.AllowAutoRedirects = false;
                using (var httpClient = rp.Channel.HostFactories.CreateHttpClient()) {
                    using (var redirectingResponse = await httpClient.GetAsync(redirectingRequest.Headers.Location)) {
                        Assert.AreEqual(HttpStatusCode.Found, redirectingResponse.StatusCode);
                        redirectingResponseUri = redirectingResponse.Headers.Location;
                    }
                }

                var response =
                    await
                    rp.Channel.ReadFromRequestAsync <PositiveAssertionResponse>(
                        new HttpRequestMessage(HttpMethod.Get, redirectingResponseUri), CancellationToken.None);

                var receivedResponses = response.Extensions.Cast <IOpenIdMessageExtension>();
                CollectionAssert <IOpenIdMessageExtension> .AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray());
            }
        }
 /// <summary>
 /// Applies a well known set of security requirements to a default set of security settings.
 /// </summary>
 /// <param name="securitySettings">The security settings to enhance with the requirements of this profile.</param>
 /// <remarks>
 /// Care should be taken to never decrease security when applying a profile.
 /// Profiles should only enhance security requirements to avoid being
 /// incompatible with each other.
 /// </remarks>
 void IProviderBehavior.ApplySecuritySettings(ProviderSecuritySettings securitySettings)
 {
     // Nothing to do here.
 }
Exemple #17
0
 /// <summary>
 /// Called to create the Association based on a request previously given by the Relying Party.
 /// </summary>
 /// <param name="request">The prior request for an association.</param>
 /// <param name="associationStore">The Provider's association store.</param>
 /// <param name="securitySettings">The security settings of the Provider.</param>
 /// <returns>
 /// The created association.
 /// </returns>
 Association IAssociateSuccessfulResponseProvider.CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings)
 {
     Requires.NotNull(request, "request");
     Requires.NotNull(associationStore, "associationStore");
     Requires.NotNull(securitySettings, "securitySettings");
     throw new NotImplementedException();
 }
Exemple #18
0
 /// <summary>
 /// Ensures the maximum association lifetime does not exceed a given limit.
 /// </summary>
 /// <param name="associationType">Type of the association.</param>
 /// <param name="maximumLifetime">The maximum lifetime.</param>
 /// <param name="securitySettings">The security settings to adjust.</param>
 private static void SetMaximumAssociationLifetimeToNotExceed(string associationType, TimeSpan maximumLifetime, ProviderSecuritySettings securitySettings)
 {
     Requires.NotNullOrEmpty(associationType, "associationType");
     Requires.That(maximumLifetime.TotalSeconds > 0, "maximumLifetime", "requires positive timespan");
     if (!securitySettings.AssociationLifetimes.ContainsKey(associationType) ||
         securitySettings.AssociationLifetimes[associationType] > maximumLifetime)
     {
         securitySettings.AssociationLifetimes[associationType] = maximumLifetime;
     }
 }
Exemple #19
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
 /// for use by a Provider.
 /// </summary>
 /// <param name="associationStore">The association store to use.</param>
 /// <param name="nonceStore">The nonce store to use.</param>
 /// <param name="securitySettings">The security settings.</param>
 internal OpenIdChannel(IAssociationStore <AssociationRelyingPartyType> associationStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
     : this(associationStore, nonceStore, new OpenIdMessageFactory(), securitySettings)
 {
     Contract.Requires <ArgumentNullException>(securitySettings != null);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
 /// for use by a Provider.
 /// </summary>
 /// <param name="associationStore">The association store to use.</param>
 /// <param name="nonceStore">The nonce store to use.</param>
 /// <param name="securitySettings">The security settings.</param>
 internal OpenIdChannel(IAssociationStore <AssociationRelyingPartyType> associationStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings)
     : this(associationStore, nonceStore, new OpenIdMessageFactory(), securitySettings)
 {
 }
Exemple #21
0
 /// <summary>
 /// Ensures the maximum association lifetime does not exceed a given limit.
 /// </summary>
 /// <param name="associationType">Type of the association.</param>
 /// <param name="maximumLifetime">The maximum lifetime.</param>
 /// <param name="securitySettings">The security settings to adjust.</param>
 private static void SetMaximumAssociationLifetimeToNotExceed(string associationType, TimeSpan maximumLifetime, ProviderSecuritySettings securitySettings)
 {
     Contract.Requires(!string.IsNullOrEmpty(associationType));
     Contract.Requires(maximumLifetime.TotalSeconds > 0);
     if (!securitySettings.AssociationLifetimes.ContainsKey(associationType) ||
         securitySettings.AssociationLifetimes[associationType] > maximumLifetime)
     {
         securitySettings.AssociationLifetimes[associationType] = maximumLifetime;
     }
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
 /// for use by a Provider.
 /// </summary>
 /// <param name="associationStore">The association store to use.</param>
 /// <param name="nonceStore">The nonce store to use.</param>
 /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
 /// <param name="securitySettings">The security settings.</param>
 private OpenIdChannel(IAssociationStore <AssociationRelyingPartyType> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider, ProviderSecuritySettings securitySettings) :
     this(messageTypeProvider, InitializeBindingElements(associationStore, nonceStore, securitySettings))
 {
 }
        /// <summary>
        /// Initializes a new instance of the SigningBindingElement class for use by a Provider.
        /// </summary>
        /// <param name="associationStore">The association store used to look up the secrets needed for signing.</param>
        /// <param name="securitySettings">The security settings.</param>
        internal SigningBindingElement(IAssociationStore <AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings)
        {
            Contract.Requires <ArgumentNullException>(associationStore != null);
            Contract.Requires <ArgumentNullException>(securitySettings != null);

            this.opAssociations     = associationStore;
            this.opSecuritySettings = securitySettings;
        }
Exemple #24
0
        private void ParameterizedAuthenticationTest(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper)
        {
            Requires.That(!statelessRP || !sharedAssociation, null, "The RP cannot be stateless while sharing an association with the OP.");
            Requires.That(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();
        }