Hello,
I'm trying to create a GeoprocessingTask to a secured service, but the only way to do it is to use the method
public static Task<GeoprocessingTask> CreateAsync(Uri uri);
This method requests the metadata from a service, but because the service is private, i get a Token Required exception. Is it possible to pass a token to the method, so that there is no authentication error? I am generating the token by calling the GenerateCredentialAsync method on AuthenticationManager.
We can't use mechanisms like ChallengeHandler or Credentials from AuthenticationManager, because it is a singleton and our server is asynchronous, it should process multiple geoprocessing requests from different arcgis users.
The only workaround we can find is to use an obsolete constructor instead of the method CreateAsync()
var geoTask = new GeoprocessingTask(uri) { Credential = new ArcGISTokenCredential() { Token = token } };
But because it is obsolete, the workaround is temporary. Is there another way to inject token to a GeoprocessingTask?
Thanks in advance,
Michał
Use a ChallengeHandler.
This gets called by the framework when you send a request that requires credentials
//I put this in the constructor of a class that manages services
AuthenticationManager.Current.ChallengeHandler = new ChallengeHandler(CreateCredentialAsync);
This method will get called when there is a request for a token from the server
private async Task<Credential> CreateCredentialAsync(CredentialRequestInfo info)
{
try
{
_log.Info($"CHALLENGE ********** : {info.ServiceUri} ***********");
if ( info.ServiceUri == null ) return null;
var credential = await AuthenticationManager.Current.GenerateCredentialAsync(info.ServiceUri, Settings.UserName, Settings.Password);
_log.Info($"RETURN credential *********: {info.ServiceUri} ********");
return credential;
}
catch (Exception e)
{
_log.Error(e, e.Message);
return null;
}
}
As I mentioned, we can't use ChallengeHandler.
We have a server that handles requests from users that have permissions to different arcgis services. With the request, a user provides an arcgis token, generated from the GenerateCredentialAsync from AuthenticationManager. There can be multiple requests at the same time, so the ChallengeHandler mechanism is not possible to use, because it is a singleton and it could use other users' tokens to connect to a service while the user that sent the request doesn't have permissions to that service.
Do you really need to authenticate the Task per user? You end up creating a GeoprocessingJob from the task. That has a Credential property on it. Are you able to set that to the new ArcGISTokenCredential as in your sample code before you await on the job's GetResultAsync()? I.e. use a single credential to get the task's metadata using the challenge handler (feels like it could be an App Login credential), and then use each client's token for each job before you get the results.
However, Runtime is not designed to run in a service (you may hit design or technical issues, as here) and it's also against the terms of use (see footnote 19, applying to the ArcGIS Runtime SDKs under the Developer Products section, in the Product-Specific Terms of Use).
That said, we are always looking to understand how we can better support customer use cases, so I'd be interested in understanding more about what you're doing here. Is it possible you could do it by shifting stuff to the client? After all, the GeoprocessingJob Runtime object is really just performing some lightweight polling of the actual server-side GP job. For example: What are the clients that are hitting your service written in (are they mobile apps, or web apps)? Since they're already passing in a token, can they hit the GP Task directly and create and manage a Job? Is there something you need from the Runtime after the job completes to process the results before passing them back to the client? Typically, these things can be done in the client.