Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Web;
- using System.Net.Http;
- using System.Net.Http.Headers;
- using System.Security.Principal;
- using System.Threading;
- using System.DirectoryServices.AccountManagement;
- namespace MyApp.Security
- {
- public class BasicAuthMessageHandler : DelegatingHandler
- {
- protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- AuthenticationHeaderValue authValue = request.Headers.Authorization;
- if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter))
- {
- string username = null;
- string password = null;
- string toSplit = Encoding.UTF8.GetString(Convert.FromBase64String(authValue.Parameter));
- int index;
- if ((index = toSplit.IndexOf(":")) != -1)//verifies that they included at least the : between the username and password
- {
- username = toSplit.Substring(0, index);
- password = toSplit.Substring(index + 1);
- }
- //makes sure that there IS some semblance of a username and password. Blanks aren't allowed.
- if ( !string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
- {
- IPrincipal currentPrincipal = CreatePrincipal(username, password);//Validates the credentials and creates a principal containing their domain groups
- Thread.CurrentPrincipal = currentPrincipal;//sets the principal for the thread
- HttpContext.Current.User = currentPrincipal;//sets the principal for the HttpContext
- }
- }
- return base.SendAsync(request, cancellationToken);
- }
- private IPrincipal CreatePrincipal(String username, String password)
- {
- PrincipalContext ctx = new PrincipalContext(ContextType.Domain);//Sets up a context for the domain the app is running in
- if (username.ToLower() == "token")//special case where the username is "token" means we're using token authentication instead of normal basic authentication
- {
- username = TokenCache.localTokenCache.validateToken(password);//checks for presence of the token in the cache and grabs the username associated with it if any.
- if (username == null)
- {
- return null;//No token? No login!
- }
- else
- {
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
- if (user.Enabled == true)//make sure their account isn't disabled.
- {
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
- }
- else
- {
- return null;//disabled account? No login!
- }
- }
- }
- if (ctx.ValidateCredentials(username, password))//if they give an actual username and password, we authenticate against the domain!
- {
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
- string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);//generate a new token for the user
- if (user.Enabled == true)//make sure their account isn't disabled.
- {
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Basic");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());//Creates and returns the Principal
- }
- else
- {
- return null;//disabled account? No login!
- }
- }
- return null;//invalid username and password? No login!
- }
- }
- }
- using System;
- using System.Security.Cryptography;
- using System.Collections.Generic;
- namespace MyApp.Security
- {
- class TokenCache : IDisposable
- {
- public static readonly TokenCache localTokenCache = new TokenCache(new TimeSpan(20,0,0));//Singleton where tokens expire after 20 hours
- private Dictionary<string, string> userToToken = new Dictionary<string, string>();
- private Dictionary<string, string> tokenToUser = new Dictionary<string, string>();
- private Dictionary<string, DateTime> tokenToDate = new Dictionary<string, DateTime>();
- private RNGCryptoServiceProvider numgen;
- private TimeSpan _maxValidity;
- private TokenCache(TimeSpan maxValidity)
- {
- _maxValidity = maxValidity;
- numgen = new RNGCryptoServiceProvider();
- }
- public string validateToken(string token)
- {
- if (tokenToUser.ContainsKey(token) && DateTime.Now - tokenToDate[token] < _maxValidity)//do we have the token, and is it unexpired?
- {
- return tokenToUser[token];//Yes? Return username.
- }else
- {
- return null;//No? Then return null;
- }
- }
- public string generateNewToken(string username)
- {
- byte[] tokenarr = new byte[33];
- numgen.GetBytes(tokenarr);
- string token = SimpleMethods.Base642URL(Convert.ToBase64String(tokenarr));//Makes a URL friendly token
- DateTime createdon = DateTime.Now;
- removePreviousTokens(username, service);
- tokenToUser.Add(token, username);
- userToToken.Add(username, token);
- tokenToDate.Add(token, createdon);
- return token;
- }
- private void removePreviousTokens(string username)
- {
- if(userToToken.ContainsKey(username))
- {
- string token = userToToken[username];
- tokenToUser.Remove(token);
- userToToken.Remove(username);
- tokenToDate.Remove(token);
- }
- }
- #region IDisposable Support
- private bool disposedValue = false; // To detect redundant calls
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- numgen.Dispose();
- }
- tokenToDate = null;
- tokenToUser = null;
- userToToken = null;
- disposedValue = true;
- }
- }
- public void Dispose()
- {
- Dispose(true);
- }
- #endregion
- }
- }
- public static string Base642URL(string base64String)
- {
- base64String = base64String.Replace("+", "-");
- base64String = base64String.Replace("/", "_");
- base64String = base64String.Replace("=", "");
- return base64String;
- }
- public static string Base642URL(string base64String)
- {
- base64String = base64String.Replace("+", "-");
- base64String = base64String.Replace("/", "_");
- base64String = base64String.Replace("=", "");
- return base64String;
- }
- public static class StringExtensions
- {
- public static string Base642URL(this string base64String)
- {
- base64String = base64String.Replace("+", "-");
- base64String = base64String.Replace("/", "_");
- base64String = base64String.Replace("=", "");
- return base64String;
- }
- }
- private IPrincipal CreatePrincipal(String username, String password)
- {
- PrincipalContext ctx = new PrincipalContext(ContextType.Domain);//Sets up a context for the domain the app is running in
- if (username.ToLower() == "token")//special case where the username is "token" means we're using token authentication instead of normal basic authentication
- {
- username = TokenCache.localTokenCache.validateToken(password);//checks for presence of the token in the cache and grabs the username associated with it if any.
- if (username == null)
- {
- return null;//No token? No login!
- }
- else
- {
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
- if (user.Enabled == true)//make sure their account isn't disabled.
- {
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
- }
- else
- {
- return null;//disabled account? No login!
- }
- }
- }
- if (ctx.ValidateCredentials(username, password))//if they give an actual username and password, we authenticate against the domain!
- {
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
- string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);//generate a new token for the user
- if (user.Enabled == true)//make sure their account isn't disabled.
- {
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Basic");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());//Creates and returns the Principal
- }
- else
- {
- return null;//disabled account? No login!
- }
- }
- return null;//invalid username and password? No login!
- }
- if (username == null)
- {
- return null;//No token? No login!
- }
- else
- {
- if (username == null)
- {
- return null;
- }
- // Just continue with the code
- if (user.Enabled == true)//make sure their account isn't disabled.
- {
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
- }
- else
- {
- return null;//disabled account? No login!
- }
- if (user.Enabled != true) // Not the same as `== false`
- {
- return null;
- }
- // Continue with the code
- private IPrincipal CreatePrincipal(String username, String password)
- {
- PrincipalContext ctx = new PrincipalContext(ContextType.Domain);//Sets up a context for the domain the app is running in
- if (username.ToLower() == "token")//special case where the username is "token" means we're using token authentication instead of normal basic authentication
- {
- username = TokenCache.localTokenCache.validateToken(password);//checks for presence of the token in the cache and grabs the username associated with it if any.
- if (username == null)
- {
- return null;//No token? No login!
- }
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
- if (user.Enabled != true)//make sure their account isn't disabled.
- {
- return null;
- }
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Token");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());//Creates and returns the Principal
- }
- if (ctx.ValidateCredentials(username, password))//if they give an actual username and password, we authenticate against the domain!
- {
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);//Grab the necessary information about the user from the domain.
- string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);//generate a new token for the user
- if (user.Enabled != true)//make sure their account isn't disabled.
- {
- return null;//disabled account? No login!
- }
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));//grab the SIDs from any groups they're in
- groups.Add(user.Sid.Value);//also add their own SID
- groups.Add("Auth:Basic");//Lets me check later from APIs if they authenticated with a token or username and password.
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());//Creates and returns the Principal
- }
- return null;//invalid username and password? No login!
- }
- private IPrincipal CreatePrincipal(String username, String password)
- {
- PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
- if (username.ToLower() == "token")
- {
- username = TokenCache.localTokenCache.validateToken(password);
- if (username == null)
- {
- return null;
- }
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
- if (user.Enabled != true)
- {
- return null;
- }
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));
- groups.Add(user.Sid.Value);
- groups.Add("Auth:Token");
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, ""), groups.ToArray());
- }
- if (ctx.ValidateCredentials(username, password))
- {
- UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
- string token = TokenCache.localTokenCache.generateNewToken(user.SamAccountName);
- if (user.Enabled != true)
- {
- return null;
- }
- //SIDs can be used to check NTFS file access permissions before doing an operation on behalf of the user.
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));
- groups.Add(user.Sid.Value);
- groups.Add("Auth:Basic");
- //Note that here I'm using the "Authentication Type" part of generic identity to store the token if I make one.
- //This is a convienient place to put a string that can be used by API methods later in the pipeline.
- return new GenericPrincipal(new GenericIdentity(user.SamAccountName, token), groups.ToArray());
- }
- return null;
- }
- List<string> groups = new List<string>(user.GetAuthorizationGroups().Select(i => i.Sid.Value));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement