Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (10.2 kB)

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