diff --git a/packages/arcgis-rest-auth/src/UserSession.ts b/packages/arcgis-rest-auth/src/UserSession.ts index 9f2bf93914..6f0ec4d26c 100644 --- a/packages/arcgis-rest-auth/src/UserSession.ts +++ b/packages/arcgis-rest-auth/src/UserSession.ts @@ -165,6 +165,11 @@ export interface IUserSessionOptions { */ portal?: string; + /** + * This value is set to true automatically if the ArcGIS Organization requires that requests be made over https. + */ + ssl?: boolean; + /** * ArcGIS Authentication is used by default. Specifying an alternative will take users directly to the corresponding provider's OAuth page. */ @@ -215,6 +220,11 @@ export class UserSession implements IAuthenticationManager { */ readonly portal: string; + /** + * This value is set to true automatically if the ArcGIS Organization requires that requests be made over https. + */ + readonly ssl: boolean; + /** * The authentication provider to use. */ @@ -301,6 +311,7 @@ export class UserSession implements IAuthenticationManager { this._token = options.token; this._tokenExpires = options.tokenExpires; this.portal = options.portal || "https://www.arcgis.com/sharing/rest"; + this.ssl = options.ssl; this.provider = options.provider || "arcgis"; this.tokenDuration = options.tokenDuration || 20160; this.redirectUri = options.redirectUri; @@ -373,6 +384,7 @@ export class UserSession implements IAuthenticationManager { new UserSession({ clientId, portal, + ssl: oauthInfo.ssl, token: oauthInfo.token, tokenExpires: new Date(oauthInfo.expires), username: oauthInfo.username @@ -430,6 +442,7 @@ export class UserSession implements IAuthenticationManager { return new UserSession({ clientId, portal, + ssl: oauthInfo.ssl, token: oauthInfo.token, tokenExpires: oauthInfo.expires, username: oauthInfo.username @@ -456,10 +469,14 @@ export class UserSession implements IAuthenticationManager { Date.now() + parseInt(match[2], 10) * 1000 - 60 * 1000 ); const username = decodeURIComponent(match[3]); + const ssl = + win.location.href.indexOf("&ssl=true") > -1 || + win.location.href.indexOf("#ssl=true") > -1; return completeSignIn(undefined, { token, expires, + ssl, username }); } @@ -512,6 +529,7 @@ export class UserSession implements IAuthenticationManager { return new UserSession({ clientId, portal, + ssl: response.ssl, redirectUri, refreshToken: response.refreshToken, refreshTokenTTL, @@ -536,6 +554,7 @@ export class UserSession implements IAuthenticationManager { token: options.token, tokenExpires: new Date(options.tokenExpires), portal: options.portal, + ssl: options.ssl, tokenDuration: options.tokenDuration, redirectUri: options.redirectUri, refreshTokenTTL: options.refreshTokenTTL @@ -557,6 +576,7 @@ export class UserSession implements IAuthenticationManager { static fromCredential(credential: ICredential) { return new UserSession({ portal: credential.server + `/sharing/rest`, + ssl: credential.ssl, token: credential.token, username: credential.userId, tokenExpires: new Date(credential.expires) @@ -576,7 +596,7 @@ export class UserSession implements IAuthenticationManager { return { expires: this.tokenExpires.getTime(), server: this.portal, - ssl: true, + ssl: this.ssl, token: this.token, userId: this.username }; @@ -644,6 +664,7 @@ export class UserSession implements IAuthenticationManager { token: this.token, tokenExpires: this.tokenExpires, portal: this.portal, + ssl: this.ssl, tokenDuration: this.tokenDuration, redirectUri: this.redirectUri, refreshTokenTTL: this.refreshTokenTTL diff --git a/packages/arcgis-rest-auth/src/fetch-token.ts b/packages/arcgis-rest-auth/src/fetch-token.ts index da1bef7ef0..73e8e30f0c 100644 --- a/packages/arcgis-rest-auth/src/fetch-token.ts +++ b/packages/arcgis-rest-auth/src/fetch-token.ts @@ -12,6 +12,7 @@ interface IFetchTokenRawResponse { access_token: string; expires_in: number; username: string; + ssl?: boolean; refresh_token?: string; } @@ -19,6 +20,7 @@ export interface IFetchTokenResponse { token: string; expires: Date; username: string; + ssl: boolean; refreshToken?: string; } @@ -38,7 +40,8 @@ export function fetchToken( username: response.username, expires: new Date( Date.now() + (response.expires_in * 60 * 1000 - 60 * 1000) - ) + ), + ssl: response.ssl === true }; if (response.refresh_token) { r.refreshToken = response.refresh_token; diff --git a/packages/arcgis-rest-auth/test/UserSession.test.ts b/packages/arcgis-rest-auth/test/UserSession.test.ts index 2dff0b1f0e..a5dbf373e5 100644 --- a/packages/arcgis-rest-auth/test/UserSession.test.ts +++ b/packages/arcgis-rest-auth/test/UserSession.test.ts @@ -34,6 +34,7 @@ describe("UserSession", () => { expect(session2.redirectUri).toEqual( "https://example-app.com/redirect-uri" ); + expect(session2.ssl).toBe(undefined); expect(session2.token).toEqual("token"); expect(session2.tokenExpires).toEqual(TOMORROW); expect(session2.refreshToken).toEqual("refreshToken"); @@ -576,6 +577,7 @@ describe("UserSession", () => { .then(session => { expect(session.token).toBe("token"); expect(session.username).toBe("c@sey"); + expect(session.ssl).toBe(true); expect(session.tokenExpires).toEqual(TOMORROW); done(); }) @@ -594,7 +596,8 @@ describe("UserSession", () => { JSON.stringify({ token: "token", expires: TOMORROW, - username: "c@sey" + username: "c@sey", + ssl: true }) ); }); @@ -703,7 +706,7 @@ describe("UserSession", () => { const MockWindow = { location: { href: - "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey&persist=true" + "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey&ssl=true&persist=true" }, get parent() { return this; @@ -721,6 +724,28 @@ describe("UserSession", () => { expect(session.token).toBe("token"); expect(session.tokenExpires.getTime()).toBeGreaterThan(Date.now()); expect(session.username).toBe("c@sey"); + expect(session.ssl).toBe(true); + }); + + it("should return a new user session with ssl as false when callback hash does not have ssl parameter", () => { + const MockWindow = { + location: { + href: + "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey&persist=true" + }, + get parent() { + return this; + } + }; + + const session = UserSession.completeOAuth2( + { + clientId: "clientId", + redirectUri: "https://example-app.com/redirect-uri" + }, + MockWindow + ); + expect(session.ssl).toBe(false); }); it("should callback to create a new user session if finds a valid opener", done => { @@ -734,6 +759,7 @@ describe("UserSession", () => { const oauthInfo = JSON.parse(oauthInfoString); expect(oauthInfo.token).toBe("token"); expect(oauthInfo.username).toBe("c@sey"); + expect(oauthInfo.ssl).toBe(true); expect(new Date(oauthInfo.expires).getTime()).toBeGreaterThan( Date.now() ); @@ -745,7 +771,7 @@ describe("UserSession", () => { }, location: { href: - "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey" + "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey&ssl=true" } }; @@ -768,6 +794,7 @@ describe("UserSession", () => { const oauthInfo = JSON.parse(oauthInfoString); expect(oauthInfo.token).toBe("token"); expect(oauthInfo.username).toBe("c@sey"); + expect(oauthInfo.ssl).toBe(true); expect(new Date(oauthInfo.expires).getTime()).toBeGreaterThan( Date.now() ); @@ -778,7 +805,7 @@ describe("UserSession", () => { }, location: { href: - "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey" + "https://example-app.com/redirect-uri#access_token=token&expires_in=1209600&username=c%40sey&ssl=true" } }; @@ -854,7 +881,8 @@ describe("UserSession", () => { access_token: "token", expires_in: 1800, refresh_token: "refreshToken", - username: "Casey" + username: "Casey", + ssl: true }); UserSession.exchangeAuthorizationCode( @@ -865,6 +893,11 @@ describe("UserSession", () => { "code" ) .then(session => { + expect(session.token).toBe("token"); + expect(session.tokenExpires.getTime()).toBeGreaterThan(Date.now()); + expect(session.username).toBe("Casey"); + expect(session.refreshToken).toBe("refreshToken"); + expect(session.ssl).toBe(true); done(); }) .catch(e => { @@ -923,7 +956,7 @@ describe("UserSession", () => { const MOCK_CREDENTIAL: ICredential = { expires: TOMORROW.getTime(), server: "https://www.arcgis.com", - ssl: true, + ssl: false, token: "token", userId: "jsmith" }; @@ -933,6 +966,7 @@ describe("UserSession", () => { clientId: "clientId", redirectUri: "https://example-app.com/redirect-uri", token: "token", + ssl: false, tokenExpires: TOMORROW, refreshToken: "refreshToken", refreshTokenExpires: TOMORROW, @@ -944,7 +978,7 @@ describe("UserSession", () => { const creds = session.toCredential(); expect(creds.userId).toEqual("jsmith"); expect(creds.server).toEqual("https://www.arcgis.com/sharing/rest"); - expect(creds.ssl).toEqual(true); + expect(creds.ssl).toEqual(false); expect(creds.token).toEqual("token"); expect(creds.expires).toEqual(TOMORROW.getTime()); }); @@ -953,6 +987,7 @@ describe("UserSession", () => { const session = UserSession.fromCredential(MOCK_CREDENTIAL); expect(session.username).toEqual("jsmith"); expect(session.portal).toEqual("https://www.arcgis.com/sharing/rest"); + expect(session.ssl).toEqual(false); expect(session.token).toEqual("token"); expect(session.tokenExpires).toEqual(new Date(TOMORROW)); }); diff --git a/packages/arcgis-rest-auth/test/fetchToken.test.ts b/packages/arcgis-rest-auth/test/fetchToken.test.ts index 7defc34937..b30ee04b2f 100644 --- a/packages/arcgis-rest-auth/test/fetchToken.test.ts +++ b/packages/arcgis-rest-auth/test/fetchToken.test.ts @@ -12,7 +12,8 @@ describe("fetchToken()", () => { it("should request a token with `client_credentials`, `client_id` and `client_secret`", done => { fetchMock.postOnce(TOKEN_URL, { access_token: "token", - expires_in: 1800 + expires_in: 1800, + ssl: true }); fetchToken(TOKEN_URL, { @@ -33,6 +34,7 @@ describe("fetchToken()", () => { expect(options.body).toContain("grant_type=client_credentials"); expect(response.token).toEqual("token"); expect(response.expires).toBeGreaterThan(Date.now()); + expect(response.ssl).toEqual(true); done(); }) .catch(e => { @@ -45,7 +47,8 @@ describe("fetchToken()", () => { access_token: "token", expires_in: 1800, refresh_token: "refreshToken", - username: "Casey" + username: "Casey", + ssl: true }); fetchToken(TOKEN_URL, { @@ -74,6 +77,32 @@ describe("fetchToken()", () => { expect(response.refreshToken).toEqual("refreshToken"); expect(response.username).toEqual("Casey"); expect(response.expires).toBeGreaterThan(Date.now()); + expect(response.ssl).toEqual(true); + done(); + }) + .catch(e => { + fail(e); + }); + }); + + it("should return ssl: false when there is no ssl property returned from endpoint response", done => { + fetchMock.postOnce(TOKEN_URL, { + access_token: "token", + expires_in: 1800, + refresh_token: "refreshToken", + username: "Casey" + }); + + fetchToken(TOKEN_URL, { + params: { + client_id: "clientId", + redirect_uri: "https://example-app.com/redirect-uri", + code: "authorizationCode", + grant_type: "authorization_code" + } + }) + .then(response => { + expect(response.ssl).toEqual(false); done(); }) .catch(e => {