6/23/18

Xamarin Android WebView Authentication

The WebView browser component is commonly used to render web content within a native application layout. When the content is secured, it is required for the app to authenticate with the Web server first.  When using the WebView component, we can leverage the component events (HTTP pipeline) to detect a challenge-response authentication event from the server and automatically login our app.

Challenge Response Security



The challenge-response interaction is a security protocol (HTTP 401) event in which a server challenges the identity of a client, and the browser responds with the security credentials required to access the content. If the required credentials are not validated, the content is forbidden to the app. We can leverage this interaction to send the impersonating identity to the server by extending the WebViewClient class and overriding the authentication event. Let’s take a look.

Extending the WebViewClient Class

In order to write a handler for the challenge-response event, we need to extend the WebViewClient class. We start by implementing a constructor that can take the credential information. This enables the activity that instantiates our class to manage the credential information and just pass it to our class during the class instantiation.


internal class AuthWebViewClient : WebViewClient
{
    public string Username { get; }
    public string Password { get; }
    private int LoginCount = 0;
    
    /// <summary>
    /// gets the user credentials for the impersonation process
    /// </summary>
    /// <param name="username"></param>
    /// <param name="password"></param>
    public AuthWebViewClient(string username, string password)
    {
        Username = username;
        Password = password;          
    }
    
    /// <summary>
    /// handles the authentication with the website.
    /// </summary>
    /// <param name="view"></param>
    /// <param name="handler"></param>
    /// <param name="host"></param>
    /// <param name="realm"></param>
    /// <remarks>
    /// </remarks>
    public override void OnReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, string host, string realm)
    {
        try
        {
            if (LoginCount < 3)
            {
                LoginCount++;
                handler.Proceed(Username, Password);
            }
            else
            {
                LoginCount = 0;
                handler.Cancel();
            }
        }
        catch (Exception ex)
        {
            Toast.MakeText(Application.Context, ex.Message, ToastLength.Long).Show();
        }
    }      
}


Handling the Authentication

When we extend the WebViewClient class, we can override some of the class events. For the authentication pipeline, we override the OnReceivedHttpAuthRequest event which provides a reference to the HttpAuthHandler object. This object provides the Proceed method which we use to send the login credentials to the server.

One important area to note here is that if there is a problem with the credentials that we send to the server, the HTTP 401 event will continue to be sent back from the server. This can create a loop between the browser and server. To prevent this, we track the number of attempts, and cancel the authentication when the limit is met. This is done by using the Cancel method on the HttpAuthHandler object.

Please note that this simple approach to pass the username and password information from the browser to the server. There are still other securities areas to be concerned with like encrypting the communication channel to protect the security credentials from unwanted traces.


Thanks for reading.

Originally published by ozkary.com

6/2/18

Xamarin Android Class Not Found Exception

The Class Not Found Exception is commonly raised when the class loader tries to find an activity or a broadcast receiver class listed on the app manifest, but it fails to find it. Common examples can be a splash activity with no layout to show an animation, or a broadcast receiver which should load after intent is received, like boot completed intent.

What is common on these cases is that these classes should be configured on the AndroidManifest.xml file as part of the build process, but during the application load lifecycle, these classes are not found. This indicates that there is missing metadata which affects the load process. Let’s review a common application manifest and class declaration and discuss the problem and solution.


AndroidManifest


<manifest package="com.ozkary.app"
<receiver       
        android:name=".BootReceiver"    
<intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />  
</intent-filter>

</receiver>
</manifest>


On the abbreviated manifest above, we can find the package name and the receiver class.  The receiver class name is relative to the package name which means that during the load time, the class loader will attempt to find a class with the name of com.ozkary.app.BootReceiver.

When the class not found exception is raised, we need to take a look at how our project metadata is getting created. This is where our class attributes become very important for our builds.


Class Metadata with Attributes

During the class implementation phase, we can leverage class attributes to add metadata information to our projects. For a Xamarin Android project, this is very important because this is the metadata that is added to the AndroidManifest file during the build cycle. With that knowledge in mind, let’s take a look at how we should properly declare our class.


[BroadcastReceiver(Name = "com.ozkary.BootReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver


By looking at our abbreviated class declaration, we are setting the receiver class name properly as well as the intent. When we build the project, the metadata generated from our classes is merged with the Properties/AndroidManifest.xml file.  This is true for all classes including activities.

When encountering this Class Not Found Exception, we should review the content of the manifest file as well our class declarations, and we should find that there is probably not enough metadata added to the classes to prevent this error.


I hope this helps some of you with this problem.

Originally published by ozkary.com