mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
Add resource param to client credential oauth grant. (#1174)
Addresses #716
This commit is contained in:
parent
a921c9c054
commit
9413481b2e
@ -10,6 +10,8 @@ const ACCESS_TOKEN_URL = 'https://foo.com/access_token';
|
||||
const CLIENT_ID = 'client_123';
|
||||
const CLIENT_SECRET = 'secret_12345456677756343';
|
||||
const SCOPE = 'scope_123';
|
||||
const AUDIENCE = 'https://foo.com/userinfo';
|
||||
const RESOURCE = 'https://foo.com/resource';
|
||||
|
||||
describe('client_credentials', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
@ -21,7 +23,9 @@ describe('client_credentials', () => {
|
||||
JSON.stringify({
|
||||
access_token: 'token_123',
|
||||
token_type: 'token_type',
|
||||
scope: SCOPE
|
||||
scope: SCOPE,
|
||||
audience: AUDIENCE,
|
||||
resource: RESOURCE
|
||||
})
|
||||
);
|
||||
|
||||
@ -39,7 +43,9 @@ describe('client_credentials', () => {
|
||||
false,
|
||||
CLIENT_ID,
|
||||
CLIENT_SECRET,
|
||||
SCOPE
|
||||
SCOPE,
|
||||
AUDIENCE,
|
||||
RESOURCE
|
||||
);
|
||||
|
||||
// Check the request to fetch the token
|
||||
@ -53,7 +59,9 @@ describe('client_credentials', () => {
|
||||
mimeType: 'application/x-www-form-urlencoded',
|
||||
params: [
|
||||
{ name: 'grant_type', value: 'client_credentials' },
|
||||
{ name: 'scope', value: SCOPE }
|
||||
{ name: 'scope', value: SCOPE },
|
||||
{ name: 'audience', value: AUDIENCE },
|
||||
{ name: 'resource', value: RESOURCE }
|
||||
]
|
||||
},
|
||||
headers: [
|
||||
@ -80,6 +88,8 @@ describe('client_credentials', () => {
|
||||
expires_in: null,
|
||||
token_type: 'token_type',
|
||||
scope: SCOPE,
|
||||
audience: AUDIENCE,
|
||||
resource: RESOURCE,
|
||||
error: null,
|
||||
error_uri: null,
|
||||
error_description: null,
|
||||
@ -95,7 +105,9 @@ describe('client_credentials', () => {
|
||||
JSON.stringify({
|
||||
access_token: 'token_123',
|
||||
token_type: 'token_type',
|
||||
scope: SCOPE
|
||||
scope: SCOPE,
|
||||
audience: AUDIENCE,
|
||||
resource: RESOURCE
|
||||
})
|
||||
);
|
||||
|
||||
@ -104,9 +116,7 @@ describe('client_credentials', () => {
|
||||
bodyCompression: '',
|
||||
parentId: 'req_1',
|
||||
statusCode: 200,
|
||||
headers: [
|
||||
{ name: 'Content-Type', value: 'application/x-www-form-urlencoded' }
|
||||
]
|
||||
headers: [{ name: 'Content-Type', value: 'application/x-www-form-urlencoded' }]
|
||||
}));
|
||||
|
||||
const result = await getToken(
|
||||
@ -115,7 +125,9 @@ describe('client_credentials', () => {
|
||||
true,
|
||||
CLIENT_ID,
|
||||
CLIENT_SECRET,
|
||||
SCOPE
|
||||
SCOPE,
|
||||
AUDIENCE,
|
||||
RESOURCE
|
||||
);
|
||||
|
||||
// Check the request to fetch the token
|
||||
@ -130,6 +142,8 @@ describe('client_credentials', () => {
|
||||
params: [
|
||||
{ name: 'grant_type', value: 'client_credentials' },
|
||||
{ name: 'scope', value: SCOPE },
|
||||
{ name: 'audience', value: AUDIENCE },
|
||||
{ name: 'resource', value: RESOURCE },
|
||||
{ name: 'client_id', value: CLIENT_ID },
|
||||
{ name: 'client_secret', value: CLIENT_SECRET }
|
||||
]
|
||||
@ -154,6 +168,8 @@ describe('client_credentials', () => {
|
||||
expires_in: null,
|
||||
token_type: 'token_type',
|
||||
scope: SCOPE,
|
||||
audience: AUDIENCE,
|
||||
resource: RESOURCE,
|
||||
error: null,
|
||||
error_uri: null,
|
||||
error_description: null,
|
||||
|
@ -13,6 +13,7 @@ export const P_ACCESS_TOKEN = 'access_token';
|
||||
export const P_CLIENT_ID = 'client_id';
|
||||
export const P_CLIENT_SECRET = 'client_secret';
|
||||
export const P_AUDIENCE = 'audience';
|
||||
export const P_RESOURCE = 'resource';
|
||||
export const P_CODE = 'code';
|
||||
export const P_NONCE = 'nonce';
|
||||
export const P_ERROR = 'error';
|
||||
|
@ -30,17 +30,9 @@ export default async function(
|
||||
): Promise<OAuth2Token | null> {
|
||||
switch (authentication.grantType) {
|
||||
case GRANT_TYPE_AUTHORIZATION_CODE:
|
||||
return _getOAuth2AuthorizationCodeHeader(
|
||||
requestId,
|
||||
authentication,
|
||||
forceRefresh
|
||||
);
|
||||
return _getOAuth2AuthorizationCodeHeader(requestId, authentication, forceRefresh);
|
||||
case GRANT_TYPE_CLIENT_CREDENTIALS:
|
||||
return _getOAuth2ClientCredentialsHeader(
|
||||
requestId,
|
||||
authentication,
|
||||
forceRefresh
|
||||
);
|
||||
return _getOAuth2ClientCredentialsHeader(requestId, authentication, forceRefresh);
|
||||
case GRANT_TYPE_IMPLICIT:
|
||||
return _getOAuth2ImplicitHeader(requestId, authentication, forceRefresh);
|
||||
case GRANT_TYPE_PASSWORD:
|
||||
@ -55,11 +47,7 @@ async function _getOAuth2AuthorizationCodeHeader(
|
||||
authentication: RequestAuthentication,
|
||||
forceRefresh: boolean
|
||||
): Promise<OAuth2Token | null> {
|
||||
const oAuth2Token = await _getAccessToken(
|
||||
requestId,
|
||||
authentication,
|
||||
forceRefresh
|
||||
);
|
||||
const oAuth2Token = await _getAccessToken(requestId, authentication, forceRefresh);
|
||||
|
||||
if (oAuth2Token) {
|
||||
return oAuth2Token;
|
||||
@ -85,11 +73,7 @@ async function _getOAuth2ClientCredentialsHeader(
|
||||
authentication: RequestAuthentication,
|
||||
forceRefresh: boolean
|
||||
): Promise<OAuth2Token | null> {
|
||||
const oAuth2Token = await _getAccessToken(
|
||||
requestId,
|
||||
authentication,
|
||||
forceRefresh
|
||||
);
|
||||
const oAuth2Token = await _getAccessToken(requestId, authentication, forceRefresh);
|
||||
|
||||
if (oAuth2Token) {
|
||||
return oAuth2Token;
|
||||
@ -102,7 +86,8 @@ async function _getOAuth2ClientCredentialsHeader(
|
||||
authentication.clientId,
|
||||
authentication.clientSecret,
|
||||
authentication.scope,
|
||||
authentication.audience
|
||||
authentication.audience,
|
||||
authentication.resource
|
||||
);
|
||||
|
||||
return _updateOAuth2Token(requestId, results);
|
||||
@ -113,11 +98,7 @@ async function _getOAuth2ImplicitHeader(
|
||||
authentication: RequestAuthentication,
|
||||
forceRefresh: boolean
|
||||
): Promise<OAuth2Token | null> {
|
||||
const oAuth2Token = await _getAccessToken(
|
||||
requestId,
|
||||
authentication,
|
||||
forceRefresh
|
||||
);
|
||||
const oAuth2Token = await _getAccessToken(requestId, authentication, forceRefresh);
|
||||
|
||||
if (oAuth2Token) {
|
||||
return oAuth2Token;
|
||||
@ -142,11 +123,7 @@ async function _getOAuth2PasswordHeader(
|
||||
authentication: RequestAuthentication,
|
||||
forceRefresh: boolean
|
||||
): Promise<OAuth2Token | null> {
|
||||
const oAuth2Token = await _getAccessToken(
|
||||
requestId,
|
||||
authentication,
|
||||
forceRefresh
|
||||
);
|
||||
const oAuth2Token = await _getAccessToken(requestId, authentication, forceRefresh);
|
||||
|
||||
if (oAuth2Token) {
|
||||
return oAuth2Token;
|
||||
@ -175,9 +152,7 @@ async function _getAccessToken(
|
||||
// See if we have a token already //
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
let token: OAuth2Token | null = await models.oAuth2Token.getByParentId(
|
||||
requestId
|
||||
);
|
||||
let token: OAuth2Token | null = await models.oAuth2Token.getByParentId(requestId);
|
||||
|
||||
if (!token) {
|
||||
return null;
|
||||
@ -222,10 +197,7 @@ async function _getAccessToken(
|
||||
return _updateOAuth2Token(requestId, refreshResults);
|
||||
}
|
||||
|
||||
async function _updateOAuth2Token(
|
||||
requestId: string,
|
||||
authResults: Object
|
||||
): Promise<OAuth2Token> {
|
||||
async function _updateOAuth2Token(requestId: string, authResults: Object): Promise<OAuth2Token> {
|
||||
const oAuth2Token = await models.oAuth2Token.getOrCreateByParentId(requestId);
|
||||
|
||||
// Calculate expiry date
|
||||
|
@ -13,15 +13,15 @@ export default async function(
|
||||
clientId: string,
|
||||
clientSecret: string,
|
||||
scope: string = '',
|
||||
audience: string = ''
|
||||
audience: string = '',
|
||||
resource: string = ''
|
||||
): Promise<Object> {
|
||||
const params = [
|
||||
{ name: c.P_GRANT_TYPE, value: c.GRANT_TYPE_CLIENT_CREDENTIALS }
|
||||
];
|
||||
const params = [{ name: c.P_GRANT_TYPE, value: c.GRANT_TYPE_CLIENT_CREDENTIALS }];
|
||||
|
||||
// Add optional params
|
||||
scope && params.push({ name: c.P_SCOPE, value: scope });
|
||||
audience && params.push({ name: c.P_AUDIENCE, value: audience });
|
||||
resource && params.push({ name: c.P_RESOURCE, value: resource });
|
||||
|
||||
const headers = [
|
||||
{ name: 'Content-Type', value: 'application/x-www-form-urlencoded' },
|
||||
@ -70,6 +70,8 @@ export default async function(
|
||||
c.P_TOKEN_TYPE,
|
||||
c.P_EXPIRES_IN,
|
||||
c.P_SCOPE,
|
||||
c.P_AUDIENCE,
|
||||
c.P_RESOURCE,
|
||||
c.P_ERROR,
|
||||
c.P_ERROR_URI,
|
||||
c.P_ERROR_DESCRIPTION
|
||||
|
@ -71,9 +71,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
this.setState({ showAdvanced });
|
||||
}
|
||||
|
||||
async _handleUpdateAccessToken(
|
||||
e: SyntheticEvent<HTMLInputElement>
|
||||
): Promise<void> {
|
||||
async _handleUpdateAccessToken(e: SyntheticEvent<HTMLInputElement>): Promise<void> {
|
||||
const { oAuth2Token } = this.props;
|
||||
const accessToken = e.currentTarget.value;
|
||||
|
||||
@ -87,9 +85,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
async _handleUpdateRefreshToken(
|
||||
e: SyntheticEvent<HTMLInputElement>
|
||||
): Promise<void> {
|
||||
async _handleUpdateRefreshToken(e: SyntheticEvent<HTMLInputElement>): Promise<void> {
|
||||
const { oAuth2Token } = this.props;
|
||||
const refreshToken = e.currentTarget.value;
|
||||
|
||||
@ -104,9 +100,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
async _handleClearTokens(): Promise<void> {
|
||||
const oAuth2Token = await models.oAuth2Token.getByParentId(
|
||||
this.props.request._id
|
||||
);
|
||||
const oAuth2Token = await models.oAuth2Token.getByParentId(this.props.request._id);
|
||||
if (oAuth2Token) {
|
||||
await models.oAuth2Token.remove(oAuth2Token);
|
||||
}
|
||||
@ -129,9 +123,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
const { request } = this.props;
|
||||
|
||||
try {
|
||||
const authentication = await this.props.handleRender(
|
||||
request.authentication
|
||||
);
|
||||
const authentication = await this.props.handleRender(request.authentication);
|
||||
await getAccessToken(request._id, authentication, true);
|
||||
this.setState({ loading: false });
|
||||
} catch (err) {
|
||||
@ -157,10 +149,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
_handleChangeCredentialsInBody(e: SyntheticEvent<HTMLInputElement>): void {
|
||||
this._handleChangeProperty(
|
||||
'credentialsInBody',
|
||||
e.currentTarget.value === 'true'
|
||||
);
|
||||
this._handleChangeProperty('credentialsInBody', e.currentTarget.value === 'true');
|
||||
}
|
||||
|
||||
_handleChangeEnabled(value: boolean): void {
|
||||
@ -207,6 +196,10 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
this._handleChangeProperty('audience', value);
|
||||
}
|
||||
|
||||
_handleChangeResource(value: string): void {
|
||||
this._handleChangeProperty('resource', value);
|
||||
}
|
||||
|
||||
_handleChangeGrantType(e: SyntheticEvent<HTMLInputElement>): void {
|
||||
this._handleChangeProperty('grantType', e.currentTarget.value);
|
||||
}
|
||||
@ -248,18 +241,10 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
help: string | null = null,
|
||||
handleAutocomplete: Function | null = null
|
||||
): React.Element<*> {
|
||||
const {
|
||||
handleRender,
|
||||
handleGetRenderContext,
|
||||
request,
|
||||
nunjucksPowerUserMode
|
||||
} = this.props;
|
||||
const { handleRender, handleGetRenderContext, request, nunjucksPowerUserMode } = this.props;
|
||||
const { authentication } = request;
|
||||
const id = label.replace(/ /g, '-');
|
||||
const type =
|
||||
!this.props.showPasswords && property === 'password'
|
||||
? 'password'
|
||||
: 'text';
|
||||
const type = !this.props.showPasswords && property === 'password' ? 'password' : 'text';
|
||||
return (
|
||||
<tr key={id}>
|
||||
<td className="pad-right no-wrap valign-middle">
|
||||
@ -270,12 +255,9 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
</td>
|
||||
<td className="wide">
|
||||
<div
|
||||
className={classnames(
|
||||
'form-control form-control--underlined no-margin',
|
||||
{
|
||||
'form-control--inactive': authentication.disabled
|
||||
}
|
||||
)}>
|
||||
className={classnames('form-control form-control--underlined no-margin', {
|
||||
'form-control--inactive': authentication.disabled
|
||||
})}>
|
||||
<OneLineEditor
|
||||
id={id}
|
||||
type={type}
|
||||
@ -316,12 +298,9 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
</td>
|
||||
<td className="wide">
|
||||
<div
|
||||
className={classnames(
|
||||
'form-control form-control--outlined no-margin',
|
||||
{
|
||||
'form-control--inactive': authentication.disabled
|
||||
}
|
||||
)}>
|
||||
className={classnames('form-control form-control--outlined no-margin', {
|
||||
'form-control--inactive': authentication.disabled
|
||||
})}>
|
||||
<select id={id} onChange={onChange} value={value}>
|
||||
{options.map(({ name, value }) => (
|
||||
<option key={value} value={value}>
|
||||
@ -341,11 +320,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
let basicFields = [];
|
||||
let advancedFields = [];
|
||||
|
||||
const clientId = this.renderInputRow(
|
||||
'Client ID',
|
||||
'clientId',
|
||||
this._handleChangeClientId
|
||||
);
|
||||
const clientId = this.renderInputRow('Client ID', 'clientId', this._handleChangeClientId);
|
||||
|
||||
const clientSecret = this.renderInputRow(
|
||||
'Client Secret',
|
||||
@ -378,29 +353,13 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
'redirected URL'
|
||||
);
|
||||
|
||||
const state = this.renderInputRow(
|
||||
'State',
|
||||
'state',
|
||||
this._handleChangeState
|
||||
);
|
||||
const state = this.renderInputRow('State', 'state', this._handleChangeState);
|
||||
|
||||
const scope = this.renderInputRow(
|
||||
'Scope',
|
||||
'scope',
|
||||
this._handleChangeScope
|
||||
);
|
||||
const scope = this.renderInputRow('Scope', 'scope', this._handleChangeScope);
|
||||
|
||||
const username = this.renderInputRow(
|
||||
'Username',
|
||||
'username',
|
||||
this._handleChangeUsername
|
||||
);
|
||||
const username = this.renderInputRow('Username', 'username', this._handleChangeUsername);
|
||||
|
||||
const password = this.renderInputRow(
|
||||
'Password',
|
||||
'password',
|
||||
this._handleChangePassword
|
||||
);
|
||||
const password = this.renderInputRow('Password', 'password', this._handleChangePassword);
|
||||
|
||||
const tokenPrefix = this.renderInputRow(
|
||||
'Header Prefix',
|
||||
@ -428,6 +387,13 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
'Indicate what resource server to access'
|
||||
);
|
||||
|
||||
const resource = this.renderInputRow(
|
||||
'Resource',
|
||||
'resource',
|
||||
this._handleChangeResource,
|
||||
'Indicate what resource to access'
|
||||
);
|
||||
|
||||
const credentialsInBody = this.renderSelectRow(
|
||||
'Credentials',
|
||||
'credentialsInBody',
|
||||
@ -455,16 +421,9 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
} else if (grantType === GRANT_TYPE_CLIENT_CREDENTIALS) {
|
||||
basicFields = [accessTokenUrl, clientId, clientSecret, enabled];
|
||||
|
||||
advancedFields = [scope, credentialsInBody, tokenPrefix, audience];
|
||||
advancedFields = [scope, credentialsInBody, tokenPrefix, audience, resource];
|
||||
} else if (grantType === GRANT_TYPE_PASSWORD) {
|
||||
basicFields = [
|
||||
username,
|
||||
password,
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
enabled
|
||||
];
|
||||
basicFields = [username, password, accessTokenUrl, clientId, clientSecret, enabled];
|
||||
|
||||
advancedFields = [scope, credentialsInBody, tokenPrefix];
|
||||
} else if (grantType === GRANT_TYPE_IMPLICIT) {
|
||||
@ -476,9 +435,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
return { basic: basicFields, advanced: advancedFields };
|
||||
}
|
||||
|
||||
static renderExpireAt(
|
||||
token: OAuth2Token | null
|
||||
): React.Element<*> | string | null {
|
||||
static renderExpireAt(token: OAuth2Token | null): React.Element<*> | string | null {
|
||||
if (!token || !token.accessToken) {
|
||||
return null;
|
||||
}
|
||||
@ -509,10 +466,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
|
||||
const errorUriButton =
|
||||
oAuth2Token && oAuth2Token.errorUri ? (
|
||||
<Link
|
||||
href={oAuth2Token.errorUri}
|
||||
title={oAuth2Token.errorUri}
|
||||
className="space-left icon">
|
||||
<Link href={oAuth2Token.errorUri} title={oAuth2Token.errorUri} className="space-left icon">
|
||||
<i className="fa fa-question-circle" />
|
||||
</Link>
|
||||
) : null;
|
||||
@ -584,9 +538,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="notice subtle margin-top text-left">
|
||||
{error && (
|
||||
<p className="selectable notice warning margin-bottom">{error}</p>
|
||||
)}
|
||||
{error && <p className="selectable notice warning margin-bottom">{error}</p>}
|
||||
{this.renderError()}
|
||||
<div className="form-control form-control--outlined">
|
||||
<label>
|
||||
@ -610,9 +562,7 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
|
||||
</div>
|
||||
<div className="pad-top text-right">
|
||||
{tok ? (
|
||||
<PromptButton
|
||||
className="btn btn--clicky"
|
||||
onClick={this._handleClearTokens}>
|
||||
<PromptButton className="btn btn--clicky" onClick={this._handleClearTokens}>
|
||||
Clear
|
||||
</PromptButton>
|
||||
) : null}
|
||||
|
Loading…
Reference in New Issue
Block a user