User-Application Authentication Possible in JS API 3.16?

3179
7
03-31-2016 07:20 AM
Jay_Gregory
Occasional Contributor III

I'm having some pesky problems implementing some authentication for my JS App (which is hosted on an internal web server).  I thought that I could follow the Application login workflow (create application in Portal, use OAuthInfo class with appId to authenticate user to my Portal and gain access to my app) to allow only specific users to access my application as long as I set the security (through Portal) of my Web Mapping Application item to one of my Portal security groups.  Turns out it doesn't matter if the Web Mapping Application is shared with everyone or no one - if my JS web app has the appId, any user can login to my application. 

So the only way (seemingly) to allow only some users access to my application is to restrict the _layers_ in my app to specific groups and use the IdentityManager class to challenge a user, etc. etc.  I like how the API handles much of this workflow without much extra coding - if my app tries to add a restricted layer to the map (map.addLayers([restrictedLayer1, layer2]), the user is prompted to sign in.  However, sometimes those restricted layers are not added until after a bunch of other stuff happens (dom parsing, widget instantiation, etc etc). 

I would like to make sure the user has access to those secured layers before anything else happens, especially before my app gets to the point where it is trying to add those secured layers to the map.  I don't know how to do this.  What classes and methods should I use to challenge a user and determine if that user has access to a specific restricted layer?  I tried using IdentityManager getCredential method, where the URL is my restricted layer endpoint, but that didn't work.  Any suggestions?

0 Kudos
7 Replies
RobertScheitlin__GISP
MVP Emeritus

Jay,

  You can use esriRequest in a function that is the first to get called in your codes workflow by using dojo Ready to call your check authorization function and only after that do you call the main init function to defines the map, etc, etc.

0 Kudos
Jay_Gregory
Occasional Contributor III

Thanks Robert - do you have any examples of working code that implements this workflow that I might be able to look at?  I'm having some difficulty with it. 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jay,

  Sorry for the delay. Here is what I came up with that seems to work well.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
    <title>Simple Map</title>
    <link rel="stylesheet" href="https://js.arcgis.com/3.16/esri/css/esri.css">
    <link rel="stylesheet" href="https://js.arcgis.com/3.16/dijit/themes/claro/claro.css">
    <style>
      html, body, #map {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script src="https://js.arcgis.com/3.16/"></script>
    <script>
      var map;

      require([
        "esri/map",
        "esri/IdentityManager",
        "esri/layers/ArcGISDynamicMapServiceLayer",
        "dojo/domReady!"
      ], function(Map, esriId, ArcGISDynamicMapServiceLayer) {
        map = new Map("map", {
          basemap: "topo",  //For full list of pre-defined basemaps, navigate to http://arcg.is/1JVo6Wd
          center: [-122.45, 37.75], // longitude, latitude
          zoom: 13
        });
        var cred = esriId.getCredential("http://mycomputer/arcgis/rest/services/mysecureservice/MapServer").then(
          function(result){
            console.info(result);
            var secDynLyr = new ArcGISDynamicMapServiceLayer("http://mycomputer/arcgis/rest/services/mysecureservice/MapServer");
            map.addLayer(secDynLyr);
          },
          function(err){
            console.info(err);
          }
        );
      });
    </script>
  </head>

  <body class="claro">
    <div id="map"></div>
  </body>
</html>
0 Kudos
Jay_Gregory
Occasional Contributor III

So what I found with this solution (which I had tried) was that esriId.getCredential will succeed as long as the user is a member of my Portal, and even if my member does NOT have access to the url endpoint passed into the function as a parameter.  Are you not seeing this behavior when you try logging in with a user that doesn't have permission to your secured service?  It doesn't make sense to me, but that is the behavior I am seeing....

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jay,

When you secured the map service in Manager did you have "Allow access to all users who are logged in" checked? Because I am not seeing what you are seeing and mine is working correctly and not adding the service if the user is not authorized. Now if the user is an admin that no matter what they will have access.

0 Kudos
Jay_Gregory
Occasional Contributor III

I use a federated / hosted Portal instance on top of my server, so I set the sharing through Portal, not through Manager.  And the service is set to only provide access to members of a group, not all members of the Portal.... 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jay,

  A federated portal instance is outside my area of expertise so I would suggest a contact to tech support then.

0 Kudos