Adding Secured Services to CredentialCache

950
4
Jump to solution
09-25-2020 07:52 AM
by Anonymous User
Not applicable

I am wondering if there is a way to add Secured Services (non-federated but shared via AGOL) to the CredentialCache?  As far as I can tell this does not work.  It would be nice to be able to do this so that secured service credentials could be stored in the same way that credentials associated with portal/AGOL are.  

The documentation seems to indicate that after credentials are used they are automatically added to the CredentialCache.  I see this happening with credentials associated with AGOL but am not seeing that happen with credentials use for secured services.  Can Secured (non-federated) Services be used with CredentialCache?  I am using the "extends DefaultAuthenticationChallengeHandler" to authenticate secured services.


					
				
			
			
				
			
			
				
0 Kudos
1 Solution

Accepted Solutions
XuemingWu
Esri Contributor

Hi Aaron,

Could you check if the feature layer fLayer was loaded or was displayed in a MapView before checking the credential cache? Though mAgencyCredentials was set on the service feature table fsTable, if it was not used to load the table or layer successfully, it won't be added to the credential cache. 

As a side note that the DefaultAuthenticationChallengeHandler also handle secured services including non-federated services. If you are already aware of it or you have special logic which requires a custom challenge handler, please ignore this side note.

Regards,

View solution in original post

0 Kudos
4 Replies
Erick_1
Esri Contributor

Hi Aaron Dick‌,

We currently don't have an API to directly add credentials into the Credential Cache. 

The credentials should be added to the cache automatically once you have successfully signed to that secured service. 

Could you share how some of the code you're using to authenticate with this service?

Are you using OAuth, Certificate Credential or IWA?

It also seems like you are using a Custom Challenge Handler. Is there anyway you could share your implementation? 

0 Kudos
by Anonymous User
Not applicable

Hi Erick,

Yeah that makes sense.  What is happening is that OAuth (OAuthTokenCredential)  portal credentials do work and I can see those credentials in the Credential Cache automatically.  However secured service credentials (UserCredential) do not seem to get added automatically.

Below is the code we use...

First we attempt to add the FeatureLayer which is derived from ServiceFeatureTable where the url to the secure service is passed in prior to the ServiceFeatureTable.  mAgencyCredential is a Credential variable. 

if (mAgencyCredentials != null) {  //Check if credentials already available
      fsTable.setCredential(mAgencyCredentials);  //on premise shared through AGOL
}
FeatureLayer fLayer = new FeatureLayer(fsTable);
mMap.getOperationalLayers().add(fLayer);

When we do the ".add" command this will automatically trigger the class we built to check credentials.  If null or invalid 

public class S1AuthenticationChallengeHandler extends DefaultAuthenticationChallengeHandler {
   public S1AuthenticationChallengeHandler(Activity context) {
      super(context);
   }

   private String lastFSPassIn = "";

   public static Boolean backPressed = false;  //used to prevent login screen from showing up when user backs out of web map preview window.

   @Override
   public AuthenticationChallengeResponse handleChallenge(AuthenticationChallenge challenge) {
      if (challenge.getRemoteResource() instanceof Portal) {  //instance of portal
         // let DefaultAuthenticationChallengeHandler handle this challenge
         return super.handleChallenge(challenge);
      } else {  //secured service
         if (!backPressed) {  //back pressed on FeatureServiceLogin triggers one more handler event unfortunately by doing a countdown.  Do not want to trigger another countdownlatch so if backpressed do nothing
               int maxAttempts = 5;
               if (challenge.getFailureCount() > maxAttempts) {
                  // exceeded maximum amount of attempts. Act like it was a cancel
                  Toast.makeText(S1ViewerActivity.getS1ViewerActivity(), "Exceeded maximum amount of attempts. Please try again!", Toast.LENGTH_LONG).show();
                  return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CANCEL, challenge);
               }

               String fsURL = challenge.getRemoteResource().getUri();

               if (!fsURL.endsWith("/FeatureServer")) {
                  if (fsURL.contains("/FeatureServer")) {
                     fsURL = fsURL.substring(0, fsURL.indexOf("/FeatureServer") + 14);
                  }
               }

               final String fsURLPassIn = fsURL;
               // create a countdown latch with a count of one to synchronize the dialog
               DownloadHelper.signal = new CountDownLatch(1);

               S1ViewerActivity.getS1ViewerActivity().runOnUiThread(new Runnable() {
                  @Override
                  public void run() {
                     try {
                        if (DownloadHelper.downloadSyncAction != null) {
                              if (MapExtentDownloadFS.getMapExtentDownloadFS() != null) {
                                 showFSLogin(errorLabel, fsURLPassIn);  //this will prompt user to type in username and password
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});

try {
DownloadHelper.signal.await();
} catch (InterruptedException e) {
String error = "Interruption handling AuthenticationChallengeResponse: " + e.getMessage();
//Toast.makeText(this, error, Toast.LENGTH_LONG).show();
}
// if credentials were set, return a new auth challenge response with them. otherwise, act like it was a cancel.
if (mAgencyCredentials != null) {
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CONTINUE_WITH_CREDENTIAL, mAgencyCredentials);
} else {
lastFSPassIn = ""; //In case of failure to login this needs to be set back to empty string in case user tries to login to webmap again.
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CANCEL, challenge);
}
} else {
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CANCEL, challenge);
}
}
}
}

The core line of code that runs (in showFSLogin) when login credentials required after typed in is as follows...

mAgencyCredentials = new UserCredential(userName, password);
0 Kudos
XuemingWu
Esri Contributor

Hi Aaron,

Could you check if the feature layer fLayer was loaded or was displayed in a MapView before checking the credential cache? Though mAgencyCredentials was set on the service feature table fsTable, if it was not used to load the table or layer successfully, it won't be added to the credential cache. 

As a side note that the DefaultAuthenticationChallengeHandler also handle secured services including non-federated services. If you are already aware of it or you have special logic which requires a custom challenge handler, please ignore this side note.

Regards,

0 Kudos
by Anonymous User
Not applicable

Xueming,

Indeed that was the problem.  As soon as I added in a line to load fsTable all is good. Thanks again.  For those wondering what I am talking about it is just as simple as adding in...

fsTable.loadAsync();

and then all is good.

Thanks Xueming!

0 Kudos