Advertisement
Guest User

Untitled

a guest
Aug 8th, 2017
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.38 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Web;
  6. using System.Net.Http;
  7. using System.Net.Http.Headers;
  8. using System.Security.Principal;
  9. using System.Threading;
  10. using System.DirectoryServices.AccountManagement;
  11.  
  12. namespace MyApp.Security
  13. {
  14. public class BasicAuthMessageHandler : DelegatingHandler
  15. {
  16.  
  17. protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  18. {
  19. AuthenticationHeaderValue authValue = request.Headers.Authorization;
  20. if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter))
  21. {
  22. string username = null;
  23. string password = null;
  24. string toSplit = Encoding.UTF8.GetString(Convert.FromBase64String(authValue.Parameter));
  25. int index;
  26. if ((index = toSplit.IndexOf(":")) != -1)//verifies that they included at least the : between the username and password
  27. {
  28. username = toSplit.Substring(0, index);
  29. password = toSplit.Substring(index + 1);
  30. }
  31. //makes sure that there IS some semblance of a username and password. Blanks aren't allowed.
  32. if ( !string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
  33. {
  34. IPrincipal currentPrincipal = CreatePrincipal(username, password);//Validates the credentials and creates a principal containing their domain groups
  35. Thread.CurrentPrincipal = currentPrincipal;//sets the principal for the thread
  36. HttpContext.Current.User = currentPrincipal;//sets the principal for the HttpContext
  37. }
  38. }
  39. return base.SendAsync(request, cancellationToken);
  40. }
  41. private IPrincipal CreatePrincipal(String username, String password)
  42. {
  43. PrincipalContext ctx = new PrincipalContext(ContextType.Domain);//Sets up a context for the domain the app is running in
  44. if (username.ToLower() == "token")//special case where the username is "token" means we're using token authentication instead of normal basic authentication
  45. {
  46. username = TokenCache.localTokenCache.validateToken(password);//checks for presence of the token in the cache and grabs the username associated with it if any.
  47. if (username == null)
  48. {
  49. return null;//No token? No login!
  50. }
  51. else
  52. {
  53. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
  54. if (user.Enabled == true)//make sure their account isn't disabled.
  55. {
  56. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  57. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  58. groups.Add(user.Sid.Value);//also add their own SID
  59. groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
  60. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  61. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  62. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
  63. }
  64. else
  65. {
  66. return null;//disabled account? No login!
  67. }
  68. }
  69. }
  70. if (ctx.ValidateCredentials(username, password))//if they give an actual username and password, we authenticate against the domain!
  71. {
  72. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
  73. string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);//generate a new token for the user
  74. if (user.Enabled == true)//make sure their account isn't disabled.
  75. {
  76. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  77. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  78. groups.Add(user.Sid.Value);//also add their own SID
  79. groups.Add("Auth:Basic");//Lets me check later from APIs if they authenticated with a token or username and password.
  80. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  81. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  82. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());//Creates and returns the Principal
  83. }
  84. else
  85. {
  86. return null;//disabled account? No login!
  87. }
  88. }
  89. return null;//invalid username and password? No login!
  90. }
  91. }
  92. }
  93.  
  94. using System;
  95. using System.Security.Cryptography;
  96. using System.Collections.Generic;
  97.  
  98. namespace MyApp.Security
  99. {
  100. class TokenCache : IDisposable
  101. {
  102. public static readonly TokenCache localTokenCache = new TokenCache(new TimeSpan(20,0,0));//Singleton where tokens expire after 20 hours
  103. private Dictionary<string, string> userToToken = new Dictionary<string, string>();
  104. private Dictionary<string, string> tokenToUser = new Dictionary<string, string>();
  105. private Dictionary<string, DateTime> tokenToDate = new Dictionary<string, DateTime>();
  106.  
  107. private RNGCryptoServiceProvider numgen;
  108. private TimeSpan _maxValidity;
  109. private TokenCache(TimeSpan maxValidity)
  110. {
  111. _maxValidity = maxValidity;
  112. numgen = new RNGCryptoServiceProvider();
  113. }
  114. public string validateToken(string token)
  115. {
  116. if (tokenToUser.ContainsKey(token) && DateTime.Now - tokenToDate[token] < _maxValidity)//do we have the token, and is it unexpired?
  117. {
  118. return tokenToUser[token];//Yes? Return username.
  119. }else
  120. {
  121. return null;//No? Then return null;
  122. }
  123. }
  124. public string generateNewToken(string username)
  125. {
  126. byte[] tokenarr = new byte[33];
  127. numgen.GetBytes(tokenarr);
  128. string token = SimpleMethods.Base642URL(Convert.ToBase64String(tokenarr));//Makes a URL friendly token
  129. DateTime createdon = DateTime.Now;
  130. removePreviousTokens(username, service);
  131. tokenToUser.Add(token, username);
  132. userToToken.Add(username, token);
  133. tokenToDate.Add(token, createdon);
  134. return token;
  135. }
  136. private void removePreviousTokens(string username)
  137. {
  138. if(userToToken.ContainsKey(username))
  139. {
  140. string token = userToToken[username];
  141. tokenToUser.Remove(token);
  142. userToToken.Remove(username);
  143. tokenToDate.Remove(token);
  144. }
  145. }
  146.  
  147. #region IDisposable Support
  148. private bool disposedValue = false; // To detect redundant calls
  149.  
  150. protected virtual void Dispose(bool disposing)
  151. {
  152. if (!disposedValue)
  153. {
  154. if (disposing)
  155. {
  156. numgen.Dispose();
  157. }
  158. tokenToDate = null;
  159. tokenToUser = null;
  160. userToToken = null;
  161. disposedValue = true;
  162. }
  163. }
  164.  
  165. public void Dispose()
  166. {
  167. Dispose(true);
  168. }
  169. #endregion
  170. }
  171. }
  172.  
  173. public static string Base642URL(string base64String)
  174. {
  175. base64String = base64String.Replace("+", "-");
  176. base64String = base64String.Replace("/", "_");
  177. base64String = base64String.Replace("=", "");
  178. return base64String;
  179. }
  180.  
  181. public static string Base642URL(string base64String)
  182. {
  183. base64String = base64String.Replace("+", "-");
  184. base64String = base64String.Replace("/", "_");
  185. base64String = base64String.Replace("=", "");
  186. return base64String;
  187. }
  188.  
  189. public static class StringExtensions
  190. {
  191. public static string Base642URL(this string base64String)
  192. {
  193. base64String = base64String.Replace("+", "-");
  194. base64String = base64String.Replace("/", "_");
  195. base64String = base64String.Replace("=", "");
  196. return base64String;
  197. }
  198. }
  199.  
  200. private IPrincipal CreatePrincipal(String username, String password)
  201. {
  202. PrincipalContext ctx = new PrincipalContext(ContextType.Domain);//Sets up a context for the domain the app is running in
  203. if (username.ToLower() == "token")//special case where the username is "token" means we're using token authentication instead of normal basic authentication
  204. {
  205. username = TokenCache.localTokenCache.validateToken(password);//checks for presence of the token in the cache and grabs the username associated with it if any.
  206. if (username == null)
  207. {
  208. return null;//No token? No login!
  209. }
  210. else
  211. {
  212. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
  213. if (user.Enabled == true)//make sure their account isn't disabled.
  214. {
  215. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  216. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  217. groups.Add(user.Sid.Value);//also add their own SID
  218. groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
  219. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  220. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  221. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
  222. }
  223. else
  224. {
  225. return null;//disabled account? No login!
  226. }
  227. }
  228. }
  229. if (ctx.ValidateCredentials(username, password))//if they give an actual username and password, we authenticate against the domain!
  230. {
  231. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
  232. string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);//generate a new token for the user
  233. if (user.Enabled == true)//make sure their account isn't disabled.
  234. {
  235. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  236. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  237. groups.Add(user.Sid.Value);//also add their own SID
  238. groups.Add("Auth:Basic");//Lets me check later from APIs if they authenticated with a token or username and password.
  239. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  240. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  241. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());//Creates and returns the Principal
  242. }
  243. else
  244. {
  245. return null;//disabled account? No login!
  246. }
  247. }
  248. return null;//invalid username and password? No login!
  249. }
  250.  
  251. if (username == null)
  252. {
  253. return null;//No token? No login!
  254. }
  255. else
  256. {
  257.  
  258. if (username == null)
  259. {
  260. return null;
  261. }
  262. // Just continue with the code
  263.  
  264. if (user.Enabled == true)//make sure their account isn't disabled.
  265. {
  266. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  267. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  268. groups.Add(user.Sid.Value);//also add their own SID
  269. groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
  270. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  271. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  272. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
  273. }
  274. else
  275. {
  276. return null;//disabled account? No login!
  277. }
  278.  
  279. if (user.Enabled != true) // Not the same as `== false`
  280. {
  281. return null;
  282. }
  283. // Continue with the code
  284.  
  285. private IPrincipal CreatePrincipal(String username, String password)
  286. {
  287. PrincipalContext ctx = new PrincipalContext(ContextType.Domain);//Sets up a context for the domain the app is running in
  288. if (username.ToLower() == "token")//special case where the username is "token" means we're using token authentication instead of normal basic authentication
  289. {
  290. username = TokenCache.localTokenCache.validateToken(password);//checks for presence of the token in the cache and grabs the username associated with it if any.
  291. if (username == null)
  292. {
  293. return null;//No token? No login!
  294. }
  295.  
  296. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
  297. if (user.Enabled != true)//make sure their account isn't disabled.
  298. {
  299. return null;
  300. }
  301.  
  302. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  303. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  304. groups.Add(user.Sid.Value);//also add their own SID
  305. groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
  306. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  307. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  308. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
  309. }
  310. if (ctx.ValidateCredentials(username, password))//if they give an actual username and password, we authenticate against the domain!
  311. {
  312. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
  313. string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);//generate a new token for the user
  314. if (user.Enabled != true)//make sure their account isn't disabled.
  315. {
  316. return null;//disabled account? No login!
  317. }
  318.  
  319. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  320. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
  321. groups.Add(user.Sid.Value);//also add their own SID
  322. groups.Add("Auth:Basic");//Lets me check later from APIs if they authenticated with a token or username and password.
  323. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  324. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  325. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());//Creates and returns the Principal
  326. }
  327. return null;//invalid username and password? No login!
  328. }
  329.  
  330. private IPrincipal CreatePrincipal(String username, String password)
  331. {
  332. PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
  333. if (username.ToLower() == "token")
  334. {
  335. username = TokenCache.localTokenCache.validateToken(password);
  336. if (username == null)
  337. {
  338. return null;
  339. }
  340.  
  341. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
  342. if (user.Enabled != true)
  343. {
  344. return null;
  345. }
  346.  
  347. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  348. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));
  349. groups.Add(user.Sid.Value);
  350. groups.Add("Auth:Token");
  351. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  352. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  353. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());
  354. }
  355. if (ctx.ValidateCredentials(username, password))
  356. {
  357. UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
  358. string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);
  359. if (user.Enabled != true)
  360. {
  361. return null;
  362. }
  363.  
  364. //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
  365. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));
  366. groups.Add(user.Sid.Value);
  367. groups.Add("Auth:Basic");
  368. //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
  369. //This is a convienient place to put a string that can be used by API methods later in the pipeline.
  370. return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());
  371. }
  372. return null;
  373. }
  374.  
  375. List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement