Question

This might seem like a basic question and back to Http protocol 101. But I am having difficulty in understanding how Basic Authentication works. I am implementing a windows service and need it to be secure. I would like to obtain the user name and password and authenticate the user to a custom user store. I also want to minimize the number of login calls, as a login call represents a call to our SQL server. What I have started so far is something like this:

The way I see it the UserAuthorized function has to make my custom login call. But, I don't want to have to do that every single time. Does basic authentication maintain if you are logged in, or is there a caching thread safe solution that I should explore.

Oh yeah I'd also like to make it so that when a user is authenticate and object is created and maintained in the thread for the listener to refer to on subsequent callbacks for a user/connection. But since ListenerCallback is static I'm not sure how this can be accomplished.

Thanks in advance for any help, I truly appreciate it and StackOverflow.

public void ThreadProc() {
    string uriPrefix = ConfigurationManager.AppSettings["ListenerPrefix"];
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add(uriPrefix);
    listener.AuthenticationSchemes = AuthenticationSchemes.Basic;

    listener.Start();

    Console.WriteLine("Start listening on " + uriPrefix);
    Console.WriteLine("Press Control-C to stop listener...");

    while (listening) {
        IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
        result.AsyncWaitHandle.WaitOne();
    }
}

public static void ListenerCallback(IAsyncResult result) {
    HttpListener listener = (HttpListener)result.AsyncState;
    HttpListenerContext context = listener.EndGetContext(result);
    WebDavEngine engine = new WebDavEngine(context.User);

    context.Response.SendChunked = false;
    FileLogger.Level = LogLevel.Debug;

    engine.IgnoreExceptions = false;

    if (UserAutorized(context)) {
        try {
            engine.Run(context, listener.Prefixes);
            engine.CommitTransaction();
        } catch {
            engine.RollBackTransaction();
        } finally {
            engine.CloseConnection();
        }
    } else
        context.Response.StatusCode = 401;

    if (context.Response.StatusCode == 401)
        ShowLoginDialog(context, context.Response);

    try {
        context.Response.Close();
    } catch {
        // client closed connection before the content was sent
    }
}

private static bool UserAutorized(HttpListenerContext context) {
    HttpListenerBasicIdentity identity = (HttpListenerBasicIdentity)context.User.Identity;

    if (!identity.IsAuthenticated) {
        string username = identity.Name;

        // workaround for Windows Vista Basic authentication. User name may be submitted in the following format: Machine\User.
        int ind = username.LastIndexOf('\\');
        if (ind > 0)
            username = username.Remove(0, ind + 1);


        Console.WriteLine("Trying Authentication since identity is NOT authenticated");

        return false;
    } else {
        Console.WriteLine("identity.IsAuthenticated: " + identity.IsAuthenticated.ToString());
        return identity.IsAuthenticated;
    }            
}

EDIT: +1 for the document alone, that really opened my eyes to the caparison of authentication schemes and how they work. Unless I a readying this wrong, it does appear that a Digest scheme might be able to maintain a "session" or at least an expiration to retry my custom authentication.

Was it helpful?

Solution 2

Thanks for the spec, I appreciated it. I did manage to solve my issue and it was not spec related but rather a design/hosting issue.

OTHER TIPS

HTTP Basic requires the login credentials with every request. HTTP doesn't have any concept of session, so you can't really tell if someone is "already logged on".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top