Capturing Username from Windows AD

19142
10
11-09-2015 02:09 PM
KDeVogelaere
Occasional Contributor

I have often wondered how to capture the usernames of visitors to an ArcGIS JS custom built web map accessible only to employees within my organization without requesting an ID and password at login. Can this be done with the following setup?

Windows Server 2008 R2

IIS 7.0

ArcGIS JS API v. 3.14

ArcGIS Web Adaptor 10.2.2

ArcGIS Server 10.2.2

User Store: Windows Domain

Role Store: ArcGIS Server Built-in

Authentication Tier: Web

Authentication Mode: Web

Access to the web map is managed through Windows Active Directory groups.

ArcGIS API for JavaScript  GIS  Web GIS

Best Regards,

KD

0 Kudos
10 Replies
by Anonymous User
Not applicable

It can be done server side. I don't know if this is the most elegant solution but it's worked great for me. I use a PHP script called from my javascript site when certain events happen (like when the map loads).

PHP:

<?php
$referred = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
if( strpos( $referred, 'www.yourdomain.com' ) !== 0 ) {
     die( "Do not call this script manually or from an external source." );
}
$authUser = $_SERVER['AUTH_USER'];

echo $authUser;
?>

JavaScript:

 request.post("pathToCode/getUser.php").then(function(data) {
     // Username from "echo" statement above is printed here
     console.log(data)
});

I think you'll just need to make sure there's a PHP MIME type enabled in IIS (I am amateur with IIS so I might have just butchered the concept of what I'm trying to say...)

KDeVogelaere
Occasional Contributor

Thanks Sarah for sharing this is possible, this is very helpful   Unfortunately at this time PHP/JQuery are not installed on this Windows server. I wonder if this can be rewritten using a Python or ASP script called from Javascript. 

I haven't tested this but classic ASP appears to have a similar method for returning AUTH_USER,

<% response.write "AUTH_USER: " & Request.ServerVariables("AUTH_USER") %>

0 Kudos
by Anonymous User
Not applicable

I bet you could do it with ASP much the same, especially seeing as you found the AUTH_USER object. Unfortunately I have no experience with it 😕

I vaguely recall having to go through the process of installing PHP on our server and it took a bit of Googling. If you have access to the server you might look for some technical articles on doing the installation yourself. If I find the resources I used I will post them.

by Anonymous User
Not applicable
JoshHevenor
Occasional Contributor II

This is a little hacky but doesn't require the server side.  Won't work if you're using windows authentication on IIS /  auto-login. It needs the signIn window.

// requires "esri/IdentityManager","dojo/aspect"
// When a signIn window is shown
IdentityManager.on("dialog-create", function(){    
    // reference to dialog
    var dlg = this.dialog;   
    
    var getUser = function(){       
        var username = dlg.txtUser_.get('value');                
        // ...        
    };

    // Listen for submit and grab username before the dialog is destroyed
    aspect.before(dlg, "execute_", getUser);
    aspect.before(dlg.btnSubmit_, "onClick", getUser);
});
KDeVogelaere
Occasional Contributor

Thanks Josh for contributing your solution, I need to take a closer look at esri/IdentityManager to understand how it's used in web apps, could you explain what this does or could you recommend any resource guides for this?

0 Kudos
JoshHevenor
Occasional Contributor II

The API docs on the IdentityManager detail the event I used. There are some  samples that get into some detail.  See the LocalStorage sample.

The snip I posted adds a listener on the sign-in window for when the submit button is clicked, then reads the username out of the textbox on the form.  I just used the chrome debug tools to inspect the form elements.

KDeVogelaere
Occasional Contributor

Thanks everyone for your comments, here is the JavaScript/Asp solution.  Windows Authentication was enabled in IIS.

username_return.html

<html>
<head>
<script type="text/javascript">
function showUser() {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                document.getElementById("txtHint").innerHTML = xmlhttp.responseText;
            }
        };
  xmlhttp.open("GET", "username_lookup.aspx", true);
  xmlhttp.send();
}
</script>
</head>

<body>
<form> 
<button type="button" onclick="showUser();">Click Me!</button>
</form>
<p>Username: <span id="txtHint"></span></p>
</body>
</html>

username_lookup.aspx

<%Response.Write(Request.ServerVariables("AUTH_USER"))%>

Output Result-

trial.png

Authentication Types-

auth.png

Best Regards,

K-

SteveCole
Frequent Contributor

So, I've wanted to capture this information for a current project and my searches led me to this thread, among others. Unfortunately for me, I don't have PHP or ASP options available to me so that leads me to seeking out a client side solution. Normally, that doesn't exist but I *MAY* have found a surrogate solution that I wanted to share. This is still unproven but the pieces are there. Anyways, you might be able to extract user information using Sharepoint, provided your organization uses it. I found many helpful sites as I descended the rabbit hole of Sharepoint web searches but this site which discusses the Javascript Object Model for Sharepoint 2010 was helpful for what I will share. My testing has ground to a halt because my organization uses Sharepoint 2010 and the following code solution will only work with Sharepoint 2013 or above (presumably).

Anyways, to get started, you need to add five JS script references into your project (my source for this was here😞

    <!-- the following 5 js files are required to use CSOM -->
    <script src="/_layouts/1033/init.js"></script>
    <script src="/_layouts/MicrosoftAjax.js"></script>
    <script src="/_layouts/sp.core.js"></script>
    <script src="/_layouts/sp.runtime.js"></script>
    <script src="/_layouts/sp.js"></script>‍‍‍‍‍‍

The paths must be adjusted to your Sharepoint set up. Our organization's Sharepoint base URL is "https://team/depts/....." so the previous code was modified to the following:

<script type="text/javascript" src="https://team/_layouts/1033/init.js" ></script>
 <script type="text/javascript" src="https://team/_layouts/MicrosoftAjax.js"></script>
 <script type="text/javascript" src="https://team/_layouts/sp.core.js" ></script> 
 <script type="text/javascript" src="https://team/_layouts/sp.runtime.js" ></script> 
 <script type="text/javascript" src="https://team/_layouts/sp.js" ></script>‍‍‍‍‍

BTW, I think the order of the Sharepoint JS script references DOES matter. I kept getting console errors until I specified them in the order shown above. With that out of the way, it's time for the JS code. There's not much code to it, really-

var targetWeb;

function spUserName() {
     var theSpCc = new SP.ClientContext('<path to sharepoint page>'); // e.g. https://team/depts/department
     targetWeb = theSpCc.get_web();
     theSpCc.load(targetWeb);
     theSpCc.executeQueryAsync(Function.createDelegate(this,this.onQuerySucceeded),Function.createDelegate(this,this.onQueryFailed));
}
function onQueryFailed(sender, args) {
     alert('Request failed. \nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
}
function onQuerySucceeded() {
     // On success, use get_ property assessor methods to return the value of the Title, ID, Language, uiVersion, Description, and Created properties of the SP.Web object.
     var theUser = targetWeb.get_currentUser();
     var theUsername = theUser.get_loginName();
     
     var message = "Web retrieved:";
     message += "\n Title: " + targetWeb.get_title();
     message += "\n ID: " + targetWeb.get_id();
     message += "\n Language: " + targetWeb.get_language();
     message += "\n UI Version: " + targetWeb.get_uiVersion();
     message += "\n Description: " + targetWeb.get_description();
     message += "\n Created: " + targetWeb.get_created();
     message += "\n\n And you are: " + theUsername ;
     alert(message);
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I haven't been able to fully test this because Sharepoint 2010 (our current version) only supports relative path names when creating a ClientContext instance. My web app won't be hosted on the Sharepoint server so this code won't work. In Sharepoint 2013, however, full paths are accepted so I feel that this *should* work.

Lastly, there is another Sharepoint related option but I still have a sticking point to implementing it. You can use AJAX on a particular Sharepoint List URL to retrieve a user's information (provided you know their user ID):

Sharepoint 2010:

https://<path to sharepoint page>/_vti_bin/ListData.svc/UserInformationList(theUserID)‍

Sharepoint 2013:

http://<path to sharepoint page>/_api/Web/GetUserById(theUserID)‍‍

 

Of course, the problem here is that you need to know, or figure out a way to reverse engineer,  a user's user ID within Sharepoint. This was my original tact but I couldn't quite figure out how to extract his programatically. If you're on a Sharepoint page, simply type "_spUserId" in the console and you'll get your ID.

Anyways, I wanted to throw this out there for the record. I know it won't help everyone but maybe it helps a few! If anyone does get it to work, I'd love to hear about it!

Steve