Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (10.4 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 5120f3cb Panagiotis Kanavos
using Pithos.Network;
48 5120f3cb Panagiotis Kanavos
using log4net;
49 5120f3cb Panagiotis Kanavos
50 1955901a Panagiotis Kanavos
namespace Pithos.Client.WPF
51 1955901a Panagiotis Kanavos
{
52 1955901a Panagiotis Kanavos
    using System;
53 1955901a Panagiotis Kanavos
    using System.Collections.Generic;
54 1955901a Panagiotis Kanavos
    using System.Linq;
55 1955901a Panagiotis Kanavos
    using System.Text;
56 1955901a Panagiotis Kanavos
    using System.Net;
57 1955901a Panagiotis Kanavos
    using System.Threading.Tasks;
58 1955901a Panagiotis Kanavos
    using System.Diagnostics.Contracts;
59 1955901a Panagiotis Kanavos
    using System.Diagnostics;
60 1955901a Panagiotis Kanavos
    using System.Net.Sockets;
61 1955901a Panagiotis Kanavos
62 1955901a Panagiotis Kanavos
    /// <summary>
63 1955901a Panagiotis Kanavos
    /// TODO: Update summary.
64 1955901a Panagiotis Kanavos
    /// </summary>
65 1955901a Panagiotis Kanavos
    /// <summary>
66 1955901a Panagiotis Kanavos
    /// Retrieves an account name and token from PITHOS
67 1955901a Panagiotis Kanavos
    /// </summary>
68 1955901a Panagiotis Kanavos
    public static class PithosAccount
69 1955901a Panagiotis Kanavos
    {
70 5120f3cb Panagiotis Kanavos
        private static readonly ILog Log = LogManager.GetLogger(typeof(PithosAccount));
71 5120f3cb Panagiotis Kanavos
72 1955901a Panagiotis Kanavos
        /// <summary>
73 1955901a Panagiotis Kanavos
        /// Asynchronously retrieves PITHOS credentials
74 1955901a Panagiotis Kanavos
        /// </summary>
75 20e9a378 Panagiotis Kanavos
        /// <param name="loginUrl">URL to retrieve the account info from PITHOS. Must end with =</param>
76 1955901a Panagiotis Kanavos
        /// <returns>The credentials wrapped in a Task</returns>
77 03ee454f Panagiotis Kanavos
        public static Task<NetworkCredential> RetrieveCredentials(string loginUrl)
78 1955901a Panagiotis Kanavos
        {
79 20e9a378 Panagiotis Kanavos
            Contract.Requires(Uri.IsWellFormedUriString(loginUrl, UriKind.Absolute));
80 1955901a Panagiotis Kanavos
81 20e9a378 Panagiotis Kanavos
            if (!Uri.IsWellFormedUriString(loginUrl, UriKind.Absolute))
82 20e9a378 Panagiotis Kanavos
                throw new ArgumentException("The pithosSite parameter must be a valid absolute URL", "loginUrl");
83 1955901a Panagiotis Kanavos
            
84 1955901a Panagiotis Kanavos
            int port = GetFreePort();
85 28076364 Panagiotis Kanavos
            
86 28076364 Panagiotis Kanavos
            //TODO:Force logout here to take care of existing cookies
87 1955901a Panagiotis Kanavos
88 1955901a Panagiotis Kanavos
89 1955901a Panagiotis Kanavos
            var listenerUrl = String.Format("http://127.0.0.1:{0}/", port);
90 1955901a Panagiotis Kanavos
91 03ee454f Panagiotis Kanavos
            
92 1955901a Panagiotis Kanavos
93 03ee454f Panagiotis Kanavos
            var receiveCredentials = ListenForRedirectAsync(port);
94 03ee454f Panagiotis Kanavos
95 2e3aee00 Panagiotis Kanavos
            var logoutUrl = loginUrl.Replace("login", "im/logout");
96 1e26eceb Panagiotis Kanavos
            var logoutProcess=Process.Start(logoutUrl);            
97 1e26eceb Panagiotis Kanavos
            TaskEx.Delay(2000).Wait();
98 03ee454f Panagiotis Kanavos
            var uriBuilder=new UriBuilder(loginUrl);                       
99 03ee454f Panagiotis Kanavos
            uriBuilder.Query="next=" + listenerUrl;
100 03ee454f Panagiotis Kanavos
101 03ee454f Panagiotis Kanavos
            var retrieveUri = uriBuilder.Uri;
102 03ee454f Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Open Browser at {0}", retrieveUri);
103 03ee454f Panagiotis Kanavos
            Process.Start(retrieveUri.ToString());
104 03ee454f Panagiotis Kanavos
105 03ee454f Panagiotis Kanavos
            return receiveCredentials;
106 03ee454f Panagiotis Kanavos
        }
107 03ee454f Panagiotis Kanavos
108 34bdb91d Panagiotis Kanavos
/*
109 03ee454f Panagiotis Kanavos
        private static async Task<NetworkCredential> ListenHttpForRedirectAsync(string listenerUrl)
110 03ee454f Panagiotis Kanavos
        {
111 03ee454f Panagiotis Kanavos
            using (var listener = new HttpListener())
112 03ee454f Panagiotis Kanavos
            {
113 03ee454f Panagiotis Kanavos
                listener.Prefixes.Add(listenerUrl);
114 03ee454f Panagiotis Kanavos
115 03ee454f Panagiotis Kanavos
                Log.InfoFormat("[RETRIEVE] Listening at {0}", listenerUrl);
116 1955901a Panagiotis Kanavos
117 1955901a Panagiotis Kanavos
118 03ee454f Panagiotis Kanavos
                try
119 1955901a Panagiotis Kanavos
                {
120 03ee454f Panagiotis Kanavos
                    listener.Start();
121 1955901a Panagiotis Kanavos
122 03ee454f Panagiotis Kanavos
                    var context = await listener.GetContextAsync()
123 03ee454f Panagiotis Kanavos
                                            .WithTimeout(TimeSpan.FromMinutes(5));
124 1955901a Panagiotis Kanavos
125 03ee454f Panagiotis Kanavos
                    var request = context.Request;
126 03ee454f Panagiotis Kanavos
                    Log.InfoFormat("[RETRIEVE] Got Connection {0}", request.RawUrl);
127 03ee454f Panagiotis Kanavos
128 03ee454f Panagiotis Kanavos
                    var query = request.QueryString;
129 03ee454f Panagiotis Kanavos
                    var userName = query["user"];
130 03ee454f Panagiotis Kanavos
                    var token = query["token"];
131 03ee454f Panagiotis Kanavos
                    if (String.IsNullOrWhiteSpace(userName) ||
132 03ee454f Panagiotis Kanavos
                        String.IsNullOrWhiteSpace(token))
133 03ee454f Panagiotis Kanavos
                    {
134 03ee454f Panagiotis Kanavos
                        Respond(context, "Failure", "The server did not return a username or token");
135 03ee454f Panagiotis Kanavos
                        Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
136 03ee454f Panagiotis Kanavos
                        throw new Exception("The server did not return a username or token");
137 1955901a Panagiotis Kanavos
                    }
138 03ee454f Panagiotis Kanavos
                    else
139 1955901a Panagiotis Kanavos
                    {
140 03ee454f Panagiotis Kanavos
                        Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
141 03ee454f Panagiotis Kanavos
                        Respond(context, "Authenticated", "Got It");
142 03ee454f Panagiotis Kanavos
143 03ee454f Panagiotis Kanavos
                        return new NetworkCredential(userName, token);
144 1955901a Panagiotis Kanavos
                    }
145 03ee454f Panagiotis Kanavos
                }
146 03ee454f Panagiotis Kanavos
                catch (Exception exc)
147 03ee454f Panagiotis Kanavos
                {
148 03ee454f Panagiotis Kanavos
                    Log.Error("[RETRIEVE][ERROR] Receive connection {0}", exc);
149 03ee454f Panagiotis Kanavos
                    throw;
150 03ee454f Panagiotis Kanavos
                }
151 03ee454f Panagiotis Kanavos
            }
152 03ee454f Panagiotis Kanavos
        }
153 34bdb91d Panagiotis Kanavos
*/
154 1955901a Panagiotis Kanavos
155 03ee454f Panagiotis Kanavos
        private static async Task<NetworkCredential> ListenForRedirectAsync(int port)
156 03ee454f Panagiotis Kanavos
        {
157 03ee454f Panagiotis Kanavos
            var listener = new TcpListener(IPAddress.Any, port);            
158 03ee454f Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Listening at {0}", port);
159 1955901a Panagiotis Kanavos
160 03ee454f Panagiotis Kanavos
            try
161 03ee454f Panagiotis Kanavos
            {
162 03ee454f Panagiotis Kanavos
                listener.Start();
163 1955901a Panagiotis Kanavos
164 03ee454f Panagiotis Kanavos
                using (var client = await listener.AcceptTcpClientAsync()
165 03ee454f Panagiotis Kanavos
                                        .WithTimeout(TimeSpan.FromMinutes(5)))
166 03ee454f Panagiotis Kanavos
                {
167 03ee454f Panagiotis Kanavos
                    using (var stream = client.GetStream())
168 03ee454f Panagiotis Kanavos
                    using (var reader=new StreamReader(stream))
169 03ee454f Panagiotis Kanavos
                    {
170 03ee454f Panagiotis Kanavos
                        var request = await reader.ReadLineAsync();
171 1a3dfbfd Panagiotis Kanavos
                        //BUG
172 1a3dfbfd Panagiotis Kanavos
                        //TODO: Add proper warnings here if the content is empty, don't just throw an exception
173 1a3dfbfd Panagiotis Kanavos
                        //This may be a common occurence 
174 1a3dfbfd Panagiotis Kanavos
175 1a3dfbfd Panagiotis Kanavos
                        if (String.IsNullOrWhiteSpace(request))
176 34bdb91d Panagiotis Kanavos
                            throw new PithosException("The server did send any information");
177 03ee454f Panagiotis Kanavos
                        Log.InfoFormat("[RETRIEVE] Got Connection {0}", request);
178 03ee454f Panagiotis Kanavos
179 03ee454f Panagiotis Kanavos
180 28076364 Panagiotis Kanavos
                        var items = ParseResponse(request);
181 03ee454f Panagiotis Kanavos
182 03ee454f Panagiotis Kanavos
                        var userName = items["user"];
183 03ee454f Panagiotis Kanavos
                        var token = items["token"];
184 03ee454f Panagiotis Kanavos
                        if (String.IsNullOrWhiteSpace(userName) ||
185 03ee454f Panagiotis Kanavos
                            String.IsNullOrWhiteSpace(token))
186 03ee454f Panagiotis Kanavos
                        {
187 03ee454f Panagiotis Kanavos
                            Respond(stream, "Failure", "The server did not return a username or token");
188 03ee454f Panagiotis Kanavos
                            Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
189 34bdb91d Panagiotis Kanavos
                            throw new PithosException("The server did not return a username or token");
190 03ee454f Panagiotis Kanavos
                        }
191 03ee454f Panagiotis Kanavos
                        else
192 03ee454f Panagiotis Kanavos
                        {
193 03ee454f Panagiotis Kanavos
                            Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
194 03ee454f Panagiotis Kanavos
                            Respond(stream, "Authenticated", "Got It");                            
195 03ee454f Panagiotis Kanavos
                        }
196 03ee454f Panagiotis Kanavos
                        return new NetworkCredential(userName, token);
197 03ee454f Panagiotis Kanavos
                    }
198 03ee454f Panagiotis Kanavos
                }
199 03ee454f Panagiotis Kanavos
            }
200 03ee454f Panagiotis Kanavos
            catch (Exception exc)
201 03ee454f Panagiotis Kanavos
            {
202 03ee454f Panagiotis Kanavos
                Log.Error("[RETRIEVE][ERROR] Receive connection {0}", exc);
203 34bdb91d Panagiotis Kanavos
                throw new PithosException("An error occured while retrieving credentials",exc);
204 03ee454f Panagiotis Kanavos
            }
205 1955901a Panagiotis Kanavos
        }
206 1955901a Panagiotis Kanavos
207 28076364 Panagiotis Kanavos
        private static Dictionary<string, string> ParseResponse(string request)
208 28076364 Panagiotis Kanavos
        {
209 28076364 Panagiotis Kanavos
            var parts = request.Split(' ');
210 28076364 Panagiotis Kanavos
            var query = parts[1].TrimStart('/', '?');
211 28076364 Panagiotis Kanavos
212 28076364 Panagiotis Kanavos
            var items = query.Split('&')
213 28076364 Panagiotis Kanavos
                .Select(pair => pair.Split('='))
214 28076364 Panagiotis Kanavos
                .ToDictionary(arr => arr[0].ToLower(), arr => Uri.UnescapeDataString(arr[1]));
215 28076364 Panagiotis Kanavos
            return items;
216 28076364 Panagiotis Kanavos
        }
217 03ee454f Panagiotis Kanavos
218 03ee454f Panagiotis Kanavos
219 437abfca Panagiotis Kanavos
        private static void Respond(HttpListenerContext context,string title,string message)
220 1955901a Panagiotis Kanavos
        {
221 1955901a Panagiotis Kanavos
            var response = context.Response;
222 437abfca Panagiotis Kanavos
            var html = String.Format("<html><head><title>{0}</title></head><body><h1>{1}</h1></body></html>", title, message);
223 437abfca Panagiotis Kanavos
            var outBuffer = Encoding.UTF8.GetBytes(html);
224 1955901a Panagiotis Kanavos
            response.ContentLength64 = outBuffer.Length;
225 1955901a Panagiotis Kanavos
            using (var stream = response.OutputStream)
226 1955901a Panagiotis Kanavos
            {
227 1955901a Panagiotis Kanavos
                stream.Write(outBuffer, 0, outBuffer.Length);
228 1955901a Panagiotis Kanavos
            }
229 1955901a Panagiotis Kanavos
230 5120f3cb Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Responded");
231 1955901a Panagiotis Kanavos
        }
232 03ee454f Panagiotis Kanavos
233 03ee454f Panagiotis Kanavos
        private static void Respond(Stream stream,string title,string message)
234 03ee454f Panagiotis Kanavos
        {
235 03ee454f Panagiotis Kanavos
            
236 03ee454f Panagiotis Kanavos
            var html = String.Format("<html><head><title>{0}</title></head><body><h1>{1}</h1></body></html>", title, message);
237 03ee454f Panagiotis Kanavos
            
238 03ee454f Panagiotis Kanavos
            var response = new StringBuilder();
239 03ee454f Panagiotis Kanavos
            response.AppendLine("HTTP/1.1 200 OK");
240 03ee454f Panagiotis Kanavos
            response.AppendFormat("Content-Length: {0}\n", html.Length);
241 03ee454f Panagiotis Kanavos
            response.AppendLine("Server: Microsoft-HTTPAPI/2.0");
242 03ee454f Panagiotis Kanavos
            response.AppendFormat("Date: {0}\n\n", DateTime.UtcNow);
243 03ee454f Panagiotis Kanavos
            response.AppendLine(html);
244 03ee454f Panagiotis Kanavos
245 03ee454f Panagiotis Kanavos
            var outBuffer=Encoding.UTF8.GetBytes(response.ToString());
246 03ee454f Panagiotis Kanavos
            
247 03ee454f Panagiotis Kanavos
            stream.Write(outBuffer, 0, outBuffer.Length);
248 03ee454f Panagiotis Kanavos
249 03ee454f Panagiotis Kanavos
            Log.InfoFormat("[RETRIEVE] Responded");
250 03ee454f Panagiotis Kanavos
        }
251 03ee454f Panagiotis Kanavos
252 03ee454f Panagiotis Kanavos
       
253 1955901a Panagiotis Kanavos
        /// <summary>
254 1955901a Panagiotis Kanavos
        /// Locates a free local port 
255 1955901a Panagiotis Kanavos
        /// </summary>
256 1955901a Panagiotis Kanavos
        /// <returns>A free port</returns>
257 1955901a Panagiotis Kanavos
        /// <remarks>The method starts and stops a TcpListener on port 0 to locate a free port.</remarks>
258 1955901a Panagiotis Kanavos
        public static int GetFreePort()
259 1955901a Panagiotis Kanavos
        {
260 1955901a Panagiotis Kanavos
            //The TcpListener will locate a free port             
261 1955901a Panagiotis Kanavos
            var listener = new TcpListener(IPAddress.Any, 0);
262 1955901a Panagiotis Kanavos
            listener.Start();
263 1955901a Panagiotis Kanavos
            var port = ((IPEndPoint)listener.LocalEndpoint).Port;
264 1955901a Panagiotis Kanavos
            listener.Stop();
265 1955901a Panagiotis Kanavos
            return port;
266 1955901a Panagiotis Kanavos
        }
267 1955901a Panagiotis Kanavos
    }
268 1955901a Panagiotis Kanavos
}