public void UserSetupUrl() { // Construct a V1 immediate request Protocol protocol = Protocol.V11; OpenIdProvider provider = this.CreateProvider(); CheckIdRequest immediateRequest = new CheckIdRequest(protocol.Version, OPUri, DotNetOpenAuth.OpenId.RelyingParty.AuthenticationRequestMode.Immediate); immediateRequest.Realm = RPRealmUri; immediateRequest.ReturnTo = RPUri; immediateRequest.LocalIdentifier = "http://somebody"; AuthenticationRequest request = new AuthenticationRequest(provider, immediateRequest); // Now simulate the request being rejected and extract the user_setup_url request.IsAuthenticated = false; Uri userSetupUrl = ((NegativeAssertionResponse)request.Response).UserSetupUrl; Assert.IsNotNull(userSetupUrl); // Now construct a new request as if it had just come in. HttpRequestInfo httpRequest = new HttpRequestInfo { UrlBeforeRewriting = userSetupUrl }; var setupRequest = AuthenticationRequest_Accessor.AttachShadow(provider.GetRequest(httpRequest)); CheckIdRequest_Accessor setupRequestMessage = setupRequest.RequestMessage; // And make sure all the right properties are set. Assert.IsFalse(setupRequestMessage.Immediate); Assert.AreEqual(immediateRequest.Realm, setupRequestMessage.Realm); Assert.AreEqual(immediateRequest.ReturnTo, setupRequestMessage.ReturnTo); Assert.AreEqual(immediateRequest.LocalIdentifier, setupRequestMessage.LocalIdentifier); Assert.AreEqual(immediateRequest.Version, setupRequestMessage.Version); }
public async Task UserSetupUrl() { // Construct a V1 immediate request Protocol protocol = Protocol.V11; OpenIdProvider provider = this.CreateProvider(); var immediateRequest = new CheckIdRequest(protocol.Version, OPUri, DotNetOpenAuth.OpenId.AuthenticationRequestMode.Immediate); immediateRequest.Realm = RPRealmUri; immediateRequest.ReturnTo = RPUri; immediateRequest.LocalIdentifier = "http://somebody"; var request = new AuthenticationRequest(provider, immediateRequest); // Now simulate the request being rejected and extract the user_setup_url request.IsAuthenticated = false; Uri userSetupUrl = ((NegativeAssertionResponse)await request.GetResponseAsync(CancellationToken.None)).UserSetupUrl; Assert.IsNotNull(userSetupUrl); // Now construct a new request as if it had just come in. var httpRequest = new HttpRequestMessage(HttpMethod.Get, userSetupUrl); var setupRequest = (AuthenticationRequest)await provider.GetRequestAsync(httpRequest); var setupRequestMessage = (CheckIdRequest)setupRequest.RequestMessage; // And make sure all the right properties are set. Assert.IsFalse(setupRequestMessage.Immediate); Assert.AreEqual(immediateRequest.Realm, setupRequestMessage.Realm); Assert.AreEqual(immediateRequest.ReturnTo, setupRequestMessage.ReturnTo); Assert.AreEqual(immediateRequest.LocalIdentifier, setupRequestMessage.LocalIdentifier); Assert.AreEqual(immediateRequest.Version, setupRequestMessage.Version); }
public void UserSetupUrlSetForV1Immediate() { var immediateRequestV1 = new CheckIdRequest(Protocol.V10.Version, OPUri, AuthenticationRequestMode.Immediate); immediateRequestV1.ReturnTo = RPUri; var response = new NegativeAssertionResponse(immediateRequestV1); response.UserSetupUrl = new Uri("http://usersetup"); response.EnsureValidMessage(); }
/// <summary> /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class. /// </summary> /// <param name="request"> /// The authentication request that caused this assertion to be generated. /// </param> internal PositiveAssertionResponse(CheckIdRequest request) : base(request) { this.ClaimedIdentifier = request.ClaimedIdentifier; this.LocalIdentifier = request.LocalIdentifier; //ERIC'S CODE - This is where we can inject the symval to an authenticated message this.SymvalIdentifier = "OP[[TESTHASH()]]"; }
/// <summary> /// Gets the value for the openid.mode that is appropriate for this response. /// </summary> /// <param name="request">The request that we're responding to.</param> /// <returns>The value of the openid.mode parameter to use.</returns> private static string GetMode(CheckIdRequest request) { ErrorUtilities.VerifyArgumentNotNull(request, "request"); Protocol protocol = Protocol.Lookup(request.Version); return(request.Immediate ? protocol.Args.Mode.setup_needed : protocol.Args.Mode.cancel); }
/// <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 { ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent); 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 { 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.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; }
/// <summary> /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class. /// </summary> /// <param name="request"> /// The authentication request that caused this assertion to be generated. /// </param> /// ERIC'S CODE //internal PositiveAssertionResponse(CheckIdRequest request) public PositiveAssertionResponse(CheckIdRequest request) : base(request) { //ERIC'S CODE - This is where we hash the code hashvalue_op = code_to_hash(SourceCode_OP); this.ClaimedIdentifier = request.ClaimedIdentifier; this.LocalIdentifier = request.LocalIdentifier; }
/// <summary> /// Initializes a new instance of the <see cref="NegativeAssertionResponse"/> class. /// </summary> /// <param name="request">The request that the relying party sent.</param> /// <param name="channel">The channel to use to simulate construction of the user_setup_url, if applicable. May be null, but the user_setup_url will not be constructed.</param> internal NegativeAssertionResponse(CheckIdRequest request, Channel channel) : base(request, GetMode(request)) { // If appropriate, and when we're provided with a channel to do it, // go ahead and construct the user_setup_url if (this.Version.Major < 2 && request.Immediate && channel != null) { this.UserSetupUrl = ConstructUserSetupUrl(request, channel); } }
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 IndirectSignedResponse(this.request); this.unsolicited = new IndirectSignedResponse(this.protocol.Version, RPUri); }
public override void SetUp() { base.SetUp(); this.protocol = Protocol.Default; this.provider = this.CreateProvider(); this.checkIdRequest = new CheckIdRequest(this.protocol.Version, OPUri, DotNetOpenAuth.OpenId.AuthenticationRequestMode.Setup); this.checkIdRequest.Realm = RPRealmUri; this.checkIdRequest.ReturnTo = RPUri; this.request = new AuthenticationRequest(this.provider, this.checkIdRequest); }
public override void SetUp() { base.SetUp(); var op = this.CreateProvider(); var rpRequest = new CheckIdRequest(Protocol.Default.Version, OPUri, DotNetOpenAuth.OpenId.AuthenticationRequestMode.Setup); rpRequest.ReturnTo = RPUri; this.extensions = rpRequest.Extensions; this.request = new AuthenticationRequest(op, rpRequest); this.request.IsAuthenticated = true; }
public void UserSetupUrlNotRequiredInV1SetupOrV2() { var setupRequestV1 = new CheckIdRequest(Protocol.V10.Version, OPUri, AuthenticationRequestMode.Setup); setupRequestV1.ReturnTo = RPUri; new NegativeAssertionResponse(setupRequestV1).EnsureValidMessage(); var setupRequestV2 = new CheckIdRequest(Protocol.V20.Version, OPUri, AuthenticationRequestMode.Setup); setupRequestV2.ReturnTo = RPUri; new NegativeAssertionResponse(setupRequestV2).EnsureValidMessage(); var immediateRequestV2 = new CheckIdRequest(Protocol.V20.Version, OPUri, AuthenticationRequestMode.Immediate); immediateRequestV2.ReturnTo = RPUri; new NegativeAssertionResponse(immediateRequestV2).EnsureValidMessage(); }
/// <summary> /// Constructs the value for the user_setup_url parameter to be sent back /// in negative assertions in response to OpenID 1.x RP's checkid_immediate requests. /// </summary> /// <param name="immediateRequest">The immediate request.</param> /// <param name="channel">The channel to use to simulate construction of the message.</param> /// <returns>The value to use for the user_setup_url parameter.</returns> private static Uri ConstructUserSetupUrl(CheckIdRequest immediateRequest, Channel channel) { Contract.Requires <ArgumentNullException>(immediateRequest != null); Contract.Requires <ArgumentNullException>(channel != null); ErrorUtilities.VerifyInternal(immediateRequest.Immediate, "Only immediate requests should be sent here."); var setupRequest = new CheckIdRequest(immediateRequest.Version, immediateRequest.Recipient, AuthenticationRequestMode.Setup); setupRequest.LocalIdentifier = immediateRequest.LocalIdentifier; setupRequest.ReturnTo = immediateRequest.ReturnTo; setupRequest.Realm = immediateRequest.Realm; setupRequest.AssociationHandle = immediateRequest.AssociationHandle; return(channel.PrepareResponse(setupRequest).GetDirectUriRequest(channel)); }
public void IsReturnUrlDiscoverable() { Protocol protocol = Protocol.Default; OpenIdProvider provider = this.CreateProvider(); CheckIdRequest checkIdRequest = new CheckIdRequest(protocol.Version, OPUri, DotNetOpenAuth.OpenId.RelyingParty.AuthenticationRequestMode.Setup); checkIdRequest.Realm = RPRealmUri; checkIdRequest.ReturnTo = RPUri; AuthenticationRequest request = new AuthenticationRequest(provider, checkIdRequest); Assert.IsFalse(request.IsReturnUrlDiscoverable(this.MockResponder.MockWebRequestHandler)); this.MockResponder.RegisterMockRPDiscovery(); request = new AuthenticationRequest(provider, checkIdRequest); Assert.IsTrue(request.IsReturnUrlDiscoverable(this.MockResponder.MockWebRequestHandler)); }
/// <summary> /// Constructs the value for the user_setup_url parameter to be sent back /// in negative assertions in response to OpenID 1.x RP's checkid_immediate requests. /// </summary> /// <param name="immediateRequest">The immediate request.</param> /// <param name="channel">The channel to use to simulate construction of the message.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The value to use for the user_setup_url parameter.</returns> private static async Task <Uri> ConstructUserSetupUrlAsync(CheckIdRequest immediateRequest, Channel channel, CancellationToken cancellationToken) { Requires.NotNull(immediateRequest, "immediateRequest"); Requires.NotNull(channel, "channel"); ErrorUtilities.VerifyInternal(immediateRequest.Immediate, "Only immediate requests should be sent here."); var setupRequest = new CheckIdRequest(immediateRequest.Version, immediateRequest.Recipient, AuthenticationRequestMode.Setup); setupRequest.LocalIdentifier = immediateRequest.LocalIdentifier; setupRequest.ReturnTo = immediateRequest.ReturnTo; setupRequest.Realm = immediateRequest.Realm; setupRequest.AssociationHandle = immediateRequest.AssociationHandle; var response = await channel.PrepareResponseAsync(setupRequest, cancellationToken); return(response.GetDirectUriRequest()); }
public void Serializable() { OpenIdProvider provider = this.CreateProvider(); CheckIdRequest immediateRequest = new CheckIdRequest(Protocol.Default.Version, OPUri, DotNetOpenAuth.OpenId.AuthenticationRequestMode.Immediate); immediateRequest.Realm = RPRealmUri; immediateRequest.ReturnTo = RPUri; immediateRequest.LocalIdentifier = "http://somebody"; AuthenticationRequest request = new AuthenticationRequest(provider, immediateRequest); MemoryStream ms = new MemoryStream(); IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, request); ms.Position = 0; var req2 = (AuthenticationRequest)formatter.Deserialize(ms); Assert.That(req2, Is.Not.Null); }
/// <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(); }
public void Mode() { var setupRequestV1 = new CheckIdRequest(Protocol.V10.Version, OPUri, AuthenticationRequestMode.Setup); setupRequestV1.ReturnTo = RPUri; var immediateRequestV1 = new CheckIdRequest(Protocol.V10.Version, OPUri, AuthenticationRequestMode.Immediate); immediateRequestV1.ReturnTo = RPUri; var setupRequestV2 = new CheckIdRequest(Protocol.V20.Version, OPUri, AuthenticationRequestMode.Setup); setupRequestV2.ReturnTo = RPUri; var immediateRequestV2 = new CheckIdRequest(Protocol.V20.Version, OPUri, AuthenticationRequestMode.Immediate); immediateRequestV2.ReturnTo = RPUri; Assert.AreEqual("id_res", new NegativeAssertionResponse(immediateRequestV1).Mode); Assert.AreEqual("cancel", new NegativeAssertionResponse(setupRequestV1).Mode); Assert.AreEqual("setup_needed", new NegativeAssertionResponse(immediateRequestV2).Mode); Assert.AreEqual("cancel", new NegativeAssertionResponse(setupRequestV2).Mode); Assert.IsTrue(new NegativeAssertionResponse(immediateRequestV1).Immediate); Assert.IsFalse(new NegativeAssertionResponse(setupRequestV1).Immediate); Assert.IsTrue(new NegativeAssertionResponse(immediateRequestV2).Immediate); Assert.IsFalse(new NegativeAssertionResponse(setupRequestV2).Immediate); }
/// <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) { Requires.NotNull(provider, "provider"); this.positiveResponse = new PositiveAssertionResponse(request); 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; Reporting.RecordEventOccurrence("AuthenticationRequest.IsDelegatedIdentifier", this.IsDelegatedIdentifier.ToString()); }
/// <summary> /// Constructs the value for the user_setup_url parameter to be sent back /// in negative assertions in response to OpenID 1.x RP's checkid_immediate requests. /// </summary> /// <param name="immediateRequest">The immediate request.</param> /// <param name="channel">The channel to use to simulate construction of the message.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The value to use for the user_setup_url parameter.</returns> private static async Task<Uri> ConstructUserSetupUrlAsync(CheckIdRequest immediateRequest, Channel channel, CancellationToken cancellationToken) { Requires.NotNull(immediateRequest, "immediateRequest"); Requires.NotNull(channel, "channel"); ErrorUtilities.VerifyInternal(immediateRequest.Immediate, "Only immediate requests should be sent here."); var setupRequest = new CheckIdRequest(immediateRequest.Version, immediateRequest.Recipient, AuthenticationRequestMode.Setup); setupRequest.LocalIdentifier = immediateRequest.LocalIdentifier; setupRequest.ReturnTo = immediateRequest.ReturnTo; setupRequest.Realm = immediateRequest.Realm; setupRequest.AssociationHandle = immediateRequest.AssociationHandle; var response = await channel.PrepareResponseAsync(setupRequest, cancellationToken); return response.GetDirectUriRequest(); }
public void Setup() { CheckIdRequest request = new CheckIdRequest(Protocol.V20.Version, OPUri, AuthenticationRequestMode.Immediate); request.ReturnTo = RPUri; this.response = new IndirectErrorResponse(request); }
/// <summary> /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class. /// </summary> /// <param name="request"> /// The authentication request that caused this assertion to be generated. /// </param> internal PositiveAssertionResponse(CheckIdRequest request) : base(request) { this.ClaimedIdentifier = request.ClaimedIdentifier; this.LocalIdentifier = request.LocalIdentifier; }
/// <summary> /// Gets the value for the openid.mode that is appropriate for this response. /// </summary> /// <param name="request">The request that we're responding to.</param> /// <returns>The value of the openid.mode parameter to use.</returns> private static string GetMode(CheckIdRequest request) { ErrorUtilities.VerifyArgumentNotNull(request, "request"); Protocol protocol = Protocol.Lookup(request.Version); return request.Immediate ? protocol.Args.Mode.setup_needed : protocol.Args.Mode.cancel; }
/// <summary> /// Creates the request message to send to the Provider, /// based on the properties in this instance. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The message to send to the Provider. /// </returns> private async Task<SignedResponseRequest> CreateRequestMessageAsync(CancellationToken cancellationToken) { Association association = await this.GetAssociationAsync(cancellationToken); SignedResponseRequest request; if (!this.IsExtensionOnly) { CheckIdRequest authRequest = new CheckIdRequest(this.DiscoveryResult.Version, this.DiscoveryResult.ProviderEndpoint, this.Mode); authRequest.ClaimedIdentifier = this.DiscoveryResult.ClaimedIdentifier; authRequest.LocalIdentifier = this.DiscoveryResult.ProviderLocalIdentifier; request = authRequest; } else { request = new SignedResponseRequest(this.DiscoveryResult.Version, this.DiscoveryResult.ProviderEndpoint, this.Mode); } request.Realm = this.Realm; request.ReturnTo = this.ReturnToUrl; request.AssociationHandle = association != null ? association.Handle : null; request.SignReturnTo = this.returnToArgsMustBeSigned; request.AddReturnToArguments(this.returnToArgs); if (this.DiscoveryResult.UserSuppliedIdentifier != null && OpenIdElement.Configuration.RelyingParty.PreserveUserSuppliedIdentifier) { request.AddReturnToArguments(UserSuppliedIdentifierParameterName, this.DiscoveryResult.UserSuppliedIdentifier.OriginalString); } foreach (IOpenIdMessageExtension extension in this.extensions) { request.Extensions.Add(extension); } return request; }
private HttpRequestInfo CreateCheckIdRequest(bool sharedAssociation) { var rp = CreateRelyingParty(true); CheckIdRequest checkidMessage = new CheckIdRequest( Protocol.Default.Version, OPUri, DotNetOpenAuth.OpenId.RelyingParty.AuthenticationRequestMode.Setup); if (sharedAssociation) { checkidMessage.AssociationHandle = SharedAssociationHandle; } checkidMessage.ClaimedIdentifier = OPLocalIdentifiers[0]; checkidMessage.LocalIdentifier = OPLocalIdentifiers[0]; checkidMessage.Realm = RPRealmUri; checkidMessage.ReturnTo = RPUri; Channel rpChannel = rp.Channel; UriBuilder receiver = new UriBuilder(OPUri); receiver.Query = MessagingUtilities.CreateQueryString(rpChannel.MessageDescriptions.GetAccessor(checkidMessage)); var headers = new WebHeaderCollection(); var httpRequest = new HttpRequestInfo("GET", receiver.Uri, receiver.Uri.PathAndQuery, headers, null); return httpRequest; }
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> /// Initializes a new instance of the <see cref="NegativeAssertionResponse"/> class. /// </summary> /// <param name="request">The request that the relying party sent.</param> internal NegativeAssertionResponse(CheckIdRequest request) : this(request, null) { }
/// <summary> /// Creates the authentication request message to send to the Provider, /// based on the properties in this instance. /// </summary> /// <returns>The message to send to the Provider.</returns> private CheckIdRequest CreateRequestMessage() { Association association = this.GetAssociation(); CheckIdRequest request = new CheckIdRequest(this.endpoint.Protocol.Version, this.endpoint.ProviderEndpoint, this.Mode); request.ClaimedIdentifier = this.endpoint.ClaimedIdentifier; request.LocalIdentifier = this.endpoint.ProviderLocalIdentifier; request.Realm = this.Realm; request.ReturnTo = this.ReturnToUrl; request.AssociationHandle = association != null ? association.Handle : null; request.AddReturnToArguments(this.returnToArgs); if (this.endpoint.UserSuppliedIdentifier != null) { request.AddReturnToArguments(UserSuppliedIdentifierParameterName, this.endpoint.UserSuppliedIdentifier); } foreach (IOpenIdMessageExtension extension in this.extensions) { request.Extensions.Add(extension); } return request; }
private void ParameterizedAuthenticationTest(Protocol protocol, bool statelessRP, bool sharedAssociation, bool positive, bool immediate, bool tamper) { Contract.Requires<ArgumentException>(!statelessRP || !sharedAssociation, "The RP cannot be stateless while sharing an association with the OP."); Contract.Requires<ArgumentException>(positive || !tamper, "Cannot tamper with a negative response."); var securitySettings = new ProviderSecuritySettings(); var cryptoKeyStore = new MemoryCryptoKeyStore(); var associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore); Association association = sharedAssociation ? HmacShaAssociation.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(); }
/// <summary> /// Constructs the value for the user_setup_url parameter to be sent back /// in negative assertions in response to OpenID 1.x RP's checkid_immediate requests. /// </summary> /// <param name="immediateRequest">The immediate request.</param> /// <param name="channel">The channel to use to simulate construction of the message.</param> /// <returns>The value to use for the user_setup_url parameter.</returns> private static Uri ConstructUserSetupUrl(CheckIdRequest immediateRequest, Channel channel) { Requires.NotNull(immediateRequest, "immediateRequest"); Requires.NotNull(channel, "channel"); ErrorUtilities.VerifyInternal(immediateRequest.Immediate, "Only immediate requests should be sent here."); var setupRequest = new CheckIdRequest(immediateRequest.Version, immediateRequest.Recipient, AuthenticationRequestMode.Setup); setupRequest.LocalIdentifier = immediateRequest.LocalIdentifier; setupRequest.ReturnTo = immediateRequest.ReturnTo; setupRequest.Realm = immediateRequest.Realm; setupRequest.AssociationHandle = immediateRequest.AssociationHandle; return channel.PrepareResponse(setupRequest).GetDirectUriRequest(channel); }
/// <summary> /// Creates the request message to send to the Provider, /// based on the properties in this instance. /// </summary> /// <returns>The message to send to the Provider.</returns> private SignedResponseRequest CreateRequestMessage() { Association association = this.GetAssociation(); SignedResponseRequest request; if (!this.IsExtensionOnly) { CheckIdRequest authRequest = new CheckIdRequest(this.DiscoveryResult.Version, this.DiscoveryResult.ProviderEndpoint, this.Mode); authRequest.ClaimedIdentifier = this.DiscoveryResult.ClaimedIdentifier; authRequest.LocalIdentifier = this.DiscoveryResult.ProviderLocalIdentifier; request = authRequest; } else { request = new SignedResponseRequest(this.DiscoveryResult.Version, this.DiscoveryResult.ProviderEndpoint, this.Mode); } request.Realm = this.Realm; request.ReturnTo = this.ReturnToUrl; request.AssociationHandle = association != null ? association.Handle : null; request.SignReturnTo = this.returnToArgsMustBeSigned; request.AddReturnToArguments(this.returnToArgs); if (this.DiscoveryResult.UserSuppliedIdentifier != null) { request.AddReturnToArguments(UserSuppliedIdentifierParameterName, this.DiscoveryResult.UserSuppliedIdentifier.OriginalString); } foreach (IOpenIdMessageExtension extension in this.extensions) { request.Extensions.Add(extension); } return request; }
/// <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()); } }