Thursday, May 5, 2016

Custom authenication in QlikView Server (NTLM)

It's all about externalizing the user validation.

  • Some kind of username mapping (other system --> QlikView) is required.
  • Works on any Server edition (Small Business Edition and EE).
  • Document access is based on NTFS rights.
  • Every user must be given rights for every document. 
  • It should be easier and more flexible on Enterprise Edition by activating DMS.
  • Also easier with per session licensing (7x more expensive).
  • IIS required (it doesn't work with QVS).
Installation
  • Install IIS.
  • Install QlikView server with IIS-QV Tunneling.
  • Set anonymous authentication on the IIS administrator for QlikView and QvAjaxZfc.
  • On QMC System -> Setup -> QVW -> Authentication set:
    • Authentication: Always
    • Type: Ntlm
    • Login Address: Default login page
  • Edit C:\Program Files\QlikView\Server\QlikViewClients\QlikViewAjax\Authenticathe.aspx
Authenticate.aspx content

<%@ Import Namespace="QlikView.AccessPoint" %>
<%@ Import Namespace="QlikView.AccessPoint.HttpInterfaces" %>
<%@ Import Namespace="QvIISWebServer" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Collections.Generic"%>
<%@ Page Language="C#" AutoEventWireup="true" %>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e) {
        Response.Clear();
        Context context = this.GetContext();
        
        // Saving the Basic authentication header to a string ("Basic UserName:Password")
        string auth = Request.Headers["Authorization"];
        
        bool valid = false;
        string userName = "";            
        if (auth != null && auth.IndexOf("Basic ") == 0)
        {
            // Removing "Basic " from the string and decoding the username and password
            string unameColonPwd = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(auth.Substring(6)));
            int colonPos = unameColonPwd.IndexOf(':');
            if (colonPos >= 0)
            {
                // Splitting username:password into two seperate strings
                userName = unameColonPwd.Substring(0, colonPos);
                string pwd = unameColonPwd.Substring(colonPos + 1);
                
                // *** IMPLEMENT THIS FUNCTION WITH YOUR OWN USER VALIDATION 
                valid = checkCredentials(userName, pwd);
            }
        }            
        
        if(valid)
        {

            // *** IMPLEMENT THIS FUNCTION WITH YOUR OWN USER MAPPING
            userName = "DOMAIN\\" + mapUserName(userName);

            // *** IMPLEMENT THIS FUNCTION TO SET THE USER GROUPS
            // You can also return null on NTFS 
            List<string> groups = getUserGroups(userName);

            // Creating an user object with groups
            IUser user = new NamedUser(userName, groups, true);
            // Associate the IUser with the session cookie and either redirect or sent back a status code
            QlikView.AccessPoint.User.GenericAuthentication(context, user);
            //Stop now so we don't issue a new BASIC challenge                                
            
            /*
            YOU CAN USE THIS HELPER FUNCTION INSTEAD GenericAuthentication WHEN THE NT USER PASSWORD IS KNOWN
            IUser user = QlikView.AccessPoint.User.TryLogon("DOMAIN\\user", "pwd"); 
            */
        }
        else
        {
            Context.Response.StatusCode=401;
            Context.Response.AppendHeader("WWW-Authenticate","Basic realm=\"QlikView\"");
        }

        return;
    }
</script>

Internet references

No comments:

Post a Comment