Revision 03ee454f

b/trunk/Pithos.Client.WPF/PithosAccount.cs
4 4
// </copyright>
5 5
// -----------------------------------------------------------------------
6 6

  
7
using System.IO;
7 8
using Pithos.Network;
8 9
using log4net;
9 10

  
......
34 35
        /// </summary>
35 36
        /// <param name="loginUrl">URL to retrieve the account info from PITHOS. Must end with =</param>
36 37
        /// <returns>The credentials wrapped in a Task</returns>
37
        public static Task<NetworkCredential> RetrieveCredentialsAsync(string loginUrl)
38
        public static Task<NetworkCredential> RetrieveCredentials(string loginUrl)
38 39
        {
39 40
            Contract.Requires(Uri.IsWellFormedUriString(loginUrl, UriKind.Absolute));
40 41

  
......
46 47

  
47 48
            var listenerUrl = String.Format("http://127.0.0.1:{0}/", port);
48 49

  
49
            HttpListener listener = new HttpListener();
50
            listener.Prefixes.Add(listenerUrl);
50
            
51 51

  
52
            Log.InfoFormat("[RETRIEVE] Listening at {0}", listenerUrl);
52
            var receiveCredentials = ListenForRedirectAsync(port);
53

  
54
            var uriBuilder=new UriBuilder(loginUrl);                       
55
            uriBuilder.Query="next=" + listenerUrl;
56

  
57
            var retrieveUri = uriBuilder.Uri;
58
            Log.InfoFormat("[RETRIEVE] Open Browser at {0}", retrieveUri);
59
            Process.Start(retrieveUri.ToString());
60

  
61
            return receiveCredentials;
62
        }
63

  
64
        private static async Task<NetworkCredential> ListenHttpForRedirectAsync(string listenerUrl)
65
        {
66
            using (var listener = new HttpListener())
67
            {
68
                listener.Prefixes.Add(listenerUrl);
69

  
70
                Log.InfoFormat("[RETRIEVE] Listening at {0}", listenerUrl);
53 71

  
54
            listener.Start();
55
            
56
            var startListening = Task.Factory.FromAsync<HttpListenerContext>(listener.BeginGetContext, listener.EndGetContext, null)
57
                .WithTimeout(TimeSpan.FromMinutes(5));
58 72

  
59
            var receiveCredentials=startListening.ContinueWith(tc =>
73
                try
60 74
                {
61
                    try
62
                    {
63
                        if (tc.IsFaulted)
64
                        {
65
                            Log.Error("[RETRIEVE][ERROR] Receive connection {0}", tc.Exception);
66
                            throw tc.Exception;
67
                        }
68
                        else
69
                        {
75
                    listener.Start();
70 76

  
71
                            var context = tc.Result;
72
                            var request = context.Request;
73
                            Log.InfoFormat("[RETRIEVE] Got Connection {0}", request.RawUrl);
74

  
75
                            var query = request.QueryString;
76
                            var userName = query["user"];
77
                            var token = query["token"];
78
                            if (String.IsNullOrWhiteSpace(userName) || String.IsNullOrWhiteSpace(token))
79
                            {
80
                                Respond(context, "Failure", "The server did not return a username or token");
81
                                Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
82
                                throw new Exception("The server did not return a username or token");
83
                            }
84
                            else
85
                            {
86

  
87
                                Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
88
                                Respond(context, "Authenticated", "Got It");
89

  
90
                                return new NetworkCredential(userName, token);
91
                            }
92
                        }
77
                    var context = await listener.GetContextAsync()
78
                                            .WithTimeout(TimeSpan.FromMinutes(5));
93 79

  
80
                    var request = context.Request;
81
                    Log.InfoFormat("[RETRIEVE] Got Connection {0}", request.RawUrl);
82

  
83
                    var query = request.QueryString;
84
                    var userName = query["user"];
85
                    var token = query["token"];
86
                    if (String.IsNullOrWhiteSpace(userName) ||
87
                        String.IsNullOrWhiteSpace(token))
88
                    {
89
                        Respond(context, "Failure", "The server did not return a username or token");
90
                        Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
91
                        throw new Exception("The server did not return a username or token");
94 92
                    }
95
                    finally
93
                    else
96 94
                    {
97
                        listener.Close();
95
                        Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
96
                        Respond(context, "Authenticated", "Got It");
97

  
98
                        return new NetworkCredential(userName, token);
98 99
                    }
99
                });
100
                }
101
                catch (Exception exc)
102
                {
103
                    Log.Error("[RETRIEVE][ERROR] Receive connection {0}", exc);
104
                    throw;
105
                }
106
            }
107
        }
100 108

  
101
            var uriBuilder=new UriBuilder(loginUrl);                       
102
            uriBuilder.Query="next=" + listenerUrl;
109
        private static async Task<NetworkCredential> ListenForRedirectAsync(int port)
110
        {
111
            var listener = new TcpListener(IPAddress.Any, port);            
112
            Log.InfoFormat("[RETRIEVE] Listening at {0}", port);
103 113

  
104
            var retrieveUri = uriBuilder.Uri;
105
            Log.InfoFormat("[RETRIEVE] Open Browser at {0}", retrieveUri);
106
            Process.Start(retrieveUri.ToString());
114
            try
115
            {
116
                listener.Start();
107 117

  
108
            return receiveCredentials;
118
                using (var client = await listener.AcceptTcpClientAsync()
119
                                        .WithTimeout(TimeSpan.FromMinutes(5)))
120
                {
121

  
122
                    using (var stream = client.GetStream())
123
                    using (var reader=new StreamReader(stream))
124
                    {
125
                        var request = await reader.ReadLineAsync();
126
                        Log.InfoFormat("[RETRIEVE] Got Connection {0}", request);
127

  
128

  
129
                        var parts=request.Split(' ');
130
                        var query = parts[1].TrimStart('/','?');
131

  
132
                        var items = query.Split('&')
133
                            .Select(pair => pair.Split('='))
134
                            .ToDictionary(arr => arr[0].ToLower(), arr => Uri.UnescapeDataString(arr[1]));
135

  
136
                        var userName = items["user"];
137
                        var token = items["token"];
138
                        if (String.IsNullOrWhiteSpace(userName) ||
139
                            String.IsNullOrWhiteSpace(token))
140
                        {
141
                            Respond(stream, "Failure", "The server did not return a username or token");
142
                            Log.ErrorFormat("[RETRIEVE] No credentials returned by server");
143
                            throw new Exception("The server did not return a username or token");
144
                        }
145
                        else
146
                        {
147
                            Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
148
                            Respond(stream, "Authenticated", "Got It");                            
149
                        }
150
                        return new NetworkCredential(userName, token);
151
                    }
152
                }
153
            }
154
            catch (Exception exc)
155
            {
156
                Log.Error("[RETRIEVE][ERROR] Receive connection {0}", exc);
157
                throw;
158
            }
109 159
        }
110 160

  
161

  
162

  
111 163
        private static void Respond(HttpListenerContext context,string title,string message)
112 164
        {
113 165
            var response = context.Response;
......
121 173

  
122 174
            Log.InfoFormat("[RETRIEVE] Responded");
123 175
        }
176

  
177
        private static void Respond(Stream stream,string title,string message)
178
        {
179
            
180
            var html = String.Format("<html><head><title>{0}</title></head><body><h1>{1}</h1></body></html>", title, message);
181
            
182
            var response = new StringBuilder();
183
            response.AppendLine("HTTP/1.1 200 OK");
184
            response.AppendFormat("Content-Length: {0}\n", html.Length);
185
            response.AppendLine("Server: Microsoft-HTTPAPI/2.0");
186
            response.AppendFormat("Date: {0}\n\n", DateTime.UtcNow);
187
            response.AppendLine(html);
188

  
189
            var outBuffer=Encoding.UTF8.GetBytes(response.ToString());
190
            
191
            stream.Write(outBuffer, 0, outBuffer.Length);
192

  
193
            Log.InfoFormat("[RETRIEVE] Responded");
194
        }
195

  
196
       
124 197
        /// <summary>
125 198
        /// Locates a free local port 
126 199
        /// </summary>
b/trunk/Pithos.Client.WPF/Preferences/AddAccountViewModel.cs
124 124

  
125 125
            try
126 126
            {
127
                var credentials = await PithosAccount.RetrieveCredentialsAsync(Settings.Default.PithosLoginUrl);
127
                var credentials = await PithosAccount.RetrieveCredentials(Settings.Default.PithosLoginUrl);
128 128
                AccountName = credentials.UserName;
129 129
                Token = credentials.Password;
130 130

  
b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
250 250

  
251 251
        public async void AddPithosAccount()
252 252
       {
253
            var credentials=await PithosAccount.RetrieveCredentialsAsync(Settings.PithosLoginUrl);
253
            var credentials=await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
254 254
            var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
255 255
            if (account == null)
256 256
            {
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
523 523
            try
524 524
            {
525 525

  
526
                var credentials = await PithosAccount.RetrieveCredentialsAsync(Settings.PithosLoginUrl);
526
                var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
527 527

  
528 528
                var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
529 529
                account.ApiKey = credentials.Password;

Also available in: Unified diff