Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / PithosAccount.cs @ fe62b7f4

History | View | Annotate | Download (10.5 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="PithosAccount.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 f3d080df Panagiotis Kanavos
43 1955901a Panagiotis Kanavos
// </copyright>
44 1955901a Panagiotis Kanavos
// -----------------------------------------------------------------------
45 1955901a Panagiotis Kanavos
46 03ee454f Panagiotis Kanavos
using System.IO;
47 db8a9589 Panagiotis Kanavos
using System.Reflection;
48 5120f3cb Panagiotis Kanavos
using Pithos.Network;
49 5120f3cb Panagiotis Kanavos
using log4net;
50 5120f3cb Panagiotis Kanavos
51 1955901a Panagiotis Kanavos
namespace Pithos.Client.WPF
52 1955901a Panagiotis Kanavos
{
53 1955901a Panagiotis Kanavos
    using System;
54 1955901a Panagiotis Kanavos
    using System.Collections.Generic;
55 1955901a Panagiotis Kanavos
    using System.Linq;
56 1955901a Panagiotis Kanavos
    using System.Text;
57 1955901a Panagiotis Kanavos
    using System.Net;
58 1955901a Panagiotis Kanavos
    using System.Threading.Tasks;
59 1955901a Panagiotis Kanavos
    using System.Diagnostics.Contracts;
60 1955901a Panagiotis Kanavos
    using System.Diagnostics;
61 1955901a Panagiotis Kanavos
    using System.Net.Sockets;
62 1955901a Panagiotis Kanavos
63 1955901a Panagiotis Kanavos
    /// <summary>
64 1955901a Panagiotis Kanavos
    /// TODO: Update summary.
65 1955901a Panagiotis Kanavos
    /// </summary>
66 1955901a Panagiotis Kanavos
    /// <summary>
67 1955901a Panagiotis Kanavos
    /// Retrieves an account name and token from PITHOS
68 1955901a Panagiotis Kanavos
    /// </summary>
69 1955901a Panagiotis Kanavos
    public static class PithosAccount
70 1955901a Panagiotis Kanavos
    {
71 db8a9589 Panagiotis Kanavos
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72 5120f3cb Panagiotis Kanavos
73 1955901a Panagiotis Kanavos
        /// <summary>
74 1955901a Panagiotis Kanavos
        /// Asynchronously retrieves PITHOS credentials
75 1955901a Panagiotis Kanavos
        /// </summary>
76 20e9a378 Panagiotis Kanavos
        /// <param name="loginUrl">URL to retrieve the account info from PITHOS. Must end with =</param>
77 1955901a Panagiotis Kanavos
        /// <returns>The credentials wrapped in a Task</returns>
78 03ee454f Panagiotis Kanavos
        public static Task<NetworkCredential> RetrieveCredentials(string loginUrl)
79 1955901a Panagiotis Kanavos
        {
80 20e9a378 Panagiotis Kanavos
            Contract.Requires(Uri.IsWellFormedUriString(loginUrl, UriKind.Absolute));
81 1955901a Panagiotis Kanavos
82 20e9a378 Panagiotis Kanavos
            if (!Uri.IsWellFormedUriString(loginUrl, UriKind.Absolute))
83 20e9a378 Panagiotis Kanavos
                throw new ArgumentException("The pithosSite parameter must be a valid absolute URL", "loginUrl");
84 1955901a Panagiotis Kanavos
            
85 1955901a Panagiotis Kanavos
            int port = GetFreePort();
86 28076364 Panagiotis Kanavos
            
87 28076364 Panagiotis Kanavos
            //TODO:Force logout here to take care of existing cookies
88 1955901a Panagiotis Kanavos
89 1955901a Panagiotis Kanavos
90 fe62b7f4 Panagiotis Kanavos
            var listenerUrl = String.Format("http://127.0.0.1:{0}", port);
91 1955901a Panagiotis Kanavos
92 03ee454f Panagiotis Kanavos
            
93 1955901a Panagiotis Kanavos
94 03ee454f Panagiotis Kanavos
            var receiveCredentials = ListenForRedirectAsync(port);
95 03ee454f Panagiotis Kanavos
96 2e3aee00 Panagiotis Kanavos
            var logoutUrl = loginUrl.Replace("login", "im/logout");
97 1e26eceb Panagiotis Kanavos
            var logoutProcess=Process.Start(logoutUrl);            
98 1e26eceb Panagiotis Kanavos
            TaskEx.Delay(2000).Wait();
99 03ee454f Panagiotis Kanavos
            var uriBuilder=new UriBuilder(loginUrl);                       
100 fe62b7f4 Panagiotis Kanavos
            uriBuilder.Query=String.Format("next={0}&force=", listenerUrl);
101 03ee454f Panagiotis Kanavos
102 03ee454f Panagiotis Kanavos
            var retrieveUri = uriBuilder.Uri;
103 03ee454f Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Open Browser at {0}", retrieveUri);
104 03ee454f Panagiotis Kanavos
            Process.Start(retrieveUri.ToString());
105 03ee454f Panagiotis Kanavos
106 03ee454f Panagiotis Kanavos
            return receiveCredentials;
107 03ee454f Panagiotis Kanavos
        }
108 03ee454f Panagiotis Kanavos
109 34bdb91d Panagiotis Kanavos
/*
110 03ee454f Panagiotis Kanavos
        private static async Task<NetworkCredential> ListenHttpForRedirectAsync(string listenerUrl)
111 03ee454f Panagiotis Kanavos
        {
112 03ee454f Panagiotis Kanavos
            using (var listener = new HttpListener())
113 03ee454f Panagiotis Kanavos
            {
114 03ee454f Panagiotis Kanavos
                listener.Prefixes.Add(listenerUrl);
115 03ee454f Panagiotis Kanavos
116 03ee454f Panagiotis Kanavos
                Log.InfoFormat("[RETRIEVE] Listening at {0}", listenerUrl);
117 1955901a Panagiotis Kanavos
118 1955901a Panagiotis Kanavos
119 03ee454f Panagiotis Kanavos
                try
120 1955901a Panagiotis Kanavos
                {
121 03ee454f Panagiotis Kanavos
                    listener.Start();
122 1955901a Panagiotis Kanavos
123 03ee454f Panagiotis Kanavos
                    var context = await listener.GetContextAsync()
124 03ee454f Panagiotis Kanavos
                                            .WithTimeout(TimeSpan.FromMinutes(5));
125 1955901a Panagiotis Kanavos
126 03ee454f Panagiotis Kanavos
                    var request = context.Request;
127 03ee454f Panagiotis Kanavos
                    Log.InfoFormat("[RETRIEVE] Got Connection {0}", request.RawUrl);
128 03ee454f Panagiotis Kanavos
129 03ee454f Panagiotis Kanavos
                    var query = request.QueryString;
130 03ee454f Panagiotis Kanavos
                    var userName = query["user"];
131 03ee454f Panagiotis Kanavos
                    var token = query["token"];
132 03ee454f Panagiotis Kanavos
                    if (String.IsNullOrWhiteSpace(userName) ||
133 03ee454f Panagiotis Kanavos
                        String.IsNullOrWhiteSpace(token))
134 03ee454f Panagiotis Kanavos
                    {
135 03ee454f Panagiotis Kanavos
                        Respond(context, "Failure", "The server did not return a username or token");
136 03ee454f Panagiotis Kanavos
                        Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
137 03ee454f Panagiotis Kanavos
                        throw new Exception("The server did not return a username or token");
138 1955901a Panagiotis Kanavos
                    }
139 03ee454f Panagiotis Kanavos
                    else
140 1955901a Panagiotis Kanavos
                    {
141 03ee454f Panagiotis Kanavos
                        Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
142 03ee454f Panagiotis Kanavos
                        Respond(context, "Authenticated", "Got It");
143 03ee454f Panagiotis Kanavos
144 03ee454f Panagiotis Kanavos
                        return new NetworkCredential(userName, token);
145 1955901a Panagiotis Kanavos
                    }
146 03ee454f Panagiotis Kanavos
                }
147 03ee454f Panagiotis Kanavos
                catch (Exception exc)
148 03ee454f Panagiotis Kanavos
                {
149 03ee454f Panagiotis Kanavos
                    Log.Error("[RETRIEVE][ERROR] Receive connection {0}", exc);
150 03ee454f Panagiotis Kanavos
                    throw;
151 03ee454f Panagiotis Kanavos
                }
152 03ee454f Panagiotis Kanavos
            }
153 03ee454f Panagiotis Kanavos
        }
154 34bdb91d Panagiotis Kanavos
*/
155 1955901a Panagiotis Kanavos
156 03ee454f Panagiotis Kanavos
        private static async Task<NetworkCredential> ListenForRedirectAsync(int port)
157 03ee454f Panagiotis Kanavos
        {
158 03ee454f Panagiotis Kanavos
            var listener = new TcpListener(IPAddress.Any, port);            
159 03ee454f Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Listening at {0}", port);
160 1955901a Panagiotis Kanavos
161 03ee454f Panagiotis Kanavos
            try
162 03ee454f Panagiotis Kanavos
            {
163 03ee454f Panagiotis Kanavos
                listener.Start();
164 1955901a Panagiotis Kanavos
165 03ee454f Panagiotis Kanavos
                using (var client = await listener.AcceptTcpClientAsync()
166 03ee454f Panagiotis Kanavos
                                        .WithTimeout(TimeSpan.FromMinutes(5)))
167 03ee454f Panagiotis Kanavos
                {
168 03ee454f Panagiotis Kanavos
                    using (var stream = client.GetStream())
169 03ee454f Panagiotis Kanavos
                    using (var reader=new StreamReader(stream))
170 03ee454f Panagiotis Kanavos
                    {
171 03ee454f Panagiotis Kanavos
                        var request = await reader.ReadLineAsync();
172 1a3dfbfd Panagiotis Kanavos
                        //BUG
173 1a3dfbfd Panagiotis Kanavos
                        //TODO: Add proper warnings here if the content is empty, don't just throw an exception
174 1a3dfbfd Panagiotis Kanavos
                        //This may be a common occurence 
175 1a3dfbfd Panagiotis Kanavos
176 1a3dfbfd Panagiotis Kanavos
                        if (String.IsNullOrWhiteSpace(request))
177 34bdb91d Panagiotis Kanavos
                            throw new PithosException("The server did send any information");
178 03ee454f Panagiotis Kanavos
                        Log.InfoFormat("[RETRIEVE] Got Connection {0}", request);
179 03ee454f Panagiotis Kanavos
180 03ee454f Panagiotis Kanavos
181 28076364 Panagiotis Kanavos
                        var items = ParseResponse(request);
182 03ee454f Panagiotis Kanavos
183 03ee454f Panagiotis Kanavos
                        var userName = items["user"];
184 03ee454f Panagiotis Kanavos
                        var token = items["token"];
185 03ee454f Panagiotis Kanavos
                        if (String.IsNullOrWhiteSpace(userName) ||
186 03ee454f Panagiotis Kanavos
                            String.IsNullOrWhiteSpace(token))
187 03ee454f Panagiotis Kanavos
                        {
188 03ee454f Panagiotis Kanavos
                            Respond(stream, "Failure", "The server did not return a username or token");
189 03ee454f Panagiotis Kanavos
                            Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
190 34bdb91d Panagiotis Kanavos
                            throw new PithosException("The server did not return a username or token");
191 03ee454f Panagiotis Kanavos
                        }
192 03ee454f Panagiotis Kanavos
                        else
193 03ee454f Panagiotis Kanavos
                        {
194 03ee454f Panagiotis Kanavos
                            Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
195 03ee454f Panagiotis Kanavos
                            Respond(stream, "Authenticated", "Got It");                            
196 03ee454f Panagiotis Kanavos
                        }
197 03ee454f Panagiotis Kanavos
                        return new NetworkCredential(userName, token);
198 03ee454f Panagiotis Kanavos
                    }
199 03ee454f Panagiotis Kanavos
                }
200 03ee454f Panagiotis Kanavos
            }
201 03ee454f Panagiotis Kanavos
            catch (Exception exc)
202 03ee454f Panagiotis Kanavos
            {
203 03ee454f Panagiotis Kanavos
                Log.Error("[RETRIEVE][ERROR] Receive connection {0}", exc);
204 34bdb91d Panagiotis Kanavos
                throw new PithosException("An error occured while retrieving credentials",exc);
205 03ee454f Panagiotis Kanavos
            }
206 1955901a Panagiotis Kanavos
        }
207 1955901a Panagiotis Kanavos
208 28076364 Panagiotis Kanavos
        private static Dictionary<string, string> ParseResponse(string request)
209 28076364 Panagiotis Kanavos
        {
210 28076364 Panagiotis Kanavos
            var parts = request.Split(' ');
211 28076364 Panagiotis Kanavos
            var query = parts[1].TrimStart('/', '?');
212 28076364 Panagiotis Kanavos
213 28076364 Panagiotis Kanavos
            var items = query.Split('&')
214 28076364 Panagiotis Kanavos
                .Select(pair => pair.Split('='))
215 28076364 Panagiotis Kanavos
                .ToDictionary(arr => arr[0].ToLower(), arr => Uri.UnescapeDataString(arr[1]));
216 28076364 Panagiotis Kanavos
            return items;
217 28076364 Panagiotis Kanavos
        }
218 03ee454f Panagiotis Kanavos
219 03ee454f Panagiotis Kanavos
220 437abfca Panagiotis Kanavos
        private static void Respond(HttpListenerContext context,string title,string message)
221 1955901a Panagiotis Kanavos
        {
222 1955901a Panagiotis Kanavos
            var response = context.Response;
223 437abfca Panagiotis Kanavos
            var html = String.Format("<html><head><title>{0}</title></head><body><h1>{1}</h1></body></html>", title, message);
224 437abfca Panagiotis Kanavos
            var outBuffer = Encoding.UTF8.GetBytes(html);
225 1955901a Panagiotis Kanavos
            response.ContentLength64 = outBuffer.Length;
226 1955901a Panagiotis Kanavos
            using (var stream = response.OutputStream)
227 1955901a Panagiotis Kanavos
            {
228 1955901a Panagiotis Kanavos
                stream.Write(outBuffer, 0, outBuffer.Length);
229 1955901a Panagiotis Kanavos
            }
230 1955901a Panagiotis Kanavos
231 5120f3cb Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Responded");
232 1955901a Panagiotis Kanavos
        }
233 03ee454f Panagiotis Kanavos
234 03ee454f Panagiotis Kanavos
        private static void Respond(Stream stream,string title,string message)
235 03ee454f Panagiotis Kanavos
        {
236 03ee454f Panagiotis Kanavos
            
237 03ee454f Panagiotis Kanavos
            var html = String.Format("<html><head><title>{0}</title></head><body><h1>{1}</h1></body></html>", title, message);
238 03ee454f Panagiotis Kanavos
            
239 03ee454f Panagiotis Kanavos
            var response = new StringBuilder();
240 03ee454f Panagiotis Kanavos
            response.AppendLine("HTTP/1.1 200 OK");
241 03ee454f Panagiotis Kanavos
            response.AppendFormat("Content-Length: {0}\n", html.Length);
242 03ee454f Panagiotis Kanavos
            response.AppendLine("Server: Microsoft-HTTPAPI/2.0");
243 03ee454f Panagiotis Kanavos
            response.AppendFormat("Date: {0}\n\n", DateTime.UtcNow);
244 03ee454f Panagiotis Kanavos
            response.AppendLine(html);
245 03ee454f Panagiotis Kanavos
246 03ee454f Panagiotis Kanavos
            var outBuffer=Encoding.UTF8.GetBytes(response.ToString());
247 03ee454f Panagiotis Kanavos
            
248 03ee454f Panagiotis Kanavos
            stream.Write(outBuffer, 0, outBuffer.Length);
249 03ee454f Panagiotis Kanavos
250 03ee454f Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Responded");
251 03ee454f Panagiotis Kanavos
        }
252 03ee454f Panagiotis Kanavos
253 03ee454f Panagiotis Kanavos
       
254 1955901a Panagiotis Kanavos
        /// <summary>
255 1955901a Panagiotis Kanavos
        /// Locates a free local port 
256 1955901a Panagiotis Kanavos
        /// </summary>
257 1955901a Panagiotis Kanavos
        /// <returns>A free port</returns>
258 1955901a Panagiotis Kanavos
        /// <remarks>The method starts and stops a TcpListener on port 0 to locate a free port.</remarks>
259 1955901a Panagiotis Kanavos
        public static int GetFreePort()
260 1955901a Panagiotis Kanavos
        {
261 1955901a Panagiotis Kanavos
            //The TcpListener will locate a free port             
262 1955901a Panagiotis Kanavos
            var listener = new TcpListener(IPAddress.Any, 0);
263 1955901a Panagiotis Kanavos
            listener.Start();
264 1955901a Panagiotis Kanavos
            var port = ((IPEndPoint)listener.LocalEndpoint).Port;
265 1955901a Panagiotis Kanavos
            listener.Stop();
266 1955901a Panagiotis Kanavos
            return port;
267 1955901a Panagiotis Kanavos
        }
268 1955901a Panagiotis Kanavos
    }
269 1955901a Panagiotis Kanavos
}