//----------------------------------------------------------------------- // // 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; } } } }