public static AuthHeaders ParseHeaders(IHeaderDictionary headers) { var result = new AuthHeaders(); if (Configuration.Security.ForcedKey != null && Configuration.Security.ForcedPlayerId != null && Configuration.Security.ForcedTribeId != null) { result.AuthToken = Configuration.Security.ForcedKey; result.PlayerId = Configuration.Security.ForcedPlayerId; result.TribeId = Configuration.Security.ForcedTribeId; result.IsSitter = false; return(result); } var combinedTokenString = headers["X-V-TOKEN"].FirstOrDefault(); combinedTokenString = String.IsNullOrWhiteSpace(combinedTokenString) ? null : combinedTokenString; if (combinedTokenString != null) { var tokenParts = combinedTokenString.Split(':'); var playerIdString = tokenParts.Length > 0 ? tokenParts[0] : null; var tribeIdString = tokenParts.Length > 1 ? tokenParts[1] : null; var authTokenString = tokenParts.Length > 2 ? tokenParts[2] : null; var sitterString = tokenParts.Length > 3 ? tokenParts[3] : null; int playerId, tribeId; if (int.TryParse(playerIdString, out playerId)) { result.PlayerId = playerId; } if (int.TryParse(tribeIdString, out tribeId)) { result.TribeId = tribeId; } bool isSitter; if (bool.TryParse(sitterString, out isSitter)) { result.IsSitter = isSitter; } else { result.IsSitter = true; } try { result.AuthToken = Guid.Parse(authTokenString); } catch { } } return(result); }
public override void OnException(ExceptionContext context) { Security.AuthHeaders auth = null; try { auth = Security.AuthenticationUtil.ParseHeaders(context.HttpContext.Request.Headers); } catch { } if (!(context.Exception is TaskCanceledException)) { String message = "Exception thrown at endpoint: {endpoint}"; if (auth != null) { message += " from request by user with token: " + auth.AuthToken; } else { message += " (auth token unavailable)"; } logger.Error(message, context.HttpContext.Request.Path.Value); } base.OnException(context); }
public override void OnActionExecuting(ActionExecutingContext context) { var failedAuthMessage = $"Say hello to our log files, Mr. or Ms. {context.HttpContext.Connection.RemoteIpAddress.ToString()}"; AuthHeaders authHeaders = null; authHeaders = AuthenticationUtil.ParseHeaders(context.HttpContext.Request.Headers); if (!authHeaders.IsValid) { var failedRequest = AuthenticationUtil.MakeFailedRecord(context.HttpContext, authHeaders); failedRequest.Reason = "Invalid authentication headers: "; var exactReasons = new List <String>(); if (authHeaders.AuthToken == null) { exactReasons.Add("AuthToken missing or invalid"); } if (authHeaders.PlayerId == null) { exactReasons.Add("PlayerId missing or invalid"); } if (authHeaders.TribeId == null) { exactReasons.Add("TribeId missing or invalid"); } failedRequest.Reason += String.Join(", ", exactReasons); dbContext.Add(failedRequest); dbContext.SaveChanges(); LogFailedRequest(failedRequest); context.Result = new ContentResult { Content = failedAuthMessage, ContentType = "text/plain", StatusCode = 401 }; return; } var requestedWorld = context.RouteData.Values["worldName"] as String; if (requestedWorld == null) { var failedRequest = AuthenticationUtil.MakeFailedRecord(context.HttpContext, authHeaders); failedRequest.Reason = "Attempted to request a protected endpoint without worldName [programmer error]"; dbContext.Add(failedRequest); dbContext.SaveChanges(); LogFailedRequest(failedRequest); context.Result = new StatusCodeResult(401); return; } var world = dbContext.World.Where(w => w.Name == requestedWorld).FirstOrDefault(); if (world == null) { var failedRequest = AuthenticationUtil.MakeFailedRecord(context.HttpContext, authHeaders); failedRequest.Reason = "Attempted to request a protected endpoint for a world that does not exist"; dbContext.Add(failedRequest); dbContext.SaveChanges(); LogFailedRequest(failedRequest); context.Result = new StatusCodeResult(401); return; } var authToken = authHeaders.AuthToken; var discoveredUser = ( from user in dbContext.User where user.AuthToken == authToken && (user.WorldId == null || user.WorldId == world.Id) select user ).FirstOrDefault(); if (discoveredUser == null || !discoveredUser.Enabled) { var failedRequest = AuthenticationUtil.MakeFailedRecord(context.HttpContext, authHeaders); if (discoveredUser == null) { failedRequest.Reason = $"No user found with given token: '{authToken}'"; context.Result = new ContentResult { Content = failedAuthMessage, ContentType = "text/plain", StatusCode = 401 }; } else { var disablingEvent = dbContext.UserLog.Where(u => u.Id == discoveredUser.Uid).OrderByDescending(l => l.TransactionTime).FirstOrDefault(); var disablingAdmin = disablingEvent?.AdminPlayerId == null ? null : dbContext.Player.Where(p => p.PlayerId == disablingEvent.AdminPlayerId.Value).FirstOrDefault(); failedRequest.Reason = "Requested by disabled user"; context.Result = new ContentResult { Content = JsonConvert.SerializeObject(new { Enabled = false, DisabledBy = disablingAdmin?.PlayerName ?? "Unknown", DisabledAt = disablingEvent?.TransactionTime }), ContentType = MediaTypeNames.Application.Json, StatusCode = 401 }; } dbContext.Add(failedRequest); dbContext.SaveChanges(); LogFailedRequest(failedRequest); return; } if (discoveredUser.PlayerId != authHeaders.PlayerId.Value) { var failedRequest = AuthenticationUtil.MakeFailedRecord(context.HttpContext, authHeaders); failedRequest.Reason = $"Player ID {authHeaders.PlayerId.Value} did not match the player ID associated with for token, got PID {discoveredUser.PlayerId}"; dbContext.Add(failedRequest); dbContext.SaveChanges(); context.Result = new ContentResult { Content = failedAuthMessage, ContentType = "text/plain", StatusCode = 401 }; return; } if (discoveredUser.PermissionsLevel < Configuration.Security.MinimumRequiredPriveleges) { var failedRequest = AuthenticationUtil.MakeFailedRecord(context.HttpContext, authHeaders); failedRequest.Reason = $"User privileges '{discoveredUser.PermissionsLevel}' was less than the minimum '{Configuration.Security.MinimumRequiredPriveleges}'"; dbContext.Add(failedRequest); dbContext.SaveChanges(); context.Result = new ContentResult { Content = failedAuthMessage, ContentType = "text/plain", StatusCode = 401 }; return; } context.HttpContext.Items["UserId"] = discoveredUser.Uid; context.HttpContext.Items["UserIsSitter"] = authHeaders.IsSitter; context.HttpContext.Items["UserPermissions"] = authHeaders.IsSitter && Configuration.Security.RestrictSitterAccess ? (short)PermissionLevel.Default : discoveredUser.PermissionsLevel; context.HttpContext.Items["PlayerId"] = authHeaders.PlayerId.Value; context.HttpContext.Items["TribeId"] = authHeaders.TribeId.Value; context.HttpContext.Items["AuthToken"] = authHeaders.AuthToken.Value; context.HttpContext.Items["AccessGroupId"] = discoveredUser.AccessGroupId; context.HttpContext.Items["User"] = discoveredUser; }
public static Scaffold.FailedAuthorizationRecord MakeFailedRecord(HttpContext httpContext, AuthHeaders headers) { var ip = httpContext.Connection.RemoteIpAddress; return(new Scaffold.FailedAuthorizationRecord { Ip = ip, OccurredAt = DateTime.UtcNow, PlayerId = headers?.PlayerId, TribeId = headers?.TribeId, RequestedEndpoint = httpContext.Request.Path.Value }); }