public class EsiaModule : NancyModule { static string client_id = "123456"; // , static string state = Guid.NewGuid().ToString("D"); // static string server_url = "https://esia.gosuslugi.ru/aas/oauth2/ac"; // static string server_url_2 = "https://esia.gosuslugi.ru/aas/oauth2/te"; // static string server_url_prns = "https://esia.gosuslugi.ru/rs/prns/"; // // /* static string server_url = "https://esia-portal1.test.gosuslugi.ru/aas/oauth2/ac"; static string server_url_2 = "https://esia-portal1.test.gosuslugi.ru/aas/oauth2/te"; static string server_url_prns = "https://esia-portal1.test.gosuslugi.ru/rs/prns/";*/ public EsiaModule() { Get["/ESIA"] = _ => { //string scope = "openid"; string scope = "fullname"; string timestamp = DateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000"); string access_type = "online"; string response_type = "code"; string redirect_uri = Request.Url.Scheme + "://" + Request.Url.HostName + (Request.Url.Port == 80 ? "" : (":" + Request.Url.Port.ToString())) + "/ESIA-OK"; // , string client_secret = ""; // string msg = scope + timestamp + client_id + state; byte[] msgBytes = Encoding.UTF8.GetBytes(msg); var signerCert = DetachedSignature.GetSignerCert(); byte[] encodedSignature = DetachedSignature.SignMsg(msgBytes, signerCert); client_secret = HttpServerUtility.UrlTokenEncode(encodedSignature); // RequestBuilder builder = new RequestBuilder(); builder.AddParam("client_id", client_id); builder.AddParam("client_secret", client_secret); builder.AddParam("redirect_uri", redirect_uri); builder.AddParam("scope", scope); builder.AddParam("response_type", response_type); builder.AddParam("state", state); builder.AddParam("timestamp", timestamp); builder.AddParam("access_type", access_type); string red_url = server_url + "?" + builder.ToString().Replace("+", "%2b"); return Response.AsRedirect(red_url); }; Get["/ESIA-OK"] = _ => { // , state , code string state_r = Request.Query["state"]; string code = Request.Query["code"]; if (state == state_r) { //string scope = "openid"; string scope = "fullname"; string timestamp = DateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000"); string redirect_uri = Request.Url.Scheme + "://" + Request.Url.HostName + (Request.Url.Port == 80 ? "" : (":" + Request.Url.Port.ToString())) + "/ESIA-OK"; string client_secret = ""; string msg = scope + timestamp + client_id + state; byte[] msgBytes = Encoding.UTF8.GetBytes(msg); var signerCert = DetachedSignature.GetSignerCert(); byte[] encodedSignature = DetachedSignature.SignMsg(msgBytes, signerCert); client_secret = HttpServerUtility.UrlTokenEncode(encodedSignature); string result; // post { RequestBuilder builder = new RequestBuilder(); builder.AddParam("client_id", client_id); builder.AddParam("code", code); builder.AddParam("grant_type", "authorization_code"); builder.AddParam("client_secret", client_secret); builder.AddParam("state", state); builder.AddParam("redirect_uri", redirect_uri); builder.AddParam("scope", scope); builder.AddParam("timestamp", timestamp); builder.AddParam("token_type", "Bearer"); var httpWebRequest = (HttpWebRequest)WebRequest.Create(server_url_2); httpWebRequest.ContentType = "application/x-www-form-urlencoded"; httpWebRequest.Method = "POST"; httpWebRequest.Timeout = int.MaxValue; httpWebRequest.Proxy = p; using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { streamWriter.Write(builder.ToString().Replace("+", "%2b")); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { result = streamReader.ReadToEnd(); } } ESIA_Marker_Answer marker = JsonConvert.DeserializeObject<ESIA_Marker_Answer>(result);// string[] marker_parts = marker.access_token.Split('.'); string header = Encoding.UTF8.GetString(base64urldecode(marker_parts[0])); string payload = Encoding.UTF8.GetString(base64urldecode(marker_parts[1])); string oid = (JsonConvert.DeserializeObject<dynamic>(payload))["urn:esia:sbj_id"]; // string user_info = ""; { var httpWebRequest = (HttpWebRequest)WebRequest.Create(server_url_prns + oid); httpWebRequest.ContentType = "application/x-www-form-urlencoded"; httpWebRequest.Method = "GET"; httpWebRequest.Headers["Authorization"] = "Bearer " + marker.access_token; httpWebRequest.Timeout = int.MaxValue; var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { user_info = streamReader.ReadToEnd(); } } string firstName = JsonConvert.DeserializeObject<dynamic>(user_info)["firstName"]; string lastName = ""; try { lastName = JsonConvert.DeserializeObject<dynamic>(user_info)["lastName"]; } catch { } string middleName = ""; try { middleName = JsonConvert.DeserializeObject<dynamic>(user_info)["middleName"]; } catch { } // MyEntities db = new MyEntities(); Helper h = new Helper(); users u; if (db.users.Any(a => a.esia_oid.Trim() == oid.Trim())) { u = db.users.FirstOrDefault(a => a.esia_oid.Trim() == oid.Trim()); } else { //create user u = new users { mail = oid, name = firstName, pass = h.HashWithSalt(oid), patronymic = middleName ?? "", surname = lastName ?? "", token = Guid.NewGuid().ToString("N"), role_id = 2, esia_oid = oid }; db.users.Add(u); db.SaveChanges(); } // DateTime expires = DateTime.UtcNow.AddYears(20); List<NancyCookie> cs = new List<NancyCookie> { new NancyCookie("id", u.id.ToString(), false) { Expires = expires }, new NancyCookie("token", u.token, false) { Expires = expires } }; var resp = Response.AsRedirect("/"); resp.AddCookie(cs[0]); resp.AddCookie(cs[1]); return resp; } else { return Response.AsJson(new { err = 1 }); } }; } static byte[] base64urldecode(string arg) { string s = arg; s = s.Replace('-', '+'); // 62nd char of encoding s = s.Replace('_', '/'); // 63rd char of encoding switch (s.Length % 4) // Pad with trailing '='s { case 0: break; // No pad chars in this case case 2: s += "=="; break; // Two pad chars case 3: s += "="; break; // One pad char default: throw new System.Exception( "Illegal base64url string!"); } return Convert.FromBase64String(s); // Standard base64 decoder } } public class RequestBuilder { List<RequesItemClass> items = new List<RequesItemClass>(); public void AddParam(string name, string value) { items.Add(new RequesItemClass { name = name, value = value }); } override public string ToString() { return string.Join("&", items.Select(a => a.name + "=" + a.value)); } } class DetachedSignature { static public X509Certificate2 GetSignerCert() { X509Store storeMy = new X509Store(StoreName.My, StoreLocation.LocalMachine); storeMy.Open(OpenFlags.ReadOnly); X509Certificate2Collection certColl = storeMy.Certificates.Find(X509FindType.FindBySubjectKeyIdentifier, "12 34 56 78 90 00 00 00 11 11 11 11 11 11 11 11 11 22 33 44", false); storeMy.Close(); return certColl[0]; } static public byte[] SignMsg(Byte[] msg, X509Certificate2 signerCert) { ContentInfo contentInfo = new ContentInfo(msg); SignedCms signedCms = new SignedCms(contentInfo, true); CmsSigner cmsSigner = new CmsSigner(signerCert); signedCms.ComputeSignature(cmsSigner); return signedCms.Encode(); } static public bool VerifyMsg(Byte[] msg, byte[] encodedSignature) { ContentInfo contentInfo = new ContentInfo(msg); SignedCms signedCms = new SignedCms(contentInfo, true); signedCms.Decode(encodedSignature); try { signedCms.CheckSignature(true); } catch (System.Security.Cryptography.CryptographicException e) { return false; } return true; } } public class ESIA_Marker_Answer { public string state { get; set; } public string token_type { get; set; } public int expires_in { get; set; } public string refresh_token { get; set; } public string id_token { get; set; } public string access_token { get; set; } } public class RequesItemClass { public string name; public string value; }
Source: https://habr.com/ru/post/276313/
All Articles