diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Grid/UserServer.Modules/OpenIdService.cs (renamed from OpenSim/Grid/UserServer/OpenIdService.cs) | 674 |
1 files changed, 337 insertions, 337 deletions
diff --git a/OpenSim/Grid/UserServer/OpenIdService.cs b/OpenSim/Grid/UserServer.Modules/OpenIdService.cs index 187758f..5c8501f 100644 --- a/OpenSim/Grid/UserServer/OpenIdService.cs +++ b/OpenSim/Grid/UserServer.Modules/OpenIdService.cs | |||
@@ -1,337 +1,337 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Collections.Specialized; | 30 | using System.Collections.Specialized; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Net; | 32 | using System.Net; |
33 | using System.Web; | 33 | using System.Web; |
34 | using DotNetOpenId; | 34 | using DotNetOpenId; |
35 | using DotNetOpenId.Provider; | 35 | using DotNetOpenId.Provider; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Servers; | 37 | using OpenSim.Framework.Servers; |
38 | 38 | ||
39 | namespace OpenSim.Grid.UserServer | 39 | namespace OpenSim.Grid.UserServer.Modules |
40 | { | 40 | { |
41 | /// <summary> | 41 | /// <summary> |
42 | /// Temporary, in-memory store for OpenID associations | 42 | /// Temporary, in-memory store for OpenID associations |
43 | /// </summary> | 43 | /// </summary> |
44 | public class ProviderMemoryStore : IAssociationStore<AssociationRelyingPartyType> | 44 | public class ProviderMemoryStore : IAssociationStore<AssociationRelyingPartyType> |
45 | { | 45 | { |
46 | private class AssociationItem | 46 | private class AssociationItem |
47 | { | 47 | { |
48 | public AssociationRelyingPartyType DistinguishingFactor; | 48 | public AssociationRelyingPartyType DistinguishingFactor; |
49 | public string Handle; | 49 | public string Handle; |
50 | public DateTime Expires; | 50 | public DateTime Expires; |
51 | public byte[] PrivateData; | 51 | public byte[] PrivateData; |
52 | } | 52 | } |
53 | 53 | ||
54 | Dictionary<string, AssociationItem> m_store = new Dictionary<string, AssociationItem>(); | 54 | Dictionary<string, AssociationItem> m_store = new Dictionary<string, AssociationItem>(); |
55 | SortedList<DateTime, AssociationItem> m_sortedStore = new SortedList<DateTime, AssociationItem>(); | 55 | SortedList<DateTime, AssociationItem> m_sortedStore = new SortedList<DateTime, AssociationItem>(); |
56 | object m_syncRoot = new object(); | 56 | object m_syncRoot = new object(); |
57 | 57 | ||
58 | #region IAssociationStore<AssociationRelyingPartyType> Members | 58 | #region IAssociationStore<AssociationRelyingPartyType> Members |
59 | 59 | ||
60 | public void StoreAssociation(AssociationRelyingPartyType distinguishingFactor, Association assoc) | 60 | public void StoreAssociation(AssociationRelyingPartyType distinguishingFactor, Association assoc) |
61 | { | 61 | { |
62 | AssociationItem item = new AssociationItem(); | 62 | AssociationItem item = new AssociationItem(); |
63 | item.DistinguishingFactor = distinguishingFactor; | 63 | item.DistinguishingFactor = distinguishingFactor; |
64 | item.Handle = assoc.Handle; | 64 | item.Handle = assoc.Handle; |
65 | item.Expires = assoc.Expires.ToLocalTime(); | 65 | item.Expires = assoc.Expires.ToLocalTime(); |
66 | item.PrivateData = assoc.SerializePrivateData(); | 66 | item.PrivateData = assoc.SerializePrivateData(); |
67 | 67 | ||
68 | lock (m_syncRoot) | 68 | lock (m_syncRoot) |
69 | { | 69 | { |
70 | m_store[item.Handle] = item; | 70 | m_store[item.Handle] = item; |
71 | m_sortedStore[item.Expires] = item; | 71 | m_sortedStore[item.Expires] = item; |
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor) | 75 | public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor) |
76 | { | 76 | { |
77 | lock (m_syncRoot) | 77 | lock (m_syncRoot) |
78 | { | 78 | { |
79 | if (m_sortedStore.Count > 0) | 79 | if (m_sortedStore.Count > 0) |
80 | { | 80 | { |
81 | AssociationItem item = m_sortedStore.Values[m_sortedStore.Count - 1]; | 81 | AssociationItem item = m_sortedStore.Values[m_sortedStore.Count - 1]; |
82 | return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); | 82 | return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); |
83 | } | 83 | } |
84 | else | 84 | else |
85 | { | 85 | { |
86 | return null; | 86 | return null; |
87 | } | 87 | } |
88 | } | 88 | } |
89 | } | 89 | } |
90 | 90 | ||
91 | public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) | 91 | public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) |
92 | { | 92 | { |
93 | AssociationItem item; | 93 | AssociationItem item; |
94 | bool success = false; | 94 | bool success = false; |
95 | lock (m_syncRoot) | 95 | lock (m_syncRoot) |
96 | success = m_store.TryGetValue(handle, out item); | 96 | success = m_store.TryGetValue(handle, out item); |
97 | 97 | ||
98 | if (success) | 98 | if (success) |
99 | return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); | 99 | return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); |
100 | else | 100 | else |
101 | return null; | 101 | return null; |
102 | } | 102 | } |
103 | 103 | ||
104 | public bool RemoveAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) | 104 | public bool RemoveAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) |
105 | { | 105 | { |
106 | lock (m_syncRoot) | 106 | lock (m_syncRoot) |
107 | { | 107 | { |
108 | for (int i = 0; i < m_sortedStore.Values.Count; i++) | 108 | for (int i = 0; i < m_sortedStore.Values.Count; i++) |
109 | { | 109 | { |
110 | AssociationItem item = m_sortedStore.Values[i]; | 110 | AssociationItem item = m_sortedStore.Values[i]; |
111 | if (item.Handle == handle) | 111 | if (item.Handle == handle) |
112 | { | 112 | { |
113 | m_sortedStore.RemoveAt(i); | 113 | m_sortedStore.RemoveAt(i); |
114 | break; | 114 | break; |
115 | } | 115 | } |
116 | } | 116 | } |
117 | 117 | ||
118 | return m_store.Remove(handle); | 118 | return m_store.Remove(handle); |
119 | } | 119 | } |
120 | } | 120 | } |
121 | 121 | ||
122 | public void ClearExpiredAssociations() | 122 | public void ClearExpiredAssociations() |
123 | { | 123 | { |
124 | lock (m_syncRoot) | 124 | lock (m_syncRoot) |
125 | { | 125 | { |
126 | List<AssociationItem> itemsCopy = new List<AssociationItem>(m_sortedStore.Values); | 126 | List<AssociationItem> itemsCopy = new List<AssociationItem>(m_sortedStore.Values); |
127 | DateTime now = DateTime.Now; | 127 | DateTime now = DateTime.Now; |
128 | 128 | ||
129 | for (int i = 0; i < itemsCopy.Count; i++) | 129 | for (int i = 0; i < itemsCopy.Count; i++) |
130 | { | 130 | { |
131 | AssociationItem item = itemsCopy[i]; | 131 | AssociationItem item = itemsCopy[i]; |
132 | 132 | ||
133 | if (item.Expires <= now) | 133 | if (item.Expires <= now) |
134 | { | 134 | { |
135 | m_sortedStore.RemoveAt(i); | 135 | m_sortedStore.RemoveAt(i); |
136 | m_store.Remove(item.Handle); | 136 | m_store.Remove(item.Handle); |
137 | } | 137 | } |
138 | } | 138 | } |
139 | } | 139 | } |
140 | } | 140 | } |
141 | 141 | ||
142 | #endregion | 142 | #endregion |
143 | } | 143 | } |
144 | 144 | ||
145 | public class OpenIdStreamHandler : IStreamHandler | 145 | public class OpenIdStreamHandler : IStreamHandler |
146 | { | 146 | { |
147 | #region HTML | 147 | #region HTML |
148 | 148 | ||
149 | /// <summary>Login form used to authenticate OpenID requests</summary> | 149 | /// <summary>Login form used to authenticate OpenID requests</summary> |
150 | const string LOGIN_PAGE = | 150 | const string LOGIN_PAGE = |
151 | @"<html> | 151 | @"<html> |
152 | <head><title>OpenSim OpenID Login</title></head> | 152 | <head><title>OpenSim OpenID Login</title></head> |
153 | <body> | 153 | <body> |
154 | <h3>OpenSim Login</h3> | 154 | <h3>OpenSim Login</h3> |
155 | <form method=""post""> | 155 | <form method=""post""> |
156 | <label for=""first"">First Name:</label> <input readonly type=""text"" name=""first"" id=""first"" value=""{0}""/> | 156 | <label for=""first"">First Name:</label> <input readonly type=""text"" name=""first"" id=""first"" value=""{0}""/> |
157 | <label for=""last"">Last Name:</label> <input readonly type=""text"" name=""last"" id=""last"" value=""{1}""/> | 157 | <label for=""last"">Last Name:</label> <input readonly type=""text"" name=""last"" id=""last"" value=""{1}""/> |
158 | <label for=""pass"">Password:</label> <input type=""password"" name=""pass"" id=""pass""/> | 158 | <label for=""pass"">Password:</label> <input type=""password"" name=""pass"" id=""pass""/> |
159 | <input type=""submit"" value=""Login""> | 159 | <input type=""submit"" value=""Login""> |
160 | </form> | 160 | </form> |
161 | </body> | 161 | </body> |
162 | </html>"; | 162 | </html>"; |
163 | 163 | ||
164 | /// <summary>Page shown for a valid OpenID identity</summary> | 164 | /// <summary>Page shown for a valid OpenID identity</summary> |
165 | const string OPENID_PAGE = | 165 | const string OPENID_PAGE = |
166 | @"<html> | 166 | @"<html> |
167 | <head> | 167 | <head> |
168 | <title>{2} {3}</title> | 168 | <title>{2} {3}</title> |
169 | <link rel=""openid2.provider openid.server"" href=""{0}://{1}/openid/server/""/> | 169 | <link rel=""openid2.provider openid.server"" href=""{0}://{1}/openid/server/""/> |
170 | </head> | 170 | </head> |
171 | <body>OpenID identifier for {2} {3}</body> | 171 | <body>OpenID identifier for {2} {3}</body> |
172 | </html> | 172 | </html> |
173 | "; | 173 | "; |
174 | 174 | ||
175 | /// <summary>Page shown for an invalid OpenID identity</summary> | 175 | /// <summary>Page shown for an invalid OpenID identity</summary> |
176 | const string INVALID_OPENID_PAGE = | 176 | const string INVALID_OPENID_PAGE = |
177 | @"<html><head><title>Identity not found</title></head> | 177 | @"<html><head><title>Identity not found</title></head> |
178 | <body>Invalid OpenID identity</body></html>"; | 178 | <body>Invalid OpenID identity</body></html>"; |
179 | 179 | ||
180 | /// <summary>Page shown if the OpenID endpoint is requested directly</summary> | 180 | /// <summary>Page shown if the OpenID endpoint is requested directly</summary> |
181 | const string ENDPOINT_PAGE = | 181 | const string ENDPOINT_PAGE = |
182 | @"<html><head><title>OpenID Endpoint</title></head><body> | 182 | @"<html><head><title>OpenID Endpoint</title></head><body> |
183 | This is an OpenID server endpoint, not a human-readable resource. | 183 | This is an OpenID server endpoint, not a human-readable resource. |
184 | For more information, see <a href='http://openid.net/'>http://openid.net/</a>. | 184 | For more information, see <a href='http://openid.net/'>http://openid.net/</a>. |
185 | </body></html>"; | 185 | </body></html>"; |
186 | 186 | ||
187 | #endregion HTML | 187 | #endregion HTML |
188 | 188 | ||
189 | public string ContentType { get { return m_contentType; } } | 189 | public string ContentType { get { return m_contentType; } } |
190 | public string HttpMethod { get { return m_httpMethod; } } | 190 | public string HttpMethod { get { return m_httpMethod; } } |
191 | public string Path { get { return m_path; } } | 191 | public string Path { get { return m_path; } } |
192 | 192 | ||
193 | string m_contentType; | 193 | string m_contentType; |
194 | string m_httpMethod; | 194 | string m_httpMethod; |
195 | string m_path; | 195 | string m_path; |
196 | UserLoginService m_loginService; | 196 | UserLoginService m_loginService; |
197 | ProviderMemoryStore m_openidStore = new ProviderMemoryStore(); | 197 | ProviderMemoryStore m_openidStore = new ProviderMemoryStore(); |
198 | 198 | ||
199 | /// <summary> | 199 | /// <summary> |
200 | /// Constructor | 200 | /// Constructor |
201 | /// </summary> | 201 | /// </summary> |
202 | public OpenIdStreamHandler(string httpMethod, string path, UserLoginService loginService) | 202 | public OpenIdStreamHandler(string httpMethod, string path, UserLoginService loginService) |
203 | { | 203 | { |
204 | m_loginService = loginService; | 204 | m_loginService = loginService; |
205 | m_httpMethod = httpMethod; | 205 | m_httpMethod = httpMethod; |
206 | m_path = path; | 206 | m_path = path; |
207 | 207 | ||
208 | m_contentType = "text/html"; | 208 | m_contentType = "text/html"; |
209 | } | 209 | } |
210 | 210 | ||
211 | /// <summary> | 211 | /// <summary> |
212 | /// Handles all GET and POST requests for OpenID identifier pages and endpoint | 212 | /// Handles all GET and POST requests for OpenID identifier pages and endpoint |
213 | /// server communication | 213 | /// server communication |
214 | /// </summary> | 214 | /// </summary> |
215 | public void Handle(string path, Stream request, Stream response, OSHttpRequest httpRequest, OSHttpResponse httpResponse) | 215 | public void Handle(string path, Stream request, Stream response, OSHttpRequest httpRequest, OSHttpResponse httpResponse) |
216 | { | 216 | { |
217 | Uri providerEndpoint = new Uri(String.Format("{0}://{1}{2}", httpRequest.Url.Scheme, httpRequest.Url.Authority, httpRequest.Url.AbsolutePath)); | 217 | Uri providerEndpoint = new Uri(String.Format("{0}://{1}{2}", httpRequest.Url.Scheme, httpRequest.Url.Authority, httpRequest.Url.AbsolutePath)); |
218 | 218 | ||
219 | // Defult to returning HTML content | 219 | // Defult to returning HTML content |
220 | m_contentType = "text/html"; | 220 | m_contentType = "text/html"; |
221 | 221 | ||
222 | try | 222 | try |
223 | { | 223 | { |
224 | NameValueCollection postQuery = HttpUtility.ParseQueryString(new StreamReader(httpRequest.InputStream).ReadToEnd()); | 224 | NameValueCollection postQuery = HttpUtility.ParseQueryString(new StreamReader(httpRequest.InputStream).ReadToEnd()); |
225 | NameValueCollection getQuery = HttpUtility.ParseQueryString(httpRequest.Url.Query); | 225 | NameValueCollection getQuery = HttpUtility.ParseQueryString(httpRequest.Url.Query); |
226 | NameValueCollection openIdQuery = (postQuery.GetValues("openid.mode") != null ? postQuery : getQuery); | 226 | NameValueCollection openIdQuery = (postQuery.GetValues("openid.mode") != null ? postQuery : getQuery); |
227 | 227 | ||
228 | OpenIdProvider provider = new OpenIdProvider(m_openidStore, providerEndpoint, httpRequest.Url, openIdQuery); | 228 | OpenIdProvider provider = new OpenIdProvider(m_openidStore, providerEndpoint, httpRequest.Url, openIdQuery); |
229 | 229 | ||
230 | if (provider.Request != null) | 230 | if (provider.Request != null) |
231 | { | 231 | { |
232 | if (!provider.Request.IsResponseReady && provider.Request is IAuthenticationRequest) | 232 | if (!provider.Request.IsResponseReady && provider.Request is IAuthenticationRequest) |
233 | { | 233 | { |
234 | IAuthenticationRequest authRequest = (IAuthenticationRequest)provider.Request; | 234 | IAuthenticationRequest authRequest = (IAuthenticationRequest)provider.Request; |
235 | string[] passwordValues = postQuery.GetValues("pass"); | 235 | string[] passwordValues = postQuery.GetValues("pass"); |
236 | 236 | ||
237 | UserProfileData profile; | 237 | UserProfileData profile; |
238 | if (TryGetProfile(new Uri(authRequest.ClaimedIdentifier.ToString()), out profile)) | 238 | if (TryGetProfile(new Uri(authRequest.ClaimedIdentifier.ToString()), out profile)) |
239 | { | 239 | { |
240 | // Check for form POST data | 240 | // Check for form POST data |
241 | if (passwordValues != null && passwordValues.Length == 1) | 241 | if (passwordValues != null && passwordValues.Length == 1) |
242 | { | 242 | { |
243 | if (profile != null && m_loginService.AuthenticateUser(profile, passwordValues[0])) | 243 | if (profile != null && m_loginService.AuthenticateUser(profile, passwordValues[0])) |
244 | authRequest.IsAuthenticated = true; | 244 | authRequest.IsAuthenticated = true; |
245 | else | 245 | else |
246 | authRequest.IsAuthenticated = false; | 246 | authRequest.IsAuthenticated = false; |
247 | } | 247 | } |
248 | else | 248 | else |
249 | { | 249 | { |
250 | // Authentication was requested, send the client a login form | 250 | // Authentication was requested, send the client a login form |
251 | using (StreamWriter writer = new StreamWriter(response)) | 251 | using (StreamWriter writer = new StreamWriter(response)) |
252 | writer.Write(String.Format(LOGIN_PAGE, profile.FirstName, profile.SurName)); | 252 | writer.Write(String.Format(LOGIN_PAGE, profile.FirstName, profile.SurName)); |
253 | return; | 253 | return; |
254 | } | 254 | } |
255 | } | 255 | } |
256 | else | 256 | else |
257 | { | 257 | { |
258 | // Cannot find an avatar matching the claimed identifier | 258 | // Cannot find an avatar matching the claimed identifier |
259 | authRequest.IsAuthenticated = false; | 259 | authRequest.IsAuthenticated = false; |
260 | } | 260 | } |
261 | } | 261 | } |
262 | 262 | ||
263 | // Add OpenID headers to the response | 263 | // Add OpenID headers to the response |
264 | foreach (string key in provider.Request.Response.Headers.Keys) | 264 | foreach (string key in provider.Request.Response.Headers.Keys) |
265 | httpResponse.AddHeader(key, provider.Request.Response.Headers[key]); | 265 | httpResponse.AddHeader(key, provider.Request.Response.Headers[key]); |
266 | 266 | ||
267 | string[] contentTypeValues = provider.Request.Response.Headers.GetValues("Content-Type"); | 267 | string[] contentTypeValues = provider.Request.Response.Headers.GetValues("Content-Type"); |
268 | if (contentTypeValues != null && contentTypeValues.Length == 1) | 268 | if (contentTypeValues != null && contentTypeValues.Length == 1) |
269 | m_contentType = contentTypeValues[0]; | 269 | m_contentType = contentTypeValues[0]; |
270 | 270 | ||
271 | // Set the response code and document body based on the OpenID result | 271 | // Set the response code and document body based on the OpenID result |
272 | httpResponse.StatusCode = (int)provider.Request.Response.Code; | 272 | httpResponse.StatusCode = (int)provider.Request.Response.Code; |
273 | response.Write(provider.Request.Response.Body, 0, provider.Request.Response.Body.Length); | 273 | response.Write(provider.Request.Response.Body, 0, provider.Request.Response.Body.Length); |
274 | response.Close(); | 274 | response.Close(); |
275 | } | 275 | } |
276 | else if (httpRequest.Url.AbsolutePath.Contains("/openid/server")) | 276 | else if (httpRequest.Url.AbsolutePath.Contains("/openid/server")) |
277 | { | 277 | { |
278 | // Standard HTTP GET was made on the OpenID endpoint, send the client the default error page | 278 | // Standard HTTP GET was made on the OpenID endpoint, send the client the default error page |
279 | using (StreamWriter writer = new StreamWriter(response)) | 279 | using (StreamWriter writer = new StreamWriter(response)) |
280 | writer.Write(ENDPOINT_PAGE); | 280 | writer.Write(ENDPOINT_PAGE); |
281 | } | 281 | } |
282 | else | 282 | else |
283 | { | 283 | { |
284 | // Try and lookup this avatar | 284 | // Try and lookup this avatar |
285 | UserProfileData profile; | 285 | UserProfileData profile; |
286 | if (TryGetProfile(httpRequest.Url, out profile)) | 286 | if (TryGetProfile(httpRequest.Url, out profile)) |
287 | { | 287 | { |
288 | using (StreamWriter writer = new StreamWriter(response)) | 288 | using (StreamWriter writer = new StreamWriter(response)) |
289 | { | 289 | { |
290 | // TODO: Print out a full profile page for this avatar | 290 | // TODO: Print out a full profile page for this avatar |
291 | writer.Write(String.Format(OPENID_PAGE, httpRequest.Url.Scheme, | 291 | writer.Write(String.Format(OPENID_PAGE, httpRequest.Url.Scheme, |
292 | httpRequest.Url.Authority, profile.FirstName, profile.SurName)); | 292 | httpRequest.Url.Authority, profile.FirstName, profile.SurName)); |
293 | } | 293 | } |
294 | } | 294 | } |
295 | else | 295 | else |
296 | { | 296 | { |
297 | // Couldn't parse an avatar name, or couldn't find the avatar in the user server | 297 | // Couldn't parse an avatar name, or couldn't find the avatar in the user server |
298 | using (StreamWriter writer = new StreamWriter(response)) | 298 | using (StreamWriter writer = new StreamWriter(response)) |
299 | writer.Write(INVALID_OPENID_PAGE); | 299 | writer.Write(INVALID_OPENID_PAGE); |
300 | } | 300 | } |
301 | } | 301 | } |
302 | } | 302 | } |
303 | catch (Exception ex) | 303 | catch (Exception ex) |
304 | { | 304 | { |
305 | httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError; | 305 | httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError; |
306 | using (StreamWriter writer = new StreamWriter(response)) | 306 | using (StreamWriter writer = new StreamWriter(response)) |
307 | writer.Write(ex.Message); | 307 | writer.Write(ex.Message); |
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | /// <summary> | 311 | /// <summary> |
312 | /// Parse a URL with a relative path of the form /users/First_Last and try to | 312 | /// Parse a URL with a relative path of the form /users/First_Last and try to |
313 | /// retrieve the profile matching that avatar name | 313 | /// retrieve the profile matching that avatar name |
314 | /// </summary> | 314 | /// </summary> |
315 | /// <param name="requestUrl">URL to parse for an avatar name</param> | 315 | /// <param name="requestUrl">URL to parse for an avatar name</param> |
316 | /// <param name="profile">Profile data for the avatar</param> | 316 | /// <param name="profile">Profile data for the avatar</param> |
317 | /// <returns>True if the parse and lookup were successful, otherwise false</returns> | 317 | /// <returns>True if the parse and lookup were successful, otherwise false</returns> |
318 | bool TryGetProfile(Uri requestUrl, out UserProfileData profile) | 318 | bool TryGetProfile(Uri requestUrl, out UserProfileData profile) |
319 | { | 319 | { |
320 | if (requestUrl.Segments.Length == 3 && requestUrl.Segments[1] == "users/") | 320 | if (requestUrl.Segments.Length == 3 && requestUrl.Segments[1] == "users/") |
321 | { | 321 | { |
322 | // Parse the avatar name from the path | 322 | // Parse the avatar name from the path |
323 | string username = requestUrl.Segments[requestUrl.Segments.Length - 1]; | 323 | string username = requestUrl.Segments[requestUrl.Segments.Length - 1]; |
324 | string[] name = username.Split('_'); | 324 | string[] name = username.Split('_'); |
325 | 325 | ||
326 | if (name.Length == 2) | 326 | if (name.Length == 2) |
327 | { | 327 | { |
328 | profile = m_loginService.GetTheUser(name[0], name[1]); | 328 | profile = m_loginService.GetTheUser(name[0], name[1]); |
329 | return (profile != null); | 329 | return (profile != null); |
330 | } | 330 | } |
331 | } | 331 | } |
332 | 332 | ||
333 | profile = null; | 333 | profile = null; |
334 | return false; | 334 | return false; |
335 | } | 335 | } |
336 | } | 336 | } |
337 | } | 337 | } |