Search This Blog

Monday, September 26, 2016

How to skip the logon dialog when debugging or testing an XAF app with the security system enabled

Sometimes during active development, you may find yourself in front of the logon form entering user credentials again and again, and it may eventually become boring. This simple to implement tip will not only save you development time, but also irritation. I wanted to highlight this technique for everyone here after assisting my colleague in this SC ticket + because another customer also found this solution helpful. Since, I also remembered that we have been using a similar thing internally for the installation tests of our demos, I think it is definitely time to let the rest of the world know about this as well.



Steps to implement


1. The instructions below imply that you have already created an XAF WinForms or Web app with the Security module, and its SecurityStrategyComplex and AuthenticationStandard components either using the Solution Wizard or manually. You likely also created predefined users and roles in code or using the application UI at runtime. Consult with the XAF online documentation for more details.


2. In the YourSolutionName.Wxx project, add the following class:

using DevExpress.ExpressApp;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp.Security;

namespace YourSolutionName.Wxx {
    public class AuthenticationStandardForDebug : AuthenticationStandard {
        private static CriteriaOperator DebugUserCriteria = CriteriaOperator.Parse("UserName = ?", "Sam");
        public override bool AskLogonParametersViaUI { get { return false; } }
        public override object Authenticate(IObjectSpace objectSpace) {
            return objectSpace.FindObject(UserType, DebugUserCriteria);
        }
    }
}

Optionally, correct the DebugUserCriteria to return a single security user you would like to use for testing by default. For instance, I used Sam in our MainDemo app.

3. In the YourSolutionName.Win/Program.cs or YourSolutioName.Web/Global.asax.cs files, locate the two lines that call the Setup and Start methods for your XafApplication object and insert the next code in front of them:


#if DEBUG
((SecurityStrategyComplex)yourXafApplication.Security).Authentication = new AuthenticationStandardForDebug();
#endif

For instance, the modified code in our MainDemo.Win/Program.cs file will look as follows:
...
#if DEBUG
                ((SecurityStrategyComplex)winApplication.Security).Authentication = new AuthenticationStandardForDebug();
#endif
                winApplication.Setup();
                winApplication.Start();
...

In short, we are overriding the default AuthenticationStandard component behavior by telling it not to display the logon form + use our predefined user for the authentication procedure only when your XAF solution is built under the Debug configuration. This technique is very powerful and allows you perform various tasks related to user authentication in XAF. For instance, our customers used the same API to automatically login into the app by a URL containing user credentials in the request string or by running an app from a command line with some secret parameter. You can learn more about this API from the online XAF docs at https://search.devexpress.com/?q=authe-nticationstandard&m=Documentation

Make a note that I prefer the explicit #if DEBUG pre-compiler directive over the System.Diagnostics.Debugger.IsAttached call because of better security. The first method physically removes this test code from the Release configuration, while the second method leaves a very small hole. The issue is that a skilled end-user can potentially run your executable under Visual Studio or external debugger and thus get access to your app without entering any user credentials.

6 comments:

  1. Thank you! Implemented right away!

    #if DEBUG is also better because you may eventually want to start without debugging from Visual Studio.

    ReplyDelete
    Replies
    1. Good point, Erik, thanks. I am happy to hear that you find this tip helpful.

      Delete
  2. I have handled it with different way but certainly your way is better. Thanks for the tip Dennis...

    ReplyDelete
  3. I've used this technique but added a check for the presence and name of user to the config file - something like:

    string autoUserName = System.Configuration.ConfigurationManager.AppSettings.Get("AutomaticalDebugUser");

    ReplyDelete