Exemple #1
0
        /// <summary>
        /// Performs any transformation on an incoming message that may be necessary and/or
        /// validates an incoming message based on the rules of this channel binding element.
        /// </summary>
        /// <param name="message">The incoming message to process.</param>
        /// <returns>
        /// True if the <paramref name="message"/> applied to this binding element
        /// and the operation was successful.  False if the operation did not apply to this message.
        /// </returns>
        /// <exception cref="ProtocolException">
        /// Thrown when the binding element rules indicate that this message is invalid and should
        /// NOT be processed.
        /// </exception>
        /// <remarks>
        /// Implementations that provide message protection must honor the
        /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
        /// </remarks>
        public bool PrepareMessageForReceiving(IProtocolMessage message)
        {
            IndirectSignedResponse response = message as IndirectSignedResponse;

            if (response != null && response.Version.Major < 2)
            {
                // Although GetReturnToArgument may return null if the parameters are not signed,
                // the ReturnToSignatureBindingElement should have thrown an exception already
                // if this is a 1.0 OP signed response without a valid signature since 1.0 OPs
                // are not supposed to be able to send unsolicited assertions.
                // Any safe solicited assertion would include our signature, allowing us to find
                // these values.
                if (response.ProviderEndpoint == null)
                {
                    string op_endpoint = response.GetReturnToArgument(ProviderEndpointParameterName);
                    response.ProviderEndpoint = new Uri(op_endpoint);
                }

                PositiveAssertionResponse authResponse = response as PositiveAssertionResponse;
                if (authResponse != null)
                {
                    if (authResponse.ClaimedIdentifier == null)
                    {
                        authResponse.ClaimedIdentifier = response.GetReturnToArgument(ClaimedIdentifierParameterName);
                    }
                }

                return(true);
            }

            return(false);
        }
        public async Task GetCallbackArguments()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();
            var rp = CreateRelyingParty();

            UriBuilder returnToBuilder = new UriBuilder(assertion.ReturnTo);

            returnToBuilder.AppendQueryArgs(new Dictionary <string, string> {
                { "a", "b" }
            });
            assertion.ReturnTo = returnToBuilder.Uri;
            var authResponse = await PositiveAuthenticationResponse.CreateAsync(assertion, rp, CancellationToken.None);

            // First pretend that the return_to args were signed.
            assertion.ReturnToParametersSignatureValidated = true;
            Assert.AreEqual(1, authResponse.GetCallbackArguments().Count);
            Assert.IsTrue(authResponse.GetCallbackArguments().ContainsKey("a"));
            Assert.AreEqual("b", authResponse.GetCallbackArgument("a"));

            // Now simulate them NOT being signed.
            assertion.ReturnToParametersSignatureValidated = false;
            Assert.AreEqual(0, authResponse.GetCallbackArguments().Count);
            Assert.IsFalse(authResponse.GetCallbackArguments().ContainsKey("a"));
            Assert.IsNull(authResponse.GetCallbackArgument("a"));
        }
Exemple #3
0
        public void InsecureIdentifiersRejectedWithRequireSsl()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();
            var rp = CreateRelyingParty();

            rp.SecuritySettings.RequireSsl = true;
            var authResponse = new PositiveAuthenticationResponse(assertion, rp);
        }
        public async Task InsecureIdentifiersRejectedWithRequireSsl()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();
            var rp = CreateRelyingParty();

            rp.SecuritySettings.RequireSsl = true;
            var authResponse = await PositiveAuthenticationResponse.CreateAsync(assertion, rp, CancellationToken.None);
        }
Exemple #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PositiveAuthenticationResponse"/> class
        /// after verifying that discovery on the identifier matches the asserted data.
        /// </summary>
        /// <param name="response">The response.</param>
        /// <param name="relyingParty">The relying party.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The newly initialized instance.</returns>
        internal static async Task <PositiveAuthenticationResponse> CreateAsync(
            PositiveAssertionResponse response, OpenIdRelyingParty relyingParty, CancellationToken cancellationToken)
        {
            var result = new PositiveAuthenticationResponse(response, relyingParty);
            await result.VerifyDiscoveryMatchesAssertionAsync(relyingParty, cancellationToken);

            return(result);
        }
        public async Task DualIdentifierNoMatchInAssertionVerificationByDefault()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion(true);
            ClaimsResponse            extension = new ClaimsResponse();

            assertion.Extensions.Add(extension);
            var rp = CreateRelyingParty();
            await PositiveAuthenticationResponse.CreateAsync(assertion, rp, CancellationToken.None);             // this will throw if it fails to find a match
        }
        public async Task SpoofedClaimedIdDetectionSolicited()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();

            assertion.ProviderEndpoint = new Uri("http://rogueOP");
            var rp           = CreateRelyingParty();
            var authResponse = await PositiveAuthenticationResponse.CreateAsync(assertion, rp, CancellationToken.None);

            Assert.AreEqual(AuthenticationStatus.Failed, authResponse.Status);
        }
Exemple #8
0
        public void SpoofedClaimedIdDetectionSolicited()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();

            assertion.ProviderEndpoint = new Uri("http://rogueOP");
            var rp           = CreateRelyingParty();
            var authResponse = new PositiveAuthenticationResponse(assertion, rp);

            Assert.AreEqual(AuthenticationStatus.Failed, authResponse.Status);
        }
Exemple #9
0
        public void DualIdentifierNoMatchInAssertionVerificationByDefault()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion(true);
            ClaimsResponse            extension = new ClaimsResponse();

            assertion.Extensions.Add(extension);
            var rp = CreateRelyingParty();

            new PositiveAuthenticationResponse(assertion, rp);             // this will throw if it fails to find a match
        }
        public async Task DualIdentifierMatchesInAssertionVerification()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion(true);
            ClaimsResponse            extension = new ClaimsResponse();

            assertion.Extensions.Add(extension);
            var rp = CreateRelyingParty();

            rp.SecuritySettings.AllowDualPurposeIdentifiers = true;
            await PositiveAuthenticationResponse.CreateAsync(assertion, rp, CancellationToken.None);             // this will throw if it fails to find a match
        }
        public override void SetUp()
        {
            base.SetUp();

            this.protocol         = Protocol.V20;
            this.request          = new CheckIdRequest(this.protocol.Version, OPUri, AuthenticationRequestMode.Setup);
            this.request.ReturnTo = RPUri;
            this.response         = new PositiveAssertionResponse(this.request);

            this.unsolicited = new PositiveAssertionResponse(this.protocol.Version, RPUri);
        }
Exemple #12
0
        public static PositiveAuthenticationResponse1 CreateAsync_ccp(
            PositiveAssertionResponse response, OpenIdRelyingParty relyingParty, CancellationToken cancellationToken)
        {
            var result = new PositiveAuthenticationResponse1(response, relyingParty);

            GlobalState.claimedEndPoint = result.Endpoint;

            result.VerifyDiscoveryMatchesAssertionAsync_ccp(relyingParty, cancellationToken);

            return(result);
        }
Exemple #13
0
        public static PositiveAuthenticationResponse1 CreateAsync_ccp(
            PositiveAssertionResponse response, OpenIdRelyingParty relyingParty, CancellationToken cancellationToken)
        {
            var result = new PositiveAuthenticationResponse1(response, relyingParty);

            result.VerifyDiscoveryMatchesAssertionAsync_ccp(relyingParty, cancellationToken);

            //Contract.Assert(false);

            return(result);
        }
        private PositiveAssertionResponse GetPositiveAssertion(bool dualIdentifier)
        {
            Protocol protocol = Protocol.Default;
            PositiveAssertionResponse assertion = new PositiveAssertionResponse(protocol.Version, this.returnTo);

            assertion.ClaimedIdentifier = dualIdentifier ? this.GetMockDualIdentifier() : this.GetMockIdentifier(protocol.ProtocolVersion, false);
            assertion.LocalIdentifier   = OPLocalIdentifiers[0];
            assertion.ReturnTo          = this.returnTo;
            assertion.ProviderEndpoint  = OPUri;
            return(assertion);
        }
Exemple #15
0
        /// <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="recipient">The intended or actual recipient of the request message.</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 IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary <string, string> fields)
        {
            RequestBase message = null;

            // Discern the OpenID version of the message.
            Protocol protocol = Protocol.V11;
            string   ns;

            if (fields.TryGetValue(Protocol.V20.openid.ns, out ns))
            {
                ErrorUtilities.VerifyProtocol(string.Equals(ns, Protocol.OpenId2Namespace, StringComparison.Ordinal), MessagingStrings.UnexpectedMessagePartValue, Protocol.V20.openid.ns, ns);
                protocol = Protocol.V20;
            }

            string mode;

            if (fields.TryGetValue(protocol.openid.mode, out mode))
            {
                if (string.Equals(mode, protocol.Args.Mode.cancel) ||
                    (string.Equals(mode, protocol.Args.Mode.setup_needed) && (protocol.Version.Major >= 2 || fields.ContainsKey(protocol.openid.user_setup_url))))
                {
                    message = new NegativeAssertionResponse(protocol.Version, recipient.Location, mode);
                }
                else if (string.Equals(mode, protocol.Args.Mode.id_res))
                {
                    if (fields.ContainsKey(protocol.openid.identity))
                    {
                        message = new PositiveAssertionResponse(protocol.Version, recipient.Location);
                    }
                    else
                    {
                        ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent);
                        message = new IndirectSignedResponse(protocol.Version, recipient.Location);
                    }
                }
                else if (string.Equals(mode, protocol.Args.Mode.error))
                {
                    message = new IndirectErrorResponse(protocol.Version, recipient.Location);
                }
                else
                {
                    ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessagePartValue, protocol.openid.mode, mode);
                }
            }

            if (message != null)
            {
                message.SetAsIncoming();
            }

            return(message);
        }
Exemple #16
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 static void Roundtrip(
            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);
            var         coordinator      = new OpenIdCoordinator(
                rp => {
                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);
                }

                rp.Channel.Respond(requestBase);
                var response = rp.Channel.ReadFromRequest <PositiveAssertionResponse>();

                var receivedResponses = response.Extensions.Cast <IOpenIdMessageExtension>();
                CollectionAssert <IOpenIdMessageExtension> .AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray());
            },
                op => {
                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          = op.Channel.ReadFromRequest <CheckIdRequest>();
                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);
                }

                op.Channel.Respond(response);
            });

            coordinator.Run();
        }
Exemple #17
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PositiveAuthenticationResponse"/> class
        /// </summary>
        /// <param name="response">The positive assertion response that was just received by the Relying Party.</param>
        /// <param name="relyingParty">The relying party.</param>
        private PositiveAuthenticationResponse(PositiveAssertionResponse response, OpenIdRelyingParty relyingParty)
            : base(response)
        {
            Requires.NotNull(relyingParty, "relyingParty");

            this.Endpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier(
                this.Response.ClaimedIdentifier,
                this.Response.GetReturnToArgument(AuthenticationRequest.UserSuppliedIdentifierParameterName),
                this.Response.LocalIdentifier,
                new ProviderEndpointDescription(this.Response.ProviderEndpoint, this.Response.Version),
                null,
                null);

            Logger.OpenId.InfoFormat("Received identity assertion for {0} via {1}.", this.Response.ClaimedIdentifier, this.Provider.Uri);
        }
Exemple #18
0
        /// <summary>
        /// Send an identity assertion on behalf of one of this Provider's
        /// members in order to redirect the user agent to a relying party
        /// web site and log him/her in immediately in one uninterrupted step.
        /// </summary>
        /// <param name="providerEndpoint">The absolute URL on the Provider site that receives OpenID messages.</param>
        /// <param name="relyingParty">The URL of the Relying Party web site.
        /// This will typically be the home page, but may be a longer URL if
        /// that Relying Party considers the scope of its realm to be more specific.
        /// The URL provided here must allow discovery of the Relying Party's
        /// XRDS document that advertises its OpenID RP endpoint.</param>
        /// <param name="claimedIdentifier">The Identifier you are asserting your member controls.</param>
        /// <param name="localIdentifier">The Identifier you know your user by internally.  This will typically
        /// be the same as <paramref name="claimedIdentifier"/>.</param>
        /// <param name="extensions">The extensions.</param>
        /// <returns>
        /// A <see cref="UserAgentResponse"/> object describing the HTTP response to send
        /// the user agent to allow the redirect with assertion to happen.
        /// </returns>
        public UserAgentResponse PrepareUnsolicitedAssertion(Uri providerEndpoint, Realm relyingParty, Identifier claimedIdentifier, Identifier localIdentifier, params IExtensionMessage[] extensions)
        {
            ErrorUtilities.VerifyArgumentNotNull(providerEndpoint, "providerEndpoint");
            ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");
            ErrorUtilities.VerifyArgumentNotNull(claimedIdentifier, "claimedIdentifier");
            ErrorUtilities.VerifyArgumentNotNull(localIdentifier, "localIdentifier");
            ErrorUtilities.VerifyArgumentNamed(providerEndpoint.IsAbsoluteUri, "providerEndpoint", OpenIdStrings.AbsoluteUriRequired);

            // Although the RP should do their due diligence to make sure that this OP
            // is authorized to send an assertion for the given claimed identifier,
            // do due diligence by performing our own discovery on the claimed identifier
            // and make sure that it is tied to this OP and OP local identifier.
            var serviceEndpoint     = DotNetOpenAuth.OpenId.RelyingParty.ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, localIdentifier, new ProviderEndpointDescription(providerEndpoint, Protocol.Default.Version), null, null);
            var discoveredEndpoints = claimedIdentifier.Discover(this.WebRequestHandler);

            if (!discoveredEndpoints.Contains(serviceEndpoint))
            {
                Logger.DebugFormat(
                    "Failed to send unsolicited assertion for {0} because its discovered services did not include this endpoint.  This endpoint: {1}{2}  Discovered endpoints: {1}{3}",
                    claimedIdentifier,
                    Environment.NewLine,
                    serviceEndpoint,
                    discoveredEndpoints.ToStringDeferred(true));
                ErrorUtilities.ThrowProtocol(OpenIdStrings.UnsolicitedAssertionForUnrelatedClaimedIdentifier, claimedIdentifier);
            }

            Logger.InfoFormat("Preparing unsolicited assertion for {0}", claimedIdentifier);
            var returnToEndpoint = relyingParty.Discover(this.WebRequestHandler, true).FirstOrDefault();

            ErrorUtilities.VerifyProtocol(returnToEndpoint != null, OpenIdStrings.NoRelyingPartyEndpointDiscovered, relyingParty);

            var positiveAssertion = new PositiveAssertionResponse(returnToEndpoint)
            {
                ProviderEndpoint  = providerEndpoint,
                ClaimedIdentifier = claimedIdentifier,
                LocalIdentifier   = localIdentifier,
            };

            if (extensions != null)
            {
                foreach (IExtensionMessage extension in extensions)
                {
                    positiveAssertion.Extensions.Add(extension);
                }
            }

            return(this.Channel.PrepareResponse(positiveAssertion));
        }
Exemple #19
0
        public void ExactPositiveAssertionPreservation()
        {
            var rp = CreateRelyingParty(true);

            // Initialize the positive assertion response with some data that is NOT in normalized form.
            var positiveAssertion = new PositiveAssertionResponse(Protocol.Default.Version, RPUri)
            {
                ClaimedIdentifier = "https://HOST:443/a",
                ProviderEndpoint  = new Uri("https://anotherHOST:443/b"),
            };

            var checkAuth = new CheckAuthenticationRequest(positiveAssertion, rp.Channel);
            var actual    = rp.Channel.MessageDescriptions.GetAccessor(checkAuth);

            Assert.AreEqual("https://HOST:443/a", actual["openid.claimed_id"]);
            Assert.AreEqual("https://anotherHOST:443/b", actual["openid.op_endpoint"]);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="PositiveAuthenticationResponse"/> class.
        /// </summary>
        /// <param name="response">The positive assertion response that was just received by the Relying Party.</param>
        /// <param name="relyingParty">The relying party.</param>
        internal PositiveAuthenticationResponse(PositiveAssertionResponse response, OpenIdRelyingParty relyingParty)
        {
            ErrorUtilities.VerifyArgumentNotNull(response, "response");
            ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");

            this.response     = response;
            this.relyingParty = relyingParty;

            this.endpoint = ServiceEndpoint.CreateForClaimedIdentifier(
                this.response.ClaimedIdentifier,
                this.response.GetReturnToArgument(AuthenticationRequest.UserSuppliedIdentifierParameterName),
                this.response.LocalIdentifier,
                new ProviderEndpointDescription(this.response.ProviderEndpoint, this.response.Version),
                null,
                null);

            this.VerifyDiscoveryMatchesAssertion();
        }
        public async Task Valid()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();
            ClaimsResponse            extension = new ClaimsResponse();

            assertion.Extensions.Add(extension);
            var rp           = CreateRelyingParty();
            var authResponse = await PositiveAuthenticationResponse.CreateAsync(assertion, rp, CancellationToken.None);

            Assert.AreEqual(AuthenticationStatus.Authenticated, authResponse.Status);
            Assert.IsNull(authResponse.Exception);
            Assert.AreEqual((string)assertion.ClaimedIdentifier, (string)authResponse.ClaimedIdentifier);
            Assert.AreEqual(authResponse.Endpoint.FriendlyIdentifierForDisplay, authResponse.FriendlyIdentifierForDisplay);
            Assert.AreSame(extension, authResponse.GetUntrustedExtension(typeof(ClaimsResponse)));
            Assert.AreSame(extension, authResponse.GetUntrustedExtension <ClaimsResponse>());
            Assert.IsNull(authResponse.GetCallbackArgument("a"));
            Assert.AreEqual(0, authResponse.GetCallbackArguments().Count);
        }
Exemple #22
0
        public void Valid()
        {
            PositiveAssertionResponse assertion = this.GetPositiveAssertion();
            ClaimsResponse            extension = new ClaimsResponse();

            assertion.Extensions.Add(extension);
            var rp                   = CreateRelyingParty();
            var authResponse         = new PositiveAuthenticationResponse(assertion, rp);
            var authResponseAccessor = PositiveAuthenticationResponse_Accessor.AttachShadow(authResponse);

            Assert.AreEqual(AuthenticationStatus.Authenticated, authResponse.Status);
            Assert.IsNull(authResponse.Exception);
            Assert.AreEqual((string)assertion.ClaimedIdentifier, (string)authResponse.ClaimedIdentifier);
            Assert.AreEqual(authResponse.Endpoint.FriendlyIdentifierForDisplay, authResponse.FriendlyIdentifierForDisplay);
            Assert.AreSame(extension, authResponse.GetUntrustedExtension(typeof(ClaimsResponse)));
            Assert.AreSame(extension, authResponse.GetUntrustedExtension <ClaimsResponse>());
            Assert.IsNull(authResponse.GetCallbackArgument("a"));
            Assert.AreEqual(0, authResponse.GetCallbackArguments().Count);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AuthenticationRequest"/> class.
        /// </summary>
        /// <param name="provider">The provider that received the request.</param>
        /// <param name="request">The incoming authentication request message.</param>
        internal AuthenticationRequest(OpenIdProvider provider, CheckIdRequest request)
            : base(provider, request)
        {
            this.positiveResponse = new PositiveAssertionResponse(request);
            this.negativeResponse = new NegativeAssertionResponse(request, provider.Channel);

            if (this.ClaimedIdentifier == Protocol.ClaimedIdentifierForOPIdentifier &&
                Protocol.ClaimedIdentifierForOPIdentifier != null)
            {
                // Force the hosting OP to deal with identifier_select by nulling out the two identifiers.
                this.IsDirectedIdentity = true;
                this.positiveResponse.ClaimedIdentifier = null;
                this.positiveResponse.LocalIdentifier   = null;
            }

            // URL delegation is only detectable from 2.0 RPs, since openid.claimed_id isn't included from 1.0 RPs.
            // If the openid.claimed_id is present, and if it's different than the openid.identity argument, then
            // the RP has discovered a claimed identifier that has delegated authentication to this Provider.
            this.IsDelegatedIdentifier = this.ClaimedIdentifier != null && this.ClaimedIdentifier != this.LocalIdentifier;
        }
        public Task <MessageProtections?> ProcessIncomingMessageAsync(IProtocolMessage message, CancellationToken cancellationToken)
        {
            IndirectSignedResponse response = message as IndirectSignedResponse;

            if (response != null && response.Version.Major < 2)
            {
                // GetReturnToArgument may return parameters that are not signed,
                // but we must allow for that since in OpenID 1.x, a stateless RP has
                // no way to preserve the provider endpoint and claimed identifier otherwise.
                // We'll verify the positive assertion later in the
                // RelyingParty.PositiveAuthenticationResponse constructor anyway.
                // If this is a 1.0 OP signed response without these parameters then we didn't initiate
                // the request ,and since 1.0 OPs are not supposed to be able to send unsolicited
                // assertions it's an invalid case that we throw an exception for.
                if (response.ProviderEndpoint == null)
                {
                    string op_endpoint = response.GetReturnToArgument(ProviderEndpointParameterName);
                    ErrorUtilities.VerifyProtocol(op_endpoint != null, MessagingStrings.RequiredParametersMissing, message.GetType().Name, ProviderEndpointParameterName);
                    response.ProviderEndpoint = new Uri(op_endpoint);
                }

                PositiveAssertionResponse authResponse = response as PositiveAssertionResponse;
                if (authResponse != null)
                {
                    if (authResponse.ClaimedIdentifier == null)
                    {
                        string claimedId = response.GetReturnToArgument(ClaimedIdentifierParameterName);
                        ErrorUtilities.VerifyProtocol(claimedId != null, MessagingStrings.RequiredParametersMissing, message.GetType().Name, ClaimedIdentifierParameterName);
                        authResponse.ClaimedIdentifier = claimedId;
                    }
                }

                return(NoneTask);
            }

            return(NullTask);
        }
Exemple #25
0
        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>
        /// Prepares an identity assertion on behalf of one of this Provider's
        /// members in order to redirect the user agent to a relying party
        /// web site and log him/her in immediately in one uninterrupted step.
        /// </summary>
        /// <param name="providerEndpoint">The absolute URL on the Provider site that receives OpenID messages.</param>
        /// <param name="relyingPartyRealm">The URL of the Relying Party web site.
        /// This will typically be the home page, but may be a longer URL if
        /// that Relying Party considers the scope of its realm to be more specific.
        /// The URL provided here must allow discovery of the Relying Party's
        /// XRDS document that advertises its OpenID RP endpoint.</param>
        /// <param name="claimedIdentifier">The Identifier you are asserting your member controls.</param>
        /// <param name="localIdentifier">The Identifier you know your user by internally.  This will typically
        /// be the same as <paramref name="claimedIdentifier" />.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="extensions">The extensions.</param>
        /// <returns>
        /// A <see cref="HttpResponseMessage" /> object describing the HTTP response to send
        /// the user agent to allow the redirect with assertion to happen.
        /// </returns>
        public async Task <HttpResponseMessage> PrepareUnsolicitedAssertionAsync(Uri providerEndpoint, Realm relyingPartyRealm, Identifier claimedIdentifier, Identifier localIdentifier, CancellationToken cancellationToken = default(CancellationToken), params IExtensionMessage[] extensions)
        {
            Requires.NotNull(providerEndpoint, "providerEndpoint");
            Requires.That(providerEndpoint.IsAbsoluteUri, "providerEndpoint", OpenIdStrings.AbsoluteUriRequired);
            Requires.NotNull(relyingPartyRealm, "relyingPartyRealm");
            Requires.NotNull(claimedIdentifier, "claimedIdentifier");
            Requires.NotNull(localIdentifier, "localIdentifier");
            RequiresEx.ValidState(this.Channel.HostFactories != null);

            // Although the RP should do their due diligence to make sure that this OP
            // is authorized to send an assertion for the given claimed identifier,
            // do due diligence by performing our own discovery on the claimed identifier
            // and make sure that it is tied to this OP and OP local identifier.
            if (this.SecuritySettings.UnsolicitedAssertionVerification != ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel.NeverVerify)
            {
                var serviceEndpoint     = IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, localIdentifier, new ProviderEndpointDescription(providerEndpoint, Protocol.Default.Version), null, null);
                var discoveredEndpoints = await this.discoveryServices.DiscoverAsync(claimedIdentifier, cancellationToken);

                if (!discoveredEndpoints.Contains(serviceEndpoint))
                {
                    Logger.OpenId.WarnFormat(
                        "Failed to send unsolicited assertion for {0} because its discovered services did not include this endpoint: {1}{2}{1}Discovered endpoints: {1}{3}",
                        claimedIdentifier,
                        Environment.NewLine,
                        serviceEndpoint,
                        discoveredEndpoints.ToStringDeferred(true));

                    // Only FAIL if the setting is set for it.
                    if (this.securitySettings.UnsolicitedAssertionVerification == ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel.RequireSuccess)
                    {
                        ErrorUtilities.ThrowProtocol(OpenIdStrings.UnsolicitedAssertionForUnrelatedClaimedIdentifier, claimedIdentifier);
                    }
                }
            }

            Logger.OpenId.InfoFormat("Preparing unsolicited assertion for {0}", claimedIdentifier);
            RelyingPartyEndpointDescription returnToEndpoint = null;
            var returnToEndpoints = await relyingPartyRealm.DiscoverReturnToEndpointsAsync(this.Channel.HostFactories, true, cancellationToken);

            if (returnToEndpoints != null)
            {
                returnToEndpoint = returnToEndpoints.FirstOrDefault();
            }
            ErrorUtilities.VerifyProtocol(returnToEndpoint != null, OpenIdStrings.NoRelyingPartyEndpointDiscovered, relyingPartyRealm);

            var positiveAssertion = new PositiveAssertionResponse(returnToEndpoint)
            {
                ProviderEndpoint  = providerEndpoint,
                ClaimedIdentifier = claimedIdentifier,
                LocalIdentifier   = localIdentifier,
            };

            if (extensions != null)
            {
                foreach (IExtensionMessage extension in extensions)
                {
                    positiveAssertion.Extensions.Add(extension);
                }
            }

            Reporting.RecordEventOccurrence(this, "PrepareUnsolicitedAssertion");
            return(await this.Channel.PrepareResponseAsync(positiveAssertion, cancellationToken));
        }
        /// <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="recipient">The intended or actual recipient of the request message.</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 IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary <string, string> fields)
        {
            ErrorUtilities.VerifyArgumentNotNull(recipient, "recipient");
            ErrorUtilities.VerifyArgumentNotNull(fields, "fields");

            RequestBase message = null;

            // Discern the OpenID version of the message.
            Protocol protocol = Protocol.V11;
            string   ns;

            if (fields.TryGetValue(Protocol.V20.openid.ns, out ns))
            {
                ErrorUtilities.VerifyProtocol(string.Equals(ns, Protocol.OpenId2Namespace, StringComparison.Ordinal), MessagingStrings.UnexpectedMessagePartValue, Protocol.V20.openid.ns, ns);
                protocol = Protocol.V20;
            }

            string mode;

            if (fields.TryGetValue(protocol.openid.mode, out mode))
            {
                if (string.Equals(mode, protocol.Args.Mode.associate))
                {
                    if (fields.ContainsKey(protocol.openid.dh_consumer_public))
                    {
                        message = new AssociateDiffieHellmanRequest(protocol.Version, recipient.Location);
                    }
                    else
                    {
                        message = new AssociateUnencryptedRequest(protocol.Version, recipient.Location);
                    }
                }
                else if (string.Equals(mode, protocol.Args.Mode.checkid_setup) ||
                         string.Equals(mode, protocol.Args.Mode.checkid_immediate))
                {
                    AuthenticationRequestMode authMode = string.Equals(mode, protocol.Args.Mode.checkid_immediate) ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup;
                    if (fields.ContainsKey(protocol.openid.identity))
                    {
                        message = new CheckIdRequest(protocol.Version, recipient.Location, authMode);
                    }
                    else
                    {
                        message = new SignedResponseRequest(protocol.Version, recipient.Location, authMode);
                    }
                }
                else if (string.Equals(mode, protocol.Args.Mode.cancel) ||
                         (string.Equals(mode, protocol.Args.Mode.setup_needed) && (protocol.Version.Major >= 2 || fields.ContainsKey(protocol.openid.user_setup_url))))
                {
                    message = new NegativeAssertionResponse(protocol.Version, recipient.Location, mode);
                }
                else if (string.Equals(mode, protocol.Args.Mode.id_res))
                {
                    if (fields.ContainsKey(protocol.openid.identity))
                    {
                        message = new PositiveAssertionResponse(protocol.Version, recipient.Location);
                    }
                    else
                    {
                        message = new IndirectSignedResponse(protocol.Version, recipient.Location);
                    }
                }
                else if (string.Equals(mode, protocol.Args.Mode.check_authentication))
                {
                    message = new CheckAuthenticationRequest(protocol.Version, recipient.Location);
                }
                else if (string.Equals(mode, protocol.Args.Mode.error))
                {
                    message = new IndirectErrorResponse(protocol.Version, recipient.Location);
                }
                else
                {
                    ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessagePartValue, protocol.openid.mode, mode);
                }
            }

            if (message != null)
            {
                message.SetAsIncoming();
            }

            return(message);
        }
Exemple #28
0
 public PositiveAuthenticationResponse1(PositiveAssertionResponse response, OpenIdRelyingParty relyingParty) : base(response, relyingParty)
 {
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SimpleXrdsProviderEndpoint"/> class.
 /// </summary>
 /// <param name="positiveAssertion">The positive assertion.</param>
 internal SimpleXrdsProviderEndpoint(PositiveAssertionResponse positiveAssertion)
 {
     this.Uri     = positiveAssertion.ProviderEndpoint;
     this.Version = positiveAssertion.Version;
 }
Exemple #30
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();
        }