Removed old .refresh file.
[dotnetoauth.git] / src / DotNetOpenAuth / OpenId / Provider / OpenIdProvider.cs
blobf7eb3adfe10125b0551fbfbef90cb8e43273d440
1 //-----------------------------------------------------------------------
2 // <copyright file="OpenIdProvider.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth.OpenId.Provider {
8 using System;
9 using System.ComponentModel;
10 using System.Linq;
11 using System.Web;
12 using DotNetOpenAuth.Configuration;
13 using DotNetOpenAuth.Messaging;
14 using DotNetOpenAuth.Messaging.Bindings;
15 using DotNetOpenAuth.OpenId.ChannelElements;
16 using DotNetOpenAuth.OpenId.Messages;
18 /// <summary>
19 /// Offers services for a web page that is acting as an OpenID identity server.
20 /// </summary>
21 public sealed class OpenIdProvider {
22 /// <summary>
23 /// The name of the key to use in the HttpApplication cache to store the
24 /// instance of <see cref="StandardProviderApplicationStore"/> to use.
25 /// </summary>
26 private const string ApplicationStoreKey = "DotNetOpenAuth.OpenId.Provider.OpenIdProvider.ApplicationStore";
28 /// <summary>
29 /// Backing field for the <see cref="SecuritySettings"/> property.
30 /// </summary>
31 private ProviderSecuritySettings securitySettings;
33 /// <summary>
34 /// Initializes a new instance of the <see cref="OpenIdProvider"/> class.
35 /// </summary>
36 public OpenIdProvider()
37 : this(DotNetOpenAuthSection.Configuration.OpenId.Provider.ApplicationStore.CreateInstance(HttpApplicationStore)) {
40 /// <summary>
41 /// Initializes a new instance of the <see cref="OpenIdProvider"/> class.
42 /// </summary>
43 /// <param name="applicationStore">The application store to use. Cannot be null.</param>
44 public OpenIdProvider(IProviderApplicationStore applicationStore)
45 : this(applicationStore, applicationStore) {
48 /// <summary>
49 /// Initializes a new instance of the <see cref="OpenIdProvider"/> class.
50 /// </summary>
51 /// <param name="associationStore">The association store to use. Cannot be null.</param>
52 /// <param name="nonceStore">The nonce store to use. Cannot be null.</param>
53 private OpenIdProvider(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore) {
54 ErrorUtilities.VerifyArgumentNotNull(associationStore, "associationStore");
55 ErrorUtilities.VerifyArgumentNotNull(nonceStore, "nonceStore");
57 this.AssociationStore = associationStore;
58 this.SecuritySettings = DotNetOpenAuthSection.Configuration.OpenId.Provider.SecuritySettings.CreateSecuritySettings();
59 this.Channel = new OpenIdChannel(this.AssociationStore, nonceStore, this.SecuritySettings);
62 /// <summary>
63 /// Gets the standard state storage mechanism that uses ASP.NET's
64 /// HttpApplication state dictionary to store associations and nonces.
65 /// </summary>
66 [EditorBrowsable(EditorBrowsableState.Advanced)]
67 public static IProviderApplicationStore HttpApplicationStore {
68 get {
69 HttpContext context = HttpContext.Current;
70 ErrorUtilities.VerifyOperation(context != null, OpenIdStrings.StoreRequiredWhenNoHttpContextAvailable, typeof(IProviderApplicationStore).Name);
71 var store = (IProviderApplicationStore)context.Application[ApplicationStoreKey];
72 if (store == null) {
73 context.Application.Lock();
74 try {
75 if ((store = (IProviderApplicationStore)context.Application[ApplicationStoreKey]) == null) {
76 context.Application[ApplicationStoreKey] = store = new StandardProviderApplicationStore();
78 } finally {
79 context.Application.UnLock();
83 return store;
87 /// <summary>
88 /// Gets the channel to use for sending/receiving messages.
89 /// </summary>
90 public Channel Channel { get; internal set; }
92 /// <summary>
93 /// Gets the security settings used by this Provider.
94 /// </summary>
95 public ProviderSecuritySettings SecuritySettings {
96 get {
97 return this.securitySettings;
100 internal set {
101 ErrorUtilities.VerifyArgumentNotNull(value, "value");
102 this.securitySettings = value;
106 /// <summary>
107 /// Gets the association store.
108 /// </summary>
109 internal IAssociationStore<AssociationRelyingPartyType> AssociationStore { get; private set; }
111 /// <summary>
112 /// Gets the web request handler to use for discovery and the part of
113 /// authentication where direct messages are sent to an untrusted remote party.
114 /// </summary>
115 internal IDirectWebRequestHandler WebRequestHandler {
116 get { return this.Channel.WebRequestHandler; }
119 /// <summary>
120 /// Gets the incoming OpenID request if there is one, or null if none was detected.
121 /// </summary>
122 /// <returns>The request that the hosting Provider should possibly process and then transmit the response for.</returns>
123 /// <remarks>
124 /// <para>Requests may be infrastructural to OpenID and allow auto-responses, or they may
125 /// be authentication requests where the Provider site has to make decisions based
126 /// on its own user database and policies.</para>
127 /// <para>Requires an <see cref="HttpContext.Current">HttpContext.Current</see> context.</para>
128 /// </remarks>
129 /// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current">HttpContext.Current</see> == <c>null</c>.</exception>
130 /// <exception cref="ProtocolException">Thrown if the incoming message is recognized but deviates from the protocol specification irrecoverably.</exception>
131 public IRequest GetRequest() {
132 return this.GetRequest(this.Channel.GetRequestFromContext());
135 /// <summary>
136 /// Gets the incoming OpenID request if there is one, or null if none was detected.
137 /// </summary>
138 /// <param name="httpRequestInfo">The incoming HTTP request to extract the message from.</param>
139 /// <returns>
140 /// The request that the hosting Provider should process and then transmit the response for.
141 /// Null if no valid OpenID request was detected in the given HTTP request.
142 /// </returns>
143 /// <remarks>
144 /// Requests may be infrastructural to OpenID and allow auto-responses, or they may
145 /// be authentication requests where the Provider site has to make decisions based
146 /// on its own user database and policies.
147 /// </remarks>
148 /// <exception cref="ProtocolException">Thrown if the incoming message is recognized but deviates from the protocol specification irrecoverably.</exception>
149 public IRequest GetRequest(HttpRequestInfo httpRequestInfo) {
150 ErrorUtilities.VerifyArgumentNotNull(httpRequestInfo, "httpRequestInfo");
152 IDirectedProtocolMessage incomingMessage = this.Channel.ReadFromRequest(httpRequestInfo);
153 if (incomingMessage == null) {
154 return null;
157 var checkIdMessage = incomingMessage as CheckIdRequest;
158 if (checkIdMessage != null) {
159 return new AuthenticationRequest(this, checkIdMessage);
162 var checkAuthMessage = incomingMessage as CheckAuthenticationRequest;
163 if (checkAuthMessage != null) {
164 return new AutoResponsiveRequest(this, incomingMessage, new CheckAuthenticationResponse(checkAuthMessage, this));
167 var associateMessage = incomingMessage as AssociateRequest;
168 if (associateMessage != null) {
169 return new AutoResponsiveRequest(this, incomingMessage, associateMessage.CreateResponse(this.AssociationStore, this.SecuritySettings));
172 throw ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessageReceivedOfMany);
175 /// <summary>
176 /// Send an identity assertion on behalf of one of this Provider's
177 /// members in order to redirect the user agent to a relying party
178 /// web site and log him/her in immediately in one uninterrupted step.
179 /// </summary>
180 /// <param name="providerEndpoint">The absolute URL on the Provider site that receives OpenID messages.</param>
181 /// <param name="relyingParty">The URL of the Relying Party web site.
182 /// This will typically be the home page, but may be a longer URL if
183 /// that Relying Party considers the scope of its realm to be more specific.
184 /// The URL provided here must allow discovery of the Relying Party's
185 /// XRDS document that advertises its OpenID RP endpoint.</param>
186 /// <param name="claimedIdentifier">The Identifier you are asserting your member controls.</param>
187 /// <param name="localIdentifier">The Identifier you know your user by internally. This will typically
188 /// be the same as <paramref name="claimedIdentifier"/>.</param>
189 /// <param name="extensions">The extensions.</param>
190 /// <returns>
191 /// A <see cref="UserAgentResponse"/> object describing the HTTP response to send
192 /// the user agent to allow the redirect with assertion to happen.
193 /// </returns>
194 public UserAgentResponse PrepareUnsolicitedAssertion(Uri providerEndpoint, Realm relyingParty, Identifier claimedIdentifier, Identifier localIdentifier, params IExtensionMessage[] extensions) {
195 ErrorUtilities.VerifyArgumentNotNull(providerEndpoint, "providerEndpoint");
196 ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");
197 ErrorUtilities.VerifyArgumentNotNull(claimedIdentifier, "claimedIdentifier");
198 ErrorUtilities.VerifyArgumentNotNull(localIdentifier, "localIdentifier");
199 ErrorUtilities.VerifyArgumentNamed(providerEndpoint.IsAbsoluteUri, "providerEndpoint", OpenIdStrings.AbsoluteUriRequired);
201 // Although the RP should do their due diligence to make sure that this OP
202 // is authorized to send an assertion for the given claimed identifier,
203 // do due diligence by performing our own discovery on the claimed identifier
204 // and make sure that it is tied to this OP and OP local identifier.
205 //// TODO: code here
207 Logger.InfoFormat("Preparing unsolicited assertion for {0}", claimedIdentifier);
208 var returnToEndpoint = relyingParty.Discover(this.WebRequestHandler, true).FirstOrDefault();
209 ErrorUtilities.VerifyProtocol(returnToEndpoint != null, OpenIdStrings.NoRelyingPartyEndpointDiscovered, relyingParty);
211 var positiveAssertion = new PositiveAssertionResponse(returnToEndpoint) {
212 ProviderEndpoint = providerEndpoint,
213 ClaimedIdentifier = claimedIdentifier,
214 LocalIdentifier = localIdentifier,
217 if (extensions != null) {
218 foreach (IExtensionMessage extension in extensions) {
219 positiveAssertion.Extensions.Add(extension);
223 return this.Channel.PrepareResponse(positiveAssertion);