//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OpenId.Provider {
using System;
using System.Threading;
using System.Threading.Tasks;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Messages;
using Validation;
///
/// Implements the interface
/// so that OpenID Provider sites can easily respond to authentication
/// requests.
///
[Serializable]
internal class AuthenticationRequest : HostProcessedRequest, IAuthenticationRequest {
///
/// The positive assertion to send, if the host site chooses to send it.
///
private readonly PositiveAssertionResponse positiveResponse;
///
/// Initializes a new instance of the class.
///
/// The provider that received the request.
/// The incoming authentication request message.
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());
}
#region HostProcessedRequest members
///
/// Gets or sets the provider endpoint.
///
///
/// The default value is the URL that the request came in on from the relying party.
///
public override Uri ProviderEndpoint {
get { return this.positiveResponse.ProviderEndpoint; }
set { this.positiveResponse.ProviderEndpoint = value; }
}
#endregion
///
/// Gets a value indicating whether the response is ready to be created and sent.
///
public override bool IsResponseReady {
get {
// The null checks on the identifiers is to make sure that an identifier_select
// has been resolved to actual identifiers.
return this.IsAuthenticated.HasValue &&
(!this.IsAuthenticated.Value || !this.IsDirectedIdentity || (this.LocalIdentifier != null && this.ClaimedIdentifier != null));
}
}
#region IAuthenticationRequest Properties
///
/// Gets a value indicating whether the Provider should help the user
/// select a Claimed Identifier to send back to the relying party.
///
public bool IsDirectedIdentity { get; private set; }
///
/// Gets a value indicating whether the requesting Relying Party is using a delegated URL.
///
///
/// When delegated identifiers are used, the should not
/// be changed at the Provider during authentication.
/// Delegation is only detectable on requests originating from OpenID 2.0 relying parties.
/// A relying party implementing only OpenID 1.x may use delegation and this property will
/// return false anyway.
///
public bool IsDelegatedIdentifier { get; private set; }
///
/// Gets or sets the Local Identifier to this OpenID Provider of the user attempting
/// to authenticate. Check to see if
/// this value is valid.
///
///
/// This may or may not be the same as the Claimed Identifier that the user agent
/// originally supplied to the relying party. The Claimed Identifier
/// endpoint may be delegating authentication to this provider using
/// this provider's local id, which is what this property contains.
/// Use this identifier when looking up this user in the provider's user account
/// list.
///
public Identifier LocalIdentifier {
get {
return this.positiveResponse.LocalIdentifier;
}
set {
// Keep LocalIdentifier and ClaimedIdentifier in sync for directed identity.
if (this.IsDirectedIdentity) {
if (this.ClaimedIdentifier != null && this.ClaimedIdentifier != value) {
throw new InvalidOperationException(OpenIdStrings.IdentifierSelectRequiresMatchingIdentifiers);
}
this.positiveResponse.ClaimedIdentifier = value;
}
this.positiveResponse.LocalIdentifier = value;
}
}
///
/// Gets or sets the identifier that the user agent is claiming at the relying party site.
/// Check to see if this value is valid.
///
///
/// This property can only be set if is
/// false, to prevent breaking URL delegation.
/// This will not be the same as this provider's local identifier for the user
/// if the user has set up his/her own identity page that points to this
/// provider for authentication.
/// The provider may use this identifier for displaying to the user when
/// asking for the user's permission to authenticate to the relying party.
///
/// Thrown from the setter
/// if is true.
public Identifier ClaimedIdentifier {
get {
return this.positiveResponse.ClaimedIdentifier;
}
set {
// Keep LocalIdentifier and ClaimedIdentifier in sync for directed identity.
if (this.IsDirectedIdentity) {
this.positiveResponse.LocalIdentifier = value;
}
this.positiveResponse.ClaimedIdentifier = value;
}
}
///
/// Gets or sets a value indicating whether the provider has determined that the
/// belongs to the currently logged in user
/// and wishes to share this information with the consumer.
///
public bool? IsAuthenticated { get; set; }
#endregion
///
/// Gets the original request message.
///
protected new CheckIdRequest RequestMessage {
get { return (CheckIdRequest)base.RequestMessage; }
}
#region IAuthenticationRequest Methods
///
/// Adds an optional fragment (#fragment) portion to the ClaimedIdentifier.
/// Useful for identifier recycling.
///
/// Should not include the # prefix character as that will be added internally.
/// May be null or the empty string to clear a previously set fragment.
///
/// Unlike the property, which can only be set if
/// using directed identity, this method can be called on any URI claimed identifier.
/// Because XRI claimed identifiers (the canonical IDs) are never recycled,
/// this method shouldnot be called for XRIs.
///
///
/// Thrown when this method is called on an XRI, or on a directed identity
/// request before the property is set.
///
public void SetClaimedIdentifierFragment(string fragment) {
UriBuilder builder = new UriBuilder(this.ClaimedIdentifier);
builder.Fragment = fragment;
this.positiveResponse.ClaimedIdentifier = builder.Uri;
}
#endregion
///
/// Sets the Claimed and Local identifiers even after they have been initially set.
///
/// The value to set to the and properties.
internal void ResetClaimedAndLocalIdentifiers(Identifier identifier) {
Requires.NotNull(identifier, "identifier");
this.positiveResponse.ClaimedIdentifier = identifier;
this.positiveResponse.LocalIdentifier = identifier;
}
///
/// Gets the response message, once is true.
///
/// The cancellation token.
/// The response message.
protected override async Task GetResponseMessageAsync(CancellationToken cancellationToken) {
if (this.IsAuthenticated.HasValue) {
return this.IsAuthenticated.Value ? (IProtocolMessage)this.positiveResponse : await this.GetNegativeResponseAsync();
} else {
return null;
}
}
}
}