source: binary-improvements/MapRendering/Web/OpenID.cs@ 324

Last change on this file since 324 was 318, checked in by alloc, 7 years ago

Added console command openiddebug

File size: 7.6 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Collections.Specialized;
4using System.IO;
5using System.Net;
6using System.Net.Security;
7using System.Text;
8using System.Text.RegularExpressions;
9using System.Security.Cryptography.X509Certificates;
10using System.Reflection;
11
12namespace AllocsFixes.NetConnections.Servers.Web
13{
14 public static class OpenID {
15 private const string STEAM_LOGIN = "https://steamcommunity.com/openid/login";
16 private static Regex steamIdUrlMatcher = new Regex (@"^https?:\/\/steamcommunity\.com\/openid\/id\/([0-9]{17,18})");
17
18 private static readonly X509Certificate2 caCert = new X509Certificate2 (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/steam-rootca.cer");
19 private static readonly X509Certificate2 caIntermediateCert = new X509Certificate2 (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/steam-intermediate.cer");
20
21 private static readonly bool verboseSsl = false;
22 public static bool debugOpenId = false;
23
24 static OpenID () {
25 for (int i = 0; i < System.Environment.GetCommandLineArgs ().Length; i++) {
26 if (System.Environment.GetCommandLineArgs () [i].EqualsCaseInsensitive ("-debugopenid")) {
27 debugOpenId = true;
28 }
29 }
30
31 ServicePointManager.ServerCertificateValidationCallback = (srvPoint, certificate, chain, errors) => {
32 if (errors == SslPolicyErrors.None) {
33 if (verboseSsl) {
34 Log.Out ("Steam certificate: No error (1)");
35 }
36 return true;
37 }
38
39 X509Chain privateChain = new X509Chain ();
40 privateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
41
42 privateChain.ChainPolicy.ExtraStore.Add (caCert);
43 privateChain.ChainPolicy.ExtraStore.Add (caIntermediateCert);
44
45 if (privateChain.Build (new X509Certificate2 (certificate))) {
46 // No errors, immediately return
47 privateChain.Reset ();
48 if (verboseSsl) {
49 Log.Out ("Steam certificate: No error (2)");
50 }
51 return true;
52 }
53
54 if (privateChain.ChainStatus.Length == 0) {
55 // No errors, immediately return
56 privateChain.Reset ();
57 if (verboseSsl) {
58 Log.Out ("Steam certificate: No error (3)");
59 }
60 return true;
61 }
62
63 // Iterate all chain elements
64 foreach (X509ChainElement chainEl in privateChain.ChainElements) {
65 if (verboseSsl) {
66 Log.Out ("Validating cert: " + chainEl.Certificate.Subject);
67 }
68 // Iterate all status flags of the current cert
69 foreach (X509ChainStatus chainStatus in chainEl.ChainElementStatus) {
70 if (verboseSsl) {
71 Log.Out (" Status: " + chainStatus.Status);
72 }
73 if (chainStatus.Status == X509ChainStatusFlags.NoError) {
74 // This status is not an error, skip
75 continue;
76 }
77 if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot && chainEl.Certificate == caCert) {
78 // This status is about the cert being an untrusted root certificate but the certificate is one of those we added, ignore
79 continue;
80 }
81 // This status is an error, print information
82 Log.Warning ("Steam certificate error: " + chainEl.Certificate.Subject + " ### Error: " + chainStatus.Status);
83 privateChain.Reset ();
84 return false;
85 }
86 }
87
88 foreach (X509ChainStatus chainStatus in privateChain.ChainStatus) {
89 if (chainStatus.Status != X509ChainStatusFlags.NoError && chainStatus.Status != X509ChainStatusFlags.UntrustedRoot) {
90 Log.Warning ("Steam certificate error: " + chainStatus.Status);
91 privateChain.Reset ();
92 return false;
93 }
94 }
95
96 // We didn't find any errors, chain is valid
97 privateChain.Reset ();
98 if (verboseSsl) {
99 Log.Out ("Steam certificate: No error (4)");
100 }
101 return true;
102 };
103
104 }
105
106 public static string GetOpenIdLoginUrl (string _returnHost, string _returnUrl) {
107 Dictionary<string, string> queryParams = new Dictionary<string, string> ();
108
109 queryParams.Add ("openid.ns", "http://specs.openid.net/auth/2.0");
110 queryParams.Add ("openid.mode", "checkid_setup");
111 queryParams.Add ("openid.return_to", _returnUrl);
112 queryParams.Add ("openid.realm", _returnHost);
113 queryParams.Add ("openid.identity", "http://specs.openid.net/auth/2.0/identifier_select");
114 queryParams.Add ("openid.claimed_id", "http://specs.openid.net/auth/2.0/identifier_select");
115
116 return STEAM_LOGIN + '?' + buildUrlParams (queryParams);
117 }
118
119 public static ulong Validate (HttpListenerRequest _req) {
120 string mode = getValue (_req, "openid.mode");
121 if (mode == "cancel") {
122 Log.Warning ("Steam OpenID login canceled");
123 return 0;
124 }
125 if (mode == "error") {
126 Log.Warning ("Steam OpenID login error: " + getValue (_req, "openid.error"));
127 if (debugOpenId) {
128 PrintOpenIdResponse (_req);
129 }
130 return 0;
131 }
132 string steamIdString = getValue (_req, "openid.claimed_id");
133 ulong steamId = 0;
134 Match steamIdMatch = steamIdUrlMatcher.Match (steamIdString);
135 if (steamIdMatch.Success) {
136 steamId = ulong.Parse (steamIdMatch.Groups [1].Value);
137 } else {
138 Log.Warning ("Steam OpenID login result did not give a valid SteamID");
139 if (debugOpenId) {
140 PrintOpenIdResponse (_req);
141 }
142 return 0;
143 }
144
145 Dictionary<string, string> queryParams = new Dictionary<string, string> ();
146
147 queryParams.Add ("openid.ns", "http://specs.openid.net/auth/2.0");
148
149 queryParams.Add ("openid.assoc_handle", getValue (_req, "openid.assoc_handle"));
150 queryParams.Add ("openid.signed", getValue (_req, "openid.signed"));
151 queryParams.Add ("openid.sig", getValue (_req, "openid.sig"));
152 queryParams.Add ("openid.identity", "http://specs.openid.net/auth/2.0/identifier_select");
153 queryParams.Add ("openid.claimed_id", "http://specs.openid.net/auth/2.0/identifier_select");
154
155 string[] signeds = getValue (_req, "openid.signed").Split (',');
156 foreach (string s in signeds) {
157 queryParams ["openid." + s] = getValue (_req, "openid." + s);
158 }
159
160 queryParams.Add ("openid.mode", "check_authentication");
161
162 byte[] postData = Encoding.ASCII.GetBytes (buildUrlParams (queryParams));
163 HttpWebRequest request = (HttpWebRequest)WebRequest.Create (STEAM_LOGIN);
164 request.Method = "POST";
165 request.ContentType = "application/x-www-form-urlencoded";
166 request.ContentLength = postData.Length;
167 request.Headers.Add (HttpRequestHeader.AcceptLanguage, "en");
168 using (Stream st = request.GetRequestStream ()) {
169 st.Write (postData, 0, postData.Length);
170 }
171
172 HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
173 string responseString = null;
174 using (Stream st = response.GetResponseStream ()) {
175 using (StreamReader str = new StreamReader (st)) {
176 responseString = str.ReadToEnd ();
177 }
178 }
179
180 if (responseString.ToLower ().Contains ("is_valid:true")) {
181 return steamId;
182 } else {
183 Log.Warning ("Steam OpenID login failed: {0}", responseString);
184 return 0;
185 }
186 }
187
188 private static string buildUrlParams (Dictionary<string, string> _queryParams) {
189 string[] paramsArr = new string[_queryParams.Count];
190 int i = 0;
191 foreach (KeyValuePair<string, string> kvp in _queryParams) {
192 paramsArr [i++] = kvp.Key + "=" + Uri.EscapeDataString (kvp.Value);
193 }
194 return string.Join ("&", paramsArr);
195 }
196
197 private static string getValue (HttpListenerRequest _req, string _name) {
198 NameValueCollection nvc = _req.QueryString;
199 if (nvc [_name] == null) {
200 throw new MissingMemberException ("OpenID parameter \"" + _name + "\" missing");
201 }
202 return nvc [_name];
203 }
204
205 private static void PrintOpenIdResponse (HttpListenerRequest _req) {
206 NameValueCollection nvc = _req.QueryString;
207 for (int i = 0; i < nvc.Count; i++) {
208 Log.Out (" " + nvc.GetKey (i) + " = " + nvc [i]);
209 }
210 }
211
212 }
213}
214
Note: See TracBrowser for help on using the repository browser.