Change server variable values that are logged in Elmah - c#

I configured Elmah in my application and when I looked at the error logs I saw that in the User section Elmah logged an ID instead of the current logged in username a shown below.
I was wondering if there is a place where I can change how the values of these server variables are set so I can put say an email or proper username in the Auth_User variable..Looking at Elmah documentation I was only able to figure out how to filter out Error logging but not actually how to update server variable values before logging.

I've written a blog post about exactly that: Enrich ELMAH errors using error filtering hook.
To summarize, use ELMAH's error filtering to overwrite the message logged to ELMAH.
In Global.asax.cs add the following code:
void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs args)
{
var httpContext = args.Context as HttpContext;
if (httpContext != null)
{
var error = new Error(args.Exception, httpContext);
error.User = GetUserFromDatabase();
ErrorLog.GetDefault(httpContext).Log(error);
args.Dismiss();
}
}
How you implement the line where you set the User property on error will be up to your application. But the code will let you set something like the user's name, username, or email.

Related

Username is not accessible on SessionLogoff and even sometime in SessionUnlock

I am writing a Windows Service(using C#, WCF) that is intended to record Windows user's session event and post it to some other WCF Service.
Below code sometimes works as expected but not always. It returns empty mostly in SessionUnlock, SessionLogoff events.
var usernmae = Machine.getInstance().getUsername();
The above code-line is used inside a utility function which is being called from OnSessionChange event of Windows Service as below: -
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
var sessionDetails = sessionLogger.BuildSessionDetails(changeDescription);
....
}
and that BuildSessionDetails function is like: -
public class SessionLogger : ISessionLogger
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public SessionDetails BuildSessionDetails(SessionChangeDescription changeDescription)
{
SessionDetails sd = new SessionDetails();
sd.ChangeTime = DateTime.Now.ToUniversalTime();
sd.SessionId = changeDescription.SessionId.ToString();
sd.ChangeType = changeDescription.Reason.ToString();
//This is where I am EXTRACTING USERNAME
sd.Username = Machine.getInstance().getUsername();
...
...
}
}
The expected result is username all time whenever the session event happens.
Any idea what is happening or causing here to not return the username always?
Your code gets the UserName property from the Win32_ComputerSystem class. The documentation on that variable says:
Name of a user that is logged on currently. This property must have a value. In a terminal services session, UserName returns the name of the user that is logged on to the console not the user logged on during the terminal service session.
Is that your intention?
You seem to consider this code to be a suitable alternative:
userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
But that will always return the name of the user specified on your service's "Log On" tab — probably not what you want.
Exactly which "user" are you trying to get?
Edit based on comments:
To get the user name associated with the session that was changed:
In OnSessionChange(), get the sessionID value from the SessionChangeDescription parameter.
Use the sessionID in a call to the WTSQuerySessionInformation function with the WTSUserName value to get the user name associated with the session.
That should work in all occasions except when a user has logged off (because the session will no longer be available to query). If that is an issue, you can work around that problem by:
Introducing a sessionID-to-username map in your application
Populating the map by enumerating all active sessions when your service starts
Adding to the map whenever you receive a logon event
Removing from the map (by sessionID) whenever there is a logoff event

How do I secure my web service apart from checking session variable for NULL?

I have written a webservice that basically inserts data into the central database and is expected to be consumed by multiple clients from multiple systems.
It works but the problem is that it can be accessed by anyone hence making it vulnerable to be used by anybody i.e. anybody can spam by entering data or anything.
One way is to check for the Session variable but how would I know the name of the session variable of the client consuming the system or may be he's not authenticating that way?
So what should I do to make it secure?
[WebMethod(EnableSession= true)]
public int InsertEngineeringData(string FunctionalLocation, string EqptType, string WINFileNo, string ComponentTagNo)
{
try
{
if (Session["User"] != null)
{
}
int EngineeringDataID = 0;
EngineeringDataDAL EngineeringDataDAL = new Vail_PlantWebApi.EngineeringDataDAL();
EngineeringDataID = EngineeringDataDAL.InsertEngineeringData(FunctionalLocation, EqptType, WINFileNo, ComponentTagNo);
return EngineeringDataID;
}
catch (Exception ex)
{
throw ex;
}
}
If it is an asmx webservice, then use the link Crocoder posted or another quick way if it works is you can try the [Authorize] attribute although I'm not sure if that will work with an inline webmethod you're using, I've only seen it used in WebAPI. Authorize attribute in ASP.NET MVC
A more robust way that would definitely work is you add a column to the Users table called 'CurrentSessionID' and another one that says 'LastLoginDateStamp' For each login request if you have a valid user you update their session there and a datestamp. Then when the user hits the api, you compare the session and make sure it hasn't exceeded what you decide is a valid threshold for the last login, maybe 24 hours for example.
There would be a lot more work to do after that, but that's the basic idea.

getting authorization code from url

When using oauth I can get an authorization code returned in the URL to me but i don't know how to get that code out of the url. For example when i give the app permission to run i get
http://localhost/?code=moBOuHmeCj.KUjTq14iwVyywiLbB44SNZ4-olDb2uFmXOwPpFzV.PQUHfFCNKAqStMp8.NMDZPjEZMJosDMC0JKZip.qHTvQ5KHI9oFIGwNh79EabwklUQjVgXzrc4Mor6mcmMRVTJTos3mv2BzIEw%3D%3D
as a response but i need to get that out of the browser and back to the server to get the long access key.How do i do this?
Set your authentication provider's returnUrl as a specific route of your site, something like http://localhost/oauth
In your OAuthController (I'm assuming your question is about a MVC app) use:
public ActionResult Index(string code)
{
// Perform any action related with 'code' value provided by auth provider.
}
Please try this code:
$code = $_GET['code'];

How to force logout user when his/her username is changed by another user?

In my application I am using Forms-Authentication to sign in and sign out users.
One functionality is admin can change the username of other users. In that case, I need to sign out the user whose username is changed.
If I do not, due to their cookies set before, they gain access to application and receive error messages (since their username does not exist and there are parts where I use their username for some functionality).
How can I force these users to log out using Forms-Authentication ?
UPDATE :
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controller = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString(); ;
// Below returns the previous username, which does not exist anymore in db.
string userName = HttpContext.Current.User.Identity.Name;
UnitOfWork unitOfWork = new UnitOfWork();
if (!unitOfWork.UserRepository.UserExists(userName))
{
FormsAuthentication.SignOut();
filterContext.HttpContext.Session.Clear();
filterContext.HttpContext.Session.Abandon();
// I am not using Roles.
}
unitOfWork.Dispose();
base.OnActionExecuting(filterContext);
}
In my customer global filter, I check whether user exist or not, if not I sign them out. However, it is not working. By working I mean they pass the authentication and gain access to application.
Thanks in advance.
Here's what you do to force user to sign out:
public void UserPasswordChangedHandler()
{
FormsAuthentication.SignOut();
Roles.DeleteCookie();
Session.Clear();
}
I don't think line by line explanation required, its self explanatory enough.
Please let me know if I am mistaken.
Update
Straightforward answer to your additional question is to keep per user boolean tracking if his data was updated by admin and if yes - just redirect him to login page.
Please see following articles for forced logout using forms authentication information:
How can I force a user to log out
How can I force a log out of all users for a website,
ASP.NET forms authentication forced logout
How to log off multiple MembershipUsers that are not the current user
Update 2
Clearing cookies
HowTo: create and remove Cookies with ASP.NET MVC
How do you clear cookies in ASP NET MVC 3 and C#
How do I invalidate a bad authentication cookie
Hope this help you.
When a user needs to become invalidated you must add their details to some kind of internal static list.
Then on every page request (possibly using Application_BeginRequest) see if that current user is in that list, and if so to call FormsAuthentication.SignOut there-and-then.
It seems like a bit of a hack, but it's the best I can think of right now.
Note that removing a user-in-absentia's session state is another issue entirely.

Sitecore 500 Error Logging / Alerts

Problem
Currently, I'm looking to serve a custom 500 error page as well as log and alert a web master about the condition that was hit (What URL, stack trace, timestamp, etc.).
I tried defined custom http errors under system configuration, but the error pages were not hit.
I am able to handle 404s and their related errors (layoutnotfound).
Question
Should I intercept the context in global.asax to handle the 500 errors and return a custom page? Is there another way with Sitecore to achieve what I'm looking for?
Mainly, I'm looking for best practice of logging / alerts for 500 errors with Sitecore
Try using ELMAH.
Here is an article on using it with Sitecore.
Elmah is great and does a good job. You can also use log4net to log exceptions. All you do is add an application_error method in global.asax and you can track all the errors that occur. You can also add different appenders and can log messages in a log file, database and email them.
Here is the code that logs the error and includes some additional information like url and Current sitecore item:
private static readonly ILog log = LogManager.GetLogger(typeof(Global));
protected void Application_Error(object sender, EventArgs e)
{
if (Context != null)
{
Exception error = Context.Server.GetLastError().GetBaseException();
log.Fatal(
GetErrorMessage(), error);
}
}
private string GetErrorMessage()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("Application_Error: Unhandled exception has been occured.");
try
{
sb.AppendLine("Current Request: " + Context.Request.RawUrl);
Sitecore.Data.Items.Item currentItem = Sitecore.Context.Item;
if (currentItem != null)
sb.AppendLine(String.Format("Current Item ({0}): {1}", currentItem.ID, currentItem.Paths.FullPath));
if (Sitecore.Context.Database != null)
sb.AppendLine("Current Database: " + Sitecore.Context.Database.Name);
}
catch { } // in no way should we prevent the site from logging the error
return sb.ToString();
}
If you want an easy solution I would recommend going with Elmah. If you want to have more control and more logging options you should go with a custom log4net solution.
I tried defined custom http errors
under system configuration, but the
error pages were not hit. I am able to
handle 404s and their related errors
(layoutnotfound).
On that particular point...Be aware that custom errors behave differently when accessed locally. Also, by default you need to use physical files (not sitecore pages) for these pages. You need be aware of IIS behaviour when returning status codes over 200 and how it is dependant on the configuration within web.config and (if running in integrated mode) the section. In particular, see the flow chart half way down the first link below.
http://learn.iis.net/page.aspx/267/how-to-use-http-detailed-errors-in-iis-70/
http://www.iis.net/ConfigReference/system.webServer/httpErrors
http://msdn.microsoft.com/en-us/library/ms689487(v=VS.90).aspx
You might also want to change the RequestErrors.UseServerSideRedirect setting to "true" to provide better http responses without redirects.

Categories

Resources