//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Test.OpenId.RelyingParty {
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.Messages;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.Test.Mocks;
using NUnit.Framework;
[TestFixture]
public class AuthenticationRequestTests : OpenIdTestBase {
private readonly Realm realm = new Realm("http://localhost/rp.aspx");
private readonly Identifier claimedId = "http://claimedId";
private readonly Identifier delegatedLocalId = "http://localId";
private readonly Protocol protocol = Protocol.Default;
private Uri returnTo;
[SetUp]
public override void SetUp() {
base.SetUp();
this.returnTo = new Uri("http://localhost/rp.aspx");
}
///
/// Verifies IsDirectedIdentity returns true when appropriate.
///
[Test]
public void IsDirectedIdentity() {
var iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId);
Assert.IsFalse(iauthRequest.IsDirectedIdentity);
iauthRequest = this.CreateAuthenticationRequest(IdentifierSelect, IdentifierSelect);
Assert.IsTrue(iauthRequest.IsDirectedIdentity);
}
///
/// Verifies ClaimedIdentifier behavior.
///
[Test]
public void ClaimedIdentifier() {
var iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.delegatedLocalId);
Assert.AreEqual(this.claimedId, iauthRequest.ClaimedIdentifier);
iauthRequest = this.CreateAuthenticationRequest(IdentifierSelect, IdentifierSelect);
Assert.IsNull(iauthRequest.ClaimedIdentifier, "In directed identity mode, the ClaimedIdentifier should be null.");
}
///
/// Verifies ProviderVersion behavior.
///
[Test]
public void ProviderVersion() {
var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId);
Assert.AreEqual(this.protocol.Version, authRequest.DiscoveryResult.Version);
}
///
/// Verifies RedirectingResponse.
///
[Test]
public async Task CreateRequestMessage() {
this.RegisterAutoProvider();
var rp = this.CreateRelyingParty();
Identifier id = this.GetMockIdentifier(ProtocolVersion.V20);
IAuthenticationRequest authRequest = await rp.CreateRequestAsync(id, this.realm, this.returnTo);
// Add some callback arguments
authRequest.AddCallbackArguments("a", "b");
authRequest.AddCallbackArguments(new Dictionary { { "c", "d" }, { "e", "f" } });
// Assembly an extension request.
var sregRequest = new ClaimsRequest();
sregRequest.Nickname = DemandLevel.Request;
authRequest.AddExtension(sregRequest);
// Construct the actual authentication request message.
var authRequestAccessor = (AuthenticationRequest)authRequest;
var req = await authRequestAccessor.CreateRequestMessageTestHookAsync(CancellationToken.None);
Assert.IsNotNull(req);
// Verify that callback arguments were included.
NameValueCollection callbackArguments = HttpUtility.ParseQueryString(req.ReturnTo.Query);
Assert.AreEqual("b", callbackArguments["a"]);
Assert.AreEqual("d", callbackArguments["c"]);
Assert.AreEqual("f", callbackArguments["e"]);
// Verify that extensions were included.
Assert.AreEqual(1, req.Extensions.Count);
Assert.IsTrue(req.Extensions.Contains(sregRequest));
}
///
/// Verifies that delegating authentication requests are filtered out when configured to do so.
///
[Test]
public async Task CreateFiltersDelegatingIdentifiers() {
Identifier id = GetMockIdentifier(ProtocolVersion.V20, false, true);
var rp = CreateRelyingParty();
// First verify that delegating identifiers work
Assert.IsTrue((await AuthenticationRequest.CreateAsync(id, rp, this.realm, this.returnTo, false, CancellationToken.None)).Any(), "The delegating identifier should have not generated any results.");
// Now disable them and try again.
rp.SecuritySettings.RejectDelegatingIdentifiers = true;
Assert.IsFalse((await AuthenticationRequest.CreateAsync(id, rp, this.realm, this.returnTo, false, CancellationToken.None)).Any(), "The delegating identifier should have not generated any results.");
}
///
/// Verifies the Provider property returns non-null.
///
[Test]
public void Provider() {
var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId);
Assert.IsNotNull(authRequest.Provider);
Assert.AreEqual(OPUri, authRequest.Provider.Uri);
Assert.AreEqual(this.protocol.Version, authRequest.Provider.Version);
}
///
/// Verifies that AddCallbackArguments adds query arguments to the return_to URL of the message.
///
[Test]
public async Task AddCallbackArgument() {
var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId);
Assert.AreEqual(this.returnTo, authRequest.ReturnToUrl);
authRequest.AddCallbackArguments("p1", "v1");
var response = (HttpResponseMessageWithOriginal)await authRequest.GetRedirectingResponseAsync(CancellationToken.None);
var req = (SignedResponseRequest)response.OriginalMessage;
NameValueCollection query = HttpUtility.ParseQueryString(req.ReturnTo.Query);
Assert.AreEqual("v1", query["p1"]);
}
///
/// Verifies that AddCallbackArguments replaces pre-existing parameter values
/// rather than appending them.
///
[Test]
public async Task AddCallbackArgumentClearsPreviousArgument() {
UriBuilder returnToWithArgs = new UriBuilder(this.returnTo);
returnToWithArgs.AppendQueryArgs(new Dictionary { { "p1", "v1" } });
this.returnTo = returnToWithArgs.Uri;
var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId);
authRequest.AddCallbackArguments("p1", "v2");
var response = (HttpResponseMessageWithOriginal)await authRequest.GetRedirectingResponseAsync(CancellationToken.None);
var req = (SignedResponseRequest)response.OriginalMessage;
NameValueCollection query = HttpUtility.ParseQueryString(req.ReturnTo.Query);
Assert.AreEqual("v2", query["p1"]);
}
///
/// Verifies identity-less checkid_* request behavior.
///
[Test]
public async Task NonIdentityRequest() {
var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId);
authRequest.IsExtensionOnly = true;
Assert.IsTrue(authRequest.IsExtensionOnly);
var response = (HttpResponseMessageWithOriginal)await authRequest.GetRedirectingResponseAsync(CancellationToken.None);
var req = (SignedResponseRequest)response.OriginalMessage;
Assert.IsNotInstanceOf(req, "An unexpected SignedResponseRequest derived type was generated.");
}
///
/// Verifies that discovery on identifiers that serve as OP identifiers and claimed identifiers
/// only generate OP Identifier auth requests.
///
[Test]
public async Task DualIdentifierUsedOnlyAsOPIdentifierForAuthRequest() {
var rp = this.CreateRelyingParty(true);
var results = (await AuthenticationRequest.CreateAsync(GetMockDualIdentifier(), rp, this.realm, this.returnTo, false, CancellationToken.None)).ToList();
Assert.AreEqual(1, results.Count);
Assert.IsTrue(results[0].IsDirectedIdentity);
// Also test when dual identiifer support is turned on.
rp.SecuritySettings.AllowDualPurposeIdentifiers = true;
results = (await AuthenticationRequest.CreateAsync(GetMockDualIdentifier(), rp, this.realm, this.returnTo, false, CancellationToken.None)).ToList();
Assert.AreEqual(1, results.Count);
Assert.IsTrue(results[0].IsDirectedIdentity);
}
///
/// Verifies that authentication requests are generated first for OPs that respond
/// to authentication requests.
///
[Test, Ignore("Not yet implemented")]
public void UnresponsiveProvidersComeLast() {
// TODO: code here
Assert.Inconclusive("Not yet implemented.");
}
private AuthenticationRequest CreateAuthenticationRequest(Identifier claimedIdentifier, Identifier providerLocalIdentifier) {
ProviderEndpointDescription providerEndpoint = new ProviderEndpointDescription(OPUri, this.protocol.Version);
IdentifierDiscoveryResult endpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier, providerEndpoint, 10, 5);
OpenIdRelyingParty rp = this.CreateRelyingParty();
return AuthenticationRequest.CreateForTest(endpoint, this.realm, this.returnTo, rp);
}
}
}