Skip to content

Commit 41d1bd3

Browse files
authored
fix(oauth): Patch redirect validation (#3656)
1 parent 5b31e33 commit 41d1bd3

File tree

1 file changed

+76
-49
lines changed

1 file changed

+76
-49
lines changed
Lines changed: 76 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,146 @@
11
// @ts-ignore
2-
import getProfile from 'grant-profile/lib/client';
3-
import querystring from 'querystring';
4-
import Debug from 'debug';
2+
import getProfile from "grant-profile/lib/client";
3+
import querystring from "querystring";
4+
import Debug from "debug";
55
import {
6-
AuthenticationRequest, AuthenticationBaseStrategy, AuthenticationResult
7-
} from '@feathersjs/authentication';
8-
import { Params } from '@feathersjs/feathers';
9-
import { NotAuthenticated } from '@feathersjs/errors';
6+
AuthenticationRequest,
7+
AuthenticationBaseStrategy,
8+
AuthenticationResult,
9+
} from "@feathersjs/authentication";
10+
import { Params } from "@feathersjs/feathers";
11+
import { NotAuthenticated } from "@feathersjs/errors";
1012

11-
const debug = Debug('@feathersjs/authentication-oauth/strategy');
13+
const debug = Debug("@feathersjs/authentication-oauth/strategy");
1214

1315
export interface OAuthProfile {
14-
id?: string|number;
16+
id?: string | number;
1517
[key: string]: any;
1618
}
1719

1820
export class OAuthStrategy extends AuthenticationBaseStrategy {
19-
get configuration () {
20-
const { entity, service, entityId, oauth } = this.authentication.configuration;
21+
get configuration() {
22+
const { entity, service, entityId, oauth } =
23+
this.authentication.configuration;
2124
const config = oauth[this.name];
2225

2326
return {
2427
entity,
2528
service,
2629
entityId,
27-
...config
30+
...config,
2831
};
2932
}
3033

31-
get entityId (): string {
34+
get entityId(): string {
3235
const { entityService } = this;
3336

3437
return this.configuration.entityId || (entityService && entityService.id);
3538
}
3639

37-
async getEntityQuery (profile: OAuthProfile, _params: Params) {
40+
async getEntityQuery(profile: OAuthProfile, _params: Params) {
3841
return {
39-
[`${this.name}Id`]: profile.sub || profile.id
42+
[`${this.name}Id`]: profile.sub || profile.id,
4043
};
4144
}
4245

43-
async getEntityData (profile: OAuthProfile, _existingEntity: any, _params: Params) {
46+
async getEntityData(
47+
profile: OAuthProfile,
48+
_existingEntity: any,
49+
_params: Params,
50+
) {
4451
return {
45-
[`${this.name}Id`]: profile.sub || profile.id
52+
[`${this.name}Id`]: profile.sub || profile.id,
4653
};
4754
}
4855

4956
/* istanbul ignore next */
50-
async getProfile (data: AuthenticationRequest, _params: Params) {
51-
const config = this.app.get('grant');
57+
async getProfile(data: AuthenticationRequest, _params: Params) {
58+
const config = this.app.get("grant");
5259
const provider = config[data.strategy];
5360

54-
debug('getProfile of oAuth profile from grant-profile with', data);
61+
debug("getProfile of oAuth profile from grant-profile with", data);
5562

5663
return getProfile(provider, data);
5764
}
5865

59-
async getCurrentEntity (params: Params) {
66+
async getCurrentEntity(params: Params) {
6067
const { authentication } = params;
6168
const { entity } = this.configuration;
6269

6370
if (authentication && authentication.strategy) {
64-
debug('getCurrentEntity with authentication', authentication);
71+
debug("getCurrentEntity with authentication", authentication);
6572

6673
const { strategy } = authentication;
67-
const authResult = await this.authentication
68-
.authenticate(authentication, params, strategy);
74+
const authResult = await this.authentication.authenticate(
75+
authentication,
76+
params,
77+
strategy,
78+
);
6979

7080
return authResult[entity];
7181
}
7282

7383
return null;
7484
}
7585

76-
async getRedirect (data: AuthenticationResult|Error, params?: Params): Promise<string | null> {
77-
const queryRedirect = (params && params.redirect) || '';
86+
async getRedirect(
87+
data: AuthenticationResult | Error,
88+
params?: Params,
89+
): Promise<string | null> {
90+
const queryRedirect = (params && params.redirect) || "";
7891
const { redirect } = this.authentication.configuration.oauth;
7992

8093
if (!redirect) {
8194
return null;
8295
}
8396

97+
if (queryRedirect && /[@\\]|^\/\/|\/\//.test(queryRedirect)) {
98+
throw new NotAuthenticated("Invalid redirect path.");
99+
}
100+
84101
const redirectUrl = redirect + queryRedirect;
85-
const separator = redirect.endsWith('?') ? '' :
86-
(redirect.indexOf('#') !== -1 ? '?' : '#');
102+
const separator = redirect.endsWith("?")
103+
? ""
104+
: redirect.indexOf("#") !== -1
105+
? "?"
106+
: "#";
87107
const authResult: AuthenticationResult = data;
88-
const query = authResult.accessToken ? {
89-
access_token: authResult.accessToken
90-
} : {
91-
error: data.message || 'OAuth Authentication not successful'
92-
};
108+
const query = authResult.accessToken
109+
? {
110+
access_token: authResult.accessToken,
111+
}
112+
: {
113+
error: data.message || "OAuth Authentication not successful",
114+
};
93115

94116
return redirectUrl + separator + querystring.stringify(query);
95117
}
96118

97-
async findEntity (profile: OAuthProfile, params: Params) {
119+
async findEntity(profile: OAuthProfile, params: Params) {
98120
const query = await this.getEntityQuery(profile, params);
99121

100-
debug('findEntity with query', query);
122+
debug("findEntity with query", query);
101123

102124
const result = await this.entityService.find({
103125
...params,
104-
query
126+
query,
105127
});
106-
const [ entity = null ] = result.data ? result.data : result;
128+
const [entity = null] = result.data ? result.data : result;
107129

108-
debug('findEntity returning', entity);
130+
debug("findEntity returning", entity);
109131

110132
return entity;
111133
}
112134

113-
async createEntity (profile: OAuthProfile, params: Params) {
135+
async createEntity(profile: OAuthProfile, params: Params) {
114136
const data = await this.getEntityData(profile, null, params);
115137

116-
debug('createEntity with data', data);
138+
debug("createEntity with data", data);
117139

118140
return this.entityService.create(data, params);
119141
}
120142

121-
async updateEntity (entity: any, profile: OAuthProfile, params: Params) {
143+
async updateEntity(entity: any, profile: OAuthProfile, params: Params) {
122144
const id = entity[this.entityId];
123145
const data = await this.getEntityData(profile, entity, params);
124146

@@ -127,12 +149,12 @@ export class OAuthStrategy extends AuthenticationBaseStrategy {
127149
return this.entityService.patch(id, data, params);
128150
}
129151

130-
async getEntity (result: any, params: Params) {
152+
async getEntity(result: any, params: Params) {
131153
const { entityService } = this;
132154
const { entityId = entityService.id, entity } = this.configuration;
133155

134156
if (!entityId || result[entityId] === undefined) {
135-
throw new NotAuthenticated('Could not get oAuth entity');
157+
throw new NotAuthenticated("Could not get oAuth entity");
136158
}
137159

138160
if (!params.provider) {
@@ -141,25 +163,30 @@ export class OAuthStrategy extends AuthenticationBaseStrategy {
141163

142164
return entityService.get(result[entityId], {
143165
...params,
144-
[entity]: result
166+
[entity]: result,
145167
});
146168
}
147169

148-
async authenticate (authentication: AuthenticationRequest, originalParams: Params) {
170+
async authenticate(
171+
authentication: AuthenticationRequest,
172+
originalParams: Params,
173+
) {
149174
const entity: string = this.configuration.entity;
150175
const { provider, ...params } = originalParams;
151176
const profile = await this.getProfile(authentication, params);
152-
const existingEntity = await this.findEntity(profile, params)
153-
|| await this.getCurrentEntity(params);
177+
const existingEntity =
178+
(await this.findEntity(profile, params)) ||
179+
(await this.getCurrentEntity(params));
154180

155181
debug(`authenticate with (existing) entity`, existingEntity);
156182

157-
const authEntity = !existingEntity ? await this.createEntity(profile, params)
183+
const authEntity = !existingEntity
184+
? await this.createEntity(profile, params)
158185
: await this.updateEntity(existingEntity, profile, params);
159186

160187
return {
161188
authentication: { strategy: this.name },
162-
[entity]: await this.getEntity(authEntity, originalParams)
189+
[entity]: await this.getEntity(authEntity, originalParams),
163190
};
164191
}
165192
}

0 commit comments

Comments
 (0)