Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UserSession.fromCredential using incorrect url? #610

Closed
TravisMS1 opened this issue Aug 12, 2019 · 14 comments
Closed

UserSession.fromCredential using incorrect url? #610

TravisMS1 opened this issue Aug 12, 2019 · 14 comments
Milestone

Comments

@TravisMS1
Copy link

TravisMS1 commented Aug 12, 2019

We have an in-house application that uses both the ArcGIS Javascript API and the ArcGIS REST JS API for connecting to a variety of services. When trying to access a GeocodeServer secured with token-based security on an on-prem ArcGIS Server instance using the ArcGIS REST JS, our request fails due to an Auth error (which is expected since we haven't provided a token or credentials). We prompt the user for a login using the JS API's IdentityManager signIn method to obtain a Credential object, and then we use that Credential object as a parameter to UserSession.fromCredential.

When we retry the request using the new UserSession object, we're getting a NOT_FEDERATED error. I believe this is due to the UserSession.fromCredential method constructing the portal url from the credential.server url. In our case, that results in a portal url of https://<host>/server/sharing/rest instead of https://<host>/portal/sharing/rest

The GeocodeServer is at https://<host>/server/rest/services/<GeocodeServer>
The associated Portal is at https://<host>/portal

@tomwayson
Copy link
Member

The associated Portal is at https:///portal

Is that something that's specific to your environment?

If so, you should be able to just modify the session's portal after calling fromCredential()

@TravisMS1
Copy link
Author

I'm not aware of it being specific to our environment. Our server instance is federated with our portal, and the GeocodeServer is secured. Since the documentation for UserSession.fromCredential states 'Translates authentication from the format used in the ArcGIS API for JavaScript', and what we're providing is a Credential object returned from the JS API IdentityManager after a successful authentication, it seemed like it might be a limitation of the fromCredential method. We can definitely just construct the ICredential manually.

Could there be Credential objects returned from the JS API that wouldn't be expected to work with fromCredential? Also, maybe it's important to note that we are on JS API 3.29 - are there differences in the 3.x and 4.x IdentityManager that could be the culprit?

@tomwayson
Copy link
Member

tomwayson commented Aug 16, 2019

I'm just not familiar enough w/ enterprise installations to know if portal is typically under /portal or that's an arbitrary choice that the administrator makes during installation.

are there differences in the 3.x and 4.x IdentityManager that could be the culprit?

dunno

Here's the current logic we use:

portal: credential.server.includes("sharing/rest")
? credential.server
: credential.server + `/sharing/rest`,

If there's a way to amend that to accommodate a common scenario we're missing, I'd gladly help shepherd a PR.

@TravisMS1
Copy link
Author

I'm also not overly familiar with the details of Enterprise installations, but I do know that many of the installations I've encountered (our internal ones, but also many of our clients') that are federated with Portal have their urls as shown in the original post (/server and /portal). I assume those are the defaults.

If the solution we come up with could warrant a fromCredential PR, we'll be glad to help out. Since the Credential objects I've seen from the JS API don't actually contain the portal url, I think fromCredential would have to make a '/info' request to the server to discover the portal url, making fromCredential asynchronous, a breaking change...

@RandallWilliams
Copy link

I can offer a little clarity here.

When installing ArcGIS Enterprise, the default URL is like:

https://someserver.domain.com:6443/arcgis (ArcGIS Server)
https://https://someserver.domain.com:7443/arcgis (Portal for ArcGIS)

After the product is installed, users frequently install the 'ArcGIS Web Adaptor' - which is recommended for ArcGIS Server, and typically required for Portal for ArcGIS (unless specialized High Availability workflows are implemented using network load balancers instead)

The web adaptor essentially acts as a reverse proxy with rudimentary round robin load balancing capabilities and helps support web tier authentication (if enabled).

During the installaton process, users supply the context under which it is installed to the web server. The name is arbitrary - though the install suggests 'arcgis' as the context. Personally, I myself use 'server' and 'portal' during the install.

ArcGIS Online differs in this respect, where you have https://someorg.maps.arcgis.com/sharing/rest/... without a user defined context. Hope that helps...

@tomwayson
Copy link
Member

Thanks @TravisMS1 and @RandallWilliams - good info.

Here's what I suggest. Instead of a full async request to /info, We could add a second argument to fromCredential() that allows users to optionally pass in a portal root that defaults to / (i.e. in the case of ArcGIS Online). My gut tells me this might need to be options.portalRoot or options.portal.root instead of a one off argument like portalRoot in case we later need someone to set things like the port or path (can it ever be anything other than sharing/rest?), etc.

Furthermore we could optionally also use isOnline to determine if the server is ArcGIS Online and if so skip any of the above options and just use the current hard-coded path.

None of that would be a breaking change.

@pspraveenkr
Copy link
Member

@TravisMS1 - It appears that UserSession.fromCredential function expects the incoming credential to be that of a "portal". However, the credential you're passing is for a "server federated with the portal".

Pls extract portal credential from jsapi like below and try passing that on to UserSession.fromCredential:

var serverCredential = identityManager.findCredential("<GeocodeServerUrl>");
var serverInfo = identityManager.findServerInfo(serverCredential.server);

// owningSystemUrl will be defined the server is federated with a portal.
var portalCredential = identityManager.findCredential(serverInfo.owningSystemUrl);

UserSession.fromCredential(portalCredential);

are there differences in the 3.x and 4.x IdentityManager that could be the culprit?

There are no major differences in 3x and 4x with respect to identity manager functionality.

@patrickarlt
Copy link
Contributor

@TravisMS1 does the above code from @pspraveenkr work for you? I think he has this right. If so we should add this to our docs and close this otherwise we can keep working through some suggestions like what @tomwayson suggested.

@TravisMS1
Copy link
Author

Thanks for the info everyone. I'm looking into the details that @pspraveenkr provided, which seem to me like they should work. At the moment though, the Identity Manager signIn processing isn't creating a portal credential to use. It creates one credential object with the server property set to our above server url, and a scope property (not documented in JS API 3.29 Credential object) set to "portal". We have to then manually register the credential with the IdentityManager using the registerToken method.

Maybe we're missing some required logic on the IdentityManager side of things? I'll follow-up once I find out more.

@TravisMS1
Copy link
Author

When adding a secure Feature Service to a Map from the same server instance, a successful login via the IdentityManager signIn dialog (launched automatically through the process that the Map object is using) creates both server and portal tokens, and raises the credential-create event. However, attempting to manually implement a similar workflow to authenticate a secure geocode service using IdentityManager neither creates the portal token, nor raises the credential-create event for the created server token. It seems there's more work that we would need to do to use IdentityManager in this way. We need to move on to some other work in the short term, but I'll reach out to the JS API team to see if they can provide any guidance.

@tomwayson
Copy link
Member

Thank you @pranavkulkarni for the example! I will add that to our docs to demonstrate how to use fromCredential() with a credential from a feature service.

@tomwayson tomwayson self-assigned this Aug 21, 2019
@tomwayson tomwayson removed their assignment Oct 27, 2019
@patrickarlt
Copy link
Contributor

Reading through auth issues lately I feel like we should handle the case where a user passes a server credential and either:

  1. If a server credential is passed figure out if there is an owning portal. If there is the ArcGISIdentityManager will be created for the portal (owningSystemUrl)
  2. If a server credential is passed and there is NO owningSystemUrl we should create the ArcGISIdentityManager with the specific server object.

We could probally gate this with an option like discoverFederatedPortal which would default to true. So the original scenario proposed by @TravisMS1 would then work like:

var serverCredential = identityManager.findCredential("<GeocodeServerUrl>");

// this would automatically discover the portal credential
var manager = ArcGISIdentityManager.fromCredential(federatedServerCredential);

// this would only manage credetntials for the server
var manager = ArcGISIdentityManager.fromCredential(federatedServerCredential, {
  discoverFederatedPortal: false
});

// if there was an unfederated portal
var manager = ArcGISIdentityManager.fromCredential(standaloneServerCredentials);

If a user wanted to check if the resulting session was for a portal or server they could check the ArcGISIdentityManager.portal or ArcGISIdentityManager.server properties.

@patrickarlt
Copy link
Contributor

Alternate idea would be to split this into 2 methods:

  • fromServerCredential - when you only want ArcGISIdentityManager in REST JS to manage credentials for a single server.
  • fromPortalCredentials - when you want ArcGISIdentityManager to manage credentials for a portal and it's federated servers. If a server credential is passed then we would discover the owning portal an use that.

@patrickarlt
Copy link
Contributor

This will be resolved at 4.0 at the beta branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants