Select to view content in your preferred language

DefaultAuthenticationChallengeHandler adding a AuthenticationChallengeResponse

2757
10
10-07-2019 11:15 AM
by Anonymous User
Not applicable

OK so I have DefaultAuthenticationChallengeHandler working fine to login to a runtime application with the following code which works great for logging in ...

AuthenticationChallengeHandler handler = new DefaultAuthenticationChallengeHandler(this);

OAuthConfiguration oAC = new OAuthConfiguration(urlLogin, Client_ID, "my-arcgis-app://auth", 129600); //90 days
AuthenticationManager.addOAuthConfiguration(oAC);
AuthenticationManager.setAuthenticationChallengeHandler(handler);

However the DefaultAuthenticationChallengeHandler works poorly for Web Maps in that the challenge occurs for every single layer in every feature service.  Nobody wants to login this many times.  When I use a custom login form for feature services I can suppress the multiple logins and use the first login to provide access to the rest of the layers in a feature service.  I can do this via a CountDownLatch to suppress the calling thread and wait for the thread firing off the login form for a specific feature service (see code below).  The issue I am having is I do like the DefaultAuthenticationChallengeHandler for login to the application because it allows me to not have to handle the username or password myself, but do not like the way it works with feature services. 

Is there a way to setup a AuthenticationChallengeResponse listener against the DefaultAuthenticationChallengeHandler so that I could add a CountDownLatch to the default login?

Below is using a custom login form to access a feature service with CountDownLatch.....

AuthenticationManager.setAuthenticationChallengeHandler(this);

@Override

public AuthenticationChallengeResponse handleChallenge(AuthenticationChallenge authenticationChallenge) {
try {
if (authenticationChallenge.getType() == AuthenticationChallenge.Type.USER_CREDENTIAL_CHALLENGE) {
if (((Portal) authenticationChallenge.getRemoteResource()).getLoadStatus() == LoadStatus.LOADED) {
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CANCEL,
authenticationChallenge);
}

int maxAttempts = 5;
if (authenticationChallenge.getFailureCount() > maxAttempts) {
// exceeded maximum amount of attempts. Act like it was a cancel
Toast.makeText(this, "Exceeded maximum amount of attempts. Please try again!", Toast.LENGTH_LONG).show();
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CANCEL,
authenticationChallenge);
}

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

final String fsURLPassIN = fsURL;

if (mAgencyCredentials==null) {
authenticationCounter++;
DownloadHelper.signal = new CountDownLatch(1);

runOnUiThread(new Runnable() {
@Override
public void run() {
showFSLogin("Credential is required to access " + authenticationChallenge.getRemoteResource().getUri(), fsURLPassIN);
}
});

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) {
if (authenticationCounter==0) { //this should be only run once after authentication as this challenge response will hit once for each layer.
loadMap();
}
authenticationCounter++;
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CONTINUE_WITH_CREDENTIAL, mAgencyCredentials);

}
}

} catch (Exception e){
e.printStackTrace();
}
// no credentials were set, return a new auth challenge response with a cancel
return new AuthenticationChallengeResponse(AuthenticationChallengeResponse.Action.CANCEL, authenticationChallenge);

}

0 Kudos
10 Replies
by Anonymous User
Not applicable

OK so looks like in 100.7 DefaultAuthenticationHandler is using Chrome Custom Tabs and it works!  So in summary after login the chrome tab for login is no longer open.  From the release notes...Release notes for 100.7.0—ArcGIS Runtime SDK for Android | ArcGIS for Developers 

Chrome Custom Tabs—The DefaultAuthenticationChallengeHandler now uses Chrome Custom Tabs by default in order to prompt users for credentials for OAuth authentication. This provides a better user experience than prompting for credentials in an external browser window. If you still prefer prompting for OAuth credentials in an external browser window, you can disable Chrome Custom Tabs with DefaultAuthenticationChallengeHandler.setChromeCustomTabsEnabled.

0 Kudos