Files
runner/src/Sdk/AadAuthentication/CookieUtility.cs
2019-10-10 00:52:42 -04:00

265 lines
9.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using GitHub.Services.Common;
namespace GitHub.Services.Client
{
internal static class CookieUtility
{
public static readonly String AcsMetadataRetrievalExceptionText = "Unable to retrieve ACS Metadata from '{0}'";
public static readonly String FedAuthCookieName = "FedAuth";
public static readonly String WindowsLiveSignOutUrl = "https://login.live.com/uilogout.srf";
public static readonly Uri WindowsLiveCookieDomain = new Uri("https://login.live.com/");
public static CookieCollection GetFederatedCookies(Uri cookieDomainAndPath)
{
CookieCollection result = null;
Cookie cookie = GetCookieEx(cookieDomainAndPath, FedAuthCookieName).FirstOrDefault();
if (cookie != null)
{
result = new CookieCollection();
result.Add(cookie);
for (Int32 x = 1; x < 50; x++)
{
String cookieName = FedAuthCookieName + x;
cookie = GetCookieEx(cookieDomainAndPath, cookieName).FirstOrDefault();
if (cookie != null)
{
result.Add(cookie);
}
else
{
break;
}
}
}
return result;
}
public static CookieCollection GetFederatedCookies(String[] token)
{
CookieCollection result = null;
if (token != null && token.Length > 0 && token[0] != null)
{
result = new CookieCollection();
result.Add(new Cookie(FedAuthCookieName, token[0]));
for (Int32 x = 1; x < token.Length; x++)
{
String cookieName = FedAuthCookieName + x;
if (token[x] != null)
{
Cookie cookie = new Cookie(cookieName, token[x]);
cookie.HttpOnly = true;
result.Add(cookie);
}
else
{
break;
}
}
}
return result;
}
public static CookieCollection GetFederatedCookies(IHttpResponse webResponse)
{
CookieCollection result = null;
IEnumerable<String> cookies = null;
if (webResponse.Headers.TryGetValues("Set-Cookie", out cookies))
{
foreach (String cookie in cookies)
{
if (cookie != null && cookie.StartsWith(CookieUtility.FedAuthCookieName, StringComparison.OrdinalIgnoreCase))
{
// Only take the security token field of the cookie, and discard the rest
String fedAuthToken = cookie.Split(';').FirstOrDefault();
Int32 index = fedAuthToken.IndexOf('=');
if (index > 0 && index < fedAuthToken.Length - 1)
{
String name = fedAuthToken.Substring(0, index);
String value = fedAuthToken.Substring(index + 1);
result = result ?? new CookieCollection();
result.Add(new Cookie(name, value));
}
}
}
}
return result;
}
public static CookieCollection GetAllCookies(Uri cookieDomainAndPath)
{
CookieCollection result = null;
List<Cookie> cookies = GetCookieEx(cookieDomainAndPath, null);
foreach (Cookie cookie in cookies)
{
if (result == null)
{
result = new CookieCollection();
}
result.Add(cookie);
}
return result;
}
public static void DeleteFederatedCookies(Uri cookieDomainAndPath)
{
CookieCollection cookies = GetFederatedCookies(cookieDomainAndPath);
if (cookies != null)
{
foreach (Cookie cookie in cookies)
{
DeleteCookieEx(cookieDomainAndPath, cookie.Name);
}
}
}
public static void DeleteWindowsLiveCookies()
{
DeleteAllCookies(WindowsLiveCookieDomain);
}
public static void DeleteAllCookies(Uri cookieDomainAndPath)
{
CookieCollection cookies = GetAllCookies(cookieDomainAndPath);
if (cookies != null)
{
foreach (Cookie cookie in cookies)
{
DeleteCookieEx(cookieDomainAndPath, cookie.Name);
}
}
}
public const UInt32 INTERNET_COOKIE_HTTPONLY = 0x00002000;
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool InternetGetCookieEx(
String url, String cookieName, StringBuilder cookieData, ref Int32 size, UInt32 flags, IntPtr reserved);
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool InternetSetCookieEx(
String url, String cookieName, String cookieData, UInt32 flags, IntPtr reserved);
public static Boolean DeleteCookieEx(Uri cookiePath, String cookieName)
{
UInt32 flags = INTERNET_COOKIE_HTTPONLY;
String path = cookiePath.ToString();
if (!path.EndsWith("/", StringComparison.Ordinal))
{
path = path + "/";
}
DateTime expiration = DateTime.UtcNow.AddYears(-1);
String cookieData = String.Format(CultureInfo.InvariantCulture, "{0}=0;expires={1};path=/;domain={2};httponly", cookieName, expiration.ToString("R"), cookiePath.Host);
return InternetSetCookieEx(path, null, cookieData, flags, IntPtr.Zero);
}
public static Boolean SetCookiesEx(
Uri cookiePath,
CookieCollection cookies)
{
String path = cookiePath.ToString();
if (!path.EndsWith("/", StringComparison.Ordinal))
{
path = path + "/";
}
Boolean successful = true;
foreach (Cookie cookie in cookies)
{
// This means it doesn't expire
if (cookie.Expires.Year == 1)
{
continue;
}
String cookieData = String.Format(CultureInfo.InvariantCulture,
"{0}; path={1}; domain={2}; expires={3}; httponly",
cookie.Value,
cookie.Path,
cookie.Domain,
cookie.Expires.ToString("ddd, dd-MMM-yyyy HH:mm:ss 'GMT'"));
successful &= InternetSetCookieEx(path, cookie.Name, cookieData, INTERNET_COOKIE_HTTPONLY, IntPtr.Zero);
}
return successful;
}
public static List<Cookie> GetCookieEx(Uri cookiePath, String cookieName)
{
UInt32 flags = INTERNET_COOKIE_HTTPONLY;
List<Cookie> cookies = new List<Cookie>();
Int32 size = 256;
StringBuilder cookieData = new StringBuilder(size);
String path = cookiePath.ToString();
if (!path.EndsWith("/", StringComparison.Ordinal))
{
path = path + "/";
}
if (!InternetGetCookieEx(path, cookieName, cookieData, ref size, flags, IntPtr.Zero))
{
if (size < 0)
{
return cookies;
}
cookieData = new StringBuilder(size);
if (!InternetGetCookieEx(path, cookieName, cookieData, ref size, flags, IntPtr.Zero))
{
return cookies;
}
}
if (cookieData.Length > 0)
{
String[] cookieSections = cookieData.ToString().Split(new char[] { ';' });
foreach (String cookieSection in cookieSections)
{
String[] cookieParts = cookieSection.Split(new char[] { '=' }, 2);
if (cookieParts.Length == 2)
{
Cookie cookie = new Cookie();
cookie.Name = cookieParts[0].TrimStart();
cookie.Value = cookieParts[1];
cookie.HttpOnly = true;
cookies.Add(cookie);
}
}
}
return cookies;
}
}
}