Skip to content

Commit

Permalink
fix(arcgis-rest-auth): ensure that mixed casing of federated server u…
Browse files Browse the repository at this point in the history
…rls does not break the system

When federated servers are configured, the UI does not enforce lower casing of the federated server
name. This can result in hosted services with UPPERCASE urls. This PR ensures that the user session
works with lower-cased urls, and that regardless of casing of inbound requests, the federated token
cache works correctly.

AFFECTS PACKAGES:
@esri/arcgis-rest-auth
  • Loading branch information
dbouwman committed Dec 3, 2018
1 parent 25b70ad commit 07c92f5
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 3 deletions.
7 changes: 4 additions & 3 deletions packages/arcgis-rest-auth/src/UserSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ export class UserSession implements IAuthenticationManager {
/^https?:\/\/\S+\.arcgis\.com.+/.test(url)
) {
return this.getFreshToken(requestOptions);
} else if (new RegExp(this.portal).test(url)) {
} else if (new RegExp(this.portal, "i").test(url)) {
return this.getFreshToken(requestOptions);
} else {
return this.getTokenForServer(url, requestOptions);
Expand Down Expand Up @@ -708,7 +708,8 @@ export class UserSession implements IAuthenticationManager {
requestOptions?: ITokenRequestOptions
) {
// requests to /rest/services/ and /rest/admin/services/ are both valid
const [root] = url.split(/\/rest(\/admin)?\/services\//);
// Federated servers may have inconsisten casing, so loweCase it
const [root] = url.toLowerCase().split(/\/rest(\/admin)?\/services\//);
const existingToken = this.trustedServers[root];

if (existingToken && existingToken.expires.getTime() > Date.now()) {
Expand All @@ -732,7 +733,7 @@ export class UserSession implements IAuthenticationManager {
*/
if (
!owningSystemUrl ||
!new RegExp(owningSystemUrl).test(this.portal)
!new RegExp(owningSystemUrl, "i").test(this.portal)
) {
throw new ArcGISAuthError(
`${url} is not federated with ${this.portal}.`,
Expand Down
84 changes: 84 additions & 0 deletions packages/arcgis-rest-auth/test/UserSession.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,90 @@ describe("UserSession", () => {
});
});

it("should return unexpired tokens for the configured portal domain, regardless of CASING", done => {
// This was a real configuration discovered on a portal instance
const session = new UserSession({
clientId: "id",
token: "token",
tokenExpires: TOMORROW,
portal: "https://pnp00035.esri.com/sharing/rest"
});

session
.getToken("https://PNP00035.esri.com/sharing/rest/portals/self")
.then(token => {
expect(token).toBe("token");
done();
})
.catch(e => {
fail(e);
});
});

it("should use fetch token when contacting a server that is federated, even if on same domain, regardless of domain casing", done => {
// This was a real configuration discovered on a portal instance
// apparently when federating servers, the UI does not force the
// server url to lowercase, and this any feature service items generated
// will have the server name using the casing the admin entered.
// this is just a test to ensure that the mis-matched casing does not
// break the federation flow.
const session = new UserSession({
clientId: "id",
token: "existing-session-token",
refreshToken: "refresh",
tokenExpires: TOMORROW,
portal: "https://pnp00035.esri.com/portal/sharing/rest"
});

fetchMock.postOnce("https://pnp00035.esri.com/server/rest/info", {
currentVersion: 10.61,
fullVersion: "10.6.1",
owningSystemUrl: "https://pnp00035.esri.com/portal",
authInfo: {
isTokenBasedSecurity: true,
tokenServicesUrl:
"https://pnp00035.esri.com/portal/sharing/rest/generateToken"
}
});

fetchMock.postOnce("https://pnp00035.esri.com/portal/sharing/rest/info", {
owningSystemUrl: "https://pnp00035.esri.com/portal",
authInfo: {
tokenServicesUrl:
"https://pnp00035.esri.com/portal/sharing/rest/generateToken",
isTokenBasedSecurity: true
}
});

fetchMock.postOnce(
"https://pnp00035.esri.com/portal/sharing/rest/generateToken",
{
token: "new-server-token",
expires: TOMORROW
}
);

// request the token twice, for the same domain, but with different casing
// and we expect a single POST to generate a token once
session
.getToken(
"https://PNP00035.esri.com/server/rest/services/Hosted/perimeters_dd83/FeatureServer"
)
.then(token => {
expect(token).toBe("new-server-token");
return session.getToken(
"https://pnp00035.esri.com/server/rest/services/Hosted/otherService/FeatureServer"
);
})
.then(token => {
expect(token).toBe("new-server-token");
done();
})
.catch(e => {
fail(e);
});
});

it("should fetch new tokens when tokens for trusted arcgis.com domains are expired", done => {
const session = new UserSession({
clientId: "id",
Expand Down

0 comments on commit 07c92f5

Please sign in to comment.