diff options
Diffstat (limited to 'src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs')
-rw-r--r-- | src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs new file mode 100644 index 0000000..d22f858 --- /dev/null +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AuthenticationRequest.cs @@ -0,0 +1,227 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthenticationRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Provider { + using System; + using System.Diagnostics.Contracts; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.Messages; + + /// <summary> + /// Implements the <see cref="IAuthenticationRequest"/> interface + /// so that OpenID Provider sites can easily respond to authentication + /// requests. + /// </summary> + [Serializable] + internal class AuthenticationRequest : HostProcessedRequest, IAuthenticationRequest { + /// <summary> + /// The positive assertion to send, if the host site chooses to send it. + /// </summary> + private readonly PositiveAssertionResponse positiveResponse; + + /// <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) { + Contract.Requires<ArgumentNullException>(provider != null); + + 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 + + /// <summary> + /// Gets or sets the provider endpoint. + /// </summary> + /// <value> + /// The default value is the URL that the request came in on from the relying party. + /// </value> + public override Uri ProviderEndpoint { + get { return this.positiveResponse.ProviderEndpoint; } + set { this.positiveResponse.ProviderEndpoint = value; } + } + + #endregion + + /// <summary> + /// Gets a value indicating whether the response is ready to be created and sent. + /// </summary> + 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 + + /// <summary> + /// Gets a value indicating whether the Provider should help the user + /// select a Claimed Identifier to send back to the relying party. + /// </summary> + public bool IsDirectedIdentity { get; private set; } + + /// <summary> + /// Gets a value indicating whether the requesting Relying Party is using a delegated URL. + /// </summary> + /// <remarks> + /// When delegated identifiers are used, the <see cref="ClaimedIdentifier"/> 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. + /// </remarks> + public bool IsDelegatedIdentifier { get; private set; } + + /// <summary> + /// Gets or sets the Local Identifier to this OpenID Provider of the user attempting + /// to authenticate. Check <see cref="IsDirectedIdentity"/> to see if + /// this value is valid. + /// </summary> + /// <remarks> + /// 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. + /// </remarks> + 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; + } + } + + /// <summary> + /// Gets or sets the identifier that the user agent is claiming at the relying party site. + /// Check <see cref="IsDirectedIdentity"/> to see if this value is valid. + /// </summary> + /// <remarks> + /// <para>This property can only be set if <see cref="IsDelegatedIdentifier"/> is + /// false, to prevent breaking URL delegation.</para> + /// <para>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.</para> + /// <para>The provider may use this identifier for displaying to the user when + /// asking for the user's permission to authenticate to the relying party.</para> + /// </remarks> + /// <exception cref="InvalidOperationException">Thrown from the setter + /// if <see cref="IsDelegatedIdentifier"/> is true.</exception> + 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; + } + } + + /// <summary> + /// Gets or sets a value indicating whether the provider has determined that the + /// <see cref="ClaimedIdentifier"/> belongs to the currently logged in user + /// and wishes to share this information with the consumer. + /// </summary> + public bool? IsAuthenticated { get; set; } + + #endregion + + /// <summary> + /// Gets the original request message. + /// </summary> + protected new CheckIdRequest RequestMessage { + get { return (CheckIdRequest)base.RequestMessage; } + } + + /// <summary> + /// Gets the response message, once <see cref="IsResponseReady"/> is <c>true</c>. + /// </summary> + protected override IProtocolMessage ResponseMessage { + get { + if (this.IsAuthenticated.HasValue) { + return this.IsAuthenticated.Value ? (IProtocolMessage)this.positiveResponse : this.NegativeResponse; + } else { + return null; + } + } + } + + #region IAuthenticationRequest Methods + + /// <summary> + /// Adds an optional fragment (#fragment) portion to the ClaimedIdentifier. + /// Useful for identifier recycling. + /// </summary> + /// <param name="fragment">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.</param> + /// <remarks> + /// <para>Unlike the <see cref="ClaimedIdentifier"/> property, which can only be set if + /// using directed identity, this method can be called on any URI claimed identifier.</para> + /// <para>Because XRI claimed identifiers (the canonical IDs) are never recycled, + /// this method should<i>not</i> be called for XRIs.</para> + /// </remarks> + /// <exception cref="InvalidOperationException"> + /// Thrown when this method is called on an XRI, or on a directed identity + /// request before the <see cref="ClaimedIdentifier"/> property is set. + /// </exception> + public void SetClaimedIdentifierFragment(string fragment) { + UriBuilder builder = new UriBuilder(this.ClaimedIdentifier); + builder.Fragment = fragment; + this.positiveResponse.ClaimedIdentifier = builder.Uri; + } + + /// <summary> + /// Sets the Claimed and Local identifiers even after they have been initially set. + /// </summary> + /// <param name="identifier">The value to set to the <see cref="ClaimedIdentifier"/> and <see cref="LocalIdentifier"/> properties.</param> + internal void ResetClaimedAndLocalIdentifiers(Identifier identifier) { + Contract.Requires<ArgumentNullException>(identifier != null); + + this.positiveResponse.ClaimedIdentifier = identifier; + this.positiveResponse.LocalIdentifier = identifier; + } + + #endregion + } +} |