mirror of
https://github.com/Kong/insomnia.git
synced 2026-04-20 06:07:24 -04:00
Implement Hawk Authentication (#446)
* Implement Hawk Authentication * fix the missing label of inputs * Fix PR reviews
This commit is contained in:
committed by
Gregory Schier
parent
0a796451d7
commit
2fcf98536f
@@ -139,6 +139,7 @@ export const AUTH_BASIC = 'basic';
|
||||
export const AUTH_DIGEST = 'digest';
|
||||
export const AUTH_BEARER = 'bearer';
|
||||
export const AUTH_NTLM = 'ntlm';
|
||||
export const AUTH_HAWK = 'hawk';
|
||||
export const AUTH_AWS_IAM = 'iam';
|
||||
export const AUTH_NETRC = 'netrc';
|
||||
|
||||
@@ -149,6 +150,7 @@ const authTypesMap = {
|
||||
[AUTH_BEARER]: ['Bearer', 'Bearer Token'],
|
||||
[AUTH_OAUTH_1]: ['OAuth 1', 'OAuth 1.0'],
|
||||
[AUTH_OAUTH_2]: ['OAuth 2', 'OAuth 2.0'],
|
||||
[AUTH_HAWK]: ['Hawk', 'Hawk'],
|
||||
[AUTH_AWS_IAM]: ['AWS', 'AWS IAM v4'],
|
||||
[AUTH_NETRC]: ['Netrc', 'Netrc']
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@ import {getAuthHeader} from '../network/authentication';
|
||||
|
||||
export async function exportHarWithRequest (renderedRequest, addContentLength = false) {
|
||||
let postData = '';
|
||||
const url = misc.prepareUrlForSending(renderedRequest.url);
|
||||
|
||||
if (renderedRequest.body.fileName) {
|
||||
try {
|
||||
postData = newBodyRaw(fs.readFileSync(renderedRequest.body.fileName, 'base64'));
|
||||
@@ -36,6 +38,8 @@ export async function exportHarWithRequest (renderedRequest, addContentLength =
|
||||
if (!misc.hasAuthHeader(renderedRequest.headers)) {
|
||||
const header = await getAuthHeader(
|
||||
renderedRequest._id,
|
||||
url,
|
||||
renderedRequest.method,
|
||||
renderedRequest.authentication
|
||||
);
|
||||
header && renderedRequest.headers.push(header);
|
||||
@@ -43,7 +47,7 @@ export async function exportHarWithRequest (renderedRequest, addContentLength =
|
||||
|
||||
return {
|
||||
method: renderedRequest.method,
|
||||
url: misc.prepareUrlForSending(renderedRequest.url),
|
||||
url,
|
||||
httpVersion: 'HTTP/1.1',
|
||||
cookies: getCookies(renderedRequest),
|
||||
headers: renderedRequest.headers,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import type {BaseModel} from './index';
|
||||
import {AUTH_BASIC, AUTH_DIGEST, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_NETRC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, CONTENT_TYPE_OTHER, getContentTypeFromHeaders, METHOD_GET, CONTENT_TYPE_GRAPHQL, CONTENT_TYPE_JSON, METHOD_POST} from '../common/constants';
|
||||
import {AUTH_BASIC, AUTH_DIGEST, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_2, AUTH_HAWK, AUTH_AWS_IAM, AUTH_NETRC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, CONTENT_TYPE_OTHER, getContentTypeFromHeaders, METHOD_GET, CONTENT_TYPE_GRAPHQL, CONTENT_TYPE_JSON, METHOD_POST} from '../common/constants';
|
||||
import * as db from '../common/database';
|
||||
import {getContentTypeHeader} from '../common/misc';
|
||||
import {buildFromParams, deconstructToParams} from '../common/querystring';
|
||||
@@ -116,6 +116,10 @@ export function newAuth (type: string, oldAuth: RequestAuthentication = {}): Req
|
||||
case AUTH_NETRC:
|
||||
return {type};
|
||||
|
||||
// hawk
|
||||
case AUTH_HAWK:
|
||||
return {type, algorithm: 'sha256'};
|
||||
|
||||
// Types needing no defaults
|
||||
default:
|
||||
return {type};
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {AUTH_BASIC, AUTH_BEARER, AUTH_OAUTH_2} from '../common/constants';
|
||||
import {AUTH_BASIC, AUTH_BEARER, AUTH_OAUTH_2, AUTH_HAWK} from '../common/constants';
|
||||
import {getBasicAuthHeader, getBearerAuthHeader} from '../common/misc';
|
||||
import getOAuth2Token from './o-auth-2/get-token';
|
||||
import * as Hawk from 'hawk';
|
||||
|
||||
export async function getAuthHeader (requestId, authentication) {
|
||||
export async function getAuthHeader (requestId, url, method, authentication) {
|
||||
if (authentication.disabled) {
|
||||
return null;
|
||||
}
|
||||
@@ -27,6 +28,21 @@ export async function getAuthHeader (requestId, authentication) {
|
||||
}
|
||||
}
|
||||
|
||||
if (authentication.type === AUTH_HAWK) {
|
||||
const {id, key, algorithm} = authentication;
|
||||
|
||||
const header = Hawk.client.header(
|
||||
url,
|
||||
method,
|
||||
{credentials: {id, key, algorithm}}
|
||||
);
|
||||
|
||||
return {
|
||||
name: 'Authorization',
|
||||
value: header.field
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -473,6 +473,8 @@ export function _actuallySend (
|
||||
} else {
|
||||
const authHeader = await getAuthHeader(
|
||||
renderedRequest._id,
|
||||
finalUrl,
|
||||
renderedRequest.method,
|
||||
renderedRequest.authentication
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {trackEvent} from '../../../analytics';
|
||||
import {showModal} from '../modals';
|
||||
import AlertModal from '../modals/alert-modal';
|
||||
import * as models from '../../../models';
|
||||
import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_NETRC, getAuthTypeName} from '../../../common/constants';
|
||||
import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_HAWK, AUTH_AWS_IAM, AUTH_NETRC, getAuthTypeName} from '../../../common/constants';
|
||||
|
||||
@autobind
|
||||
class AuthDropdown extends PureComponent {
|
||||
@@ -70,6 +70,7 @@ class AuthDropdown extends PureComponent {
|
||||
{this.renderAuthType(AUTH_NTLM)}
|
||||
{this.renderAuthType(AUTH_AWS_IAM)}
|
||||
{this.renderAuthType(AUTH_NETRC)}
|
||||
{this.renderAuthType(AUTH_HAWK)}
|
||||
<DropdownDivider>Other</DropdownDivider>
|
||||
{this.renderAuthType(AUTH_NONE, 'No Authentication')}
|
||||
</Dropdown>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_NETRC} from '../../../../common/constants';
|
||||
import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_HAWK, AUTH_NETRC} from '../../../../common/constants';
|
||||
import BasicAuth from './basic-auth';
|
||||
import DigestAuth from './digest-auth';
|
||||
import BearerAuth from './bearer-auth';
|
||||
import NTLMAuth from './ntlm-auth';
|
||||
import OAuth2Auth from './o-auth-2-auth';
|
||||
import HawkAuth from './hawk-auth';
|
||||
import AWSAuth from './aws-auth';
|
||||
import NetrcAuth from './netrc-auth';
|
||||
import autobind from 'autobind-decorator';
|
||||
@@ -49,6 +50,15 @@ class AuthWrapper extends PureComponent {
|
||||
showPasswords={showPasswords}
|
||||
/>
|
||||
);
|
||||
} else if (authentication.type === AUTH_HAWK) {
|
||||
return (
|
||||
<HawkAuth
|
||||
request={request}
|
||||
handleRender={handleRender}
|
||||
handleGetRenderContext={handleGetRenderContext}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
} else if (authentication.type === AUTH_OAUTH_1) {
|
||||
return (
|
||||
<div className="vertically-center text-center">
|
||||
|
||||
107
app/ui/components/editors/auth/hawk-auth.js
Normal file
107
app/ui/components/editors/auth/hawk-auth.js
Normal file
@@ -0,0 +1,107 @@
|
||||
// @flow
|
||||
import type { Request } from '../../../../models/request';
|
||||
|
||||
import React from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import OneLineEditor from '../../codemirror/one-line-editor';
|
||||
import * as misc from '../../../../common/misc';
|
||||
|
||||
@autobind
|
||||
class HawkAuth extends React.PureComponent {
|
||||
props: {
|
||||
request: Request,
|
||||
handleRender: Function,
|
||||
handleGetRenderContext: Function,
|
||||
onChange: Function
|
||||
};
|
||||
|
||||
_handleChangeProperty: Function;
|
||||
|
||||
constructor (props: any) {
|
||||
super(props);
|
||||
|
||||
this._handleChangeProperty = misc.debounce(this._handleChangeProperty, 500);
|
||||
}
|
||||
|
||||
_handleChangeProperty (property: string, value: string | boolean): void {
|
||||
const {request} = this.props;
|
||||
const authentication = Object.assign({}, request.authentication, {[property]: value});
|
||||
this.props.onChange(authentication);
|
||||
}
|
||||
|
||||
_handleChangeHawkAuthId (value: string): void {
|
||||
this._handleChangeProperty('id', value);
|
||||
}
|
||||
|
||||
_handleChangeHawkAuthKey (value: string): void {
|
||||
this._handleChangeProperty('key', value);
|
||||
}
|
||||
|
||||
_handleChangeAlgorithm (value: string): void {
|
||||
this._handleChangeProperty('algorithm', value);
|
||||
}
|
||||
|
||||
renderHawkAuthenticationFields (): Array<React.Element<*>> {
|
||||
const hawkAuthId = this.renderInputRow(
|
||||
'Hawk Auth ID',
|
||||
'id',
|
||||
this._handleChangeHawkAuthId
|
||||
);
|
||||
|
||||
const hawkAuthKey = this.renderInputRow(
|
||||
'Hawk Auth Key',
|
||||
'key',
|
||||
this._handleChangeHawkAuthKey
|
||||
);
|
||||
|
||||
const algorithm = this.renderInputRow(
|
||||
'Algorithm',
|
||||
'algorithm',
|
||||
this._handleChangeAlgorithm
|
||||
);
|
||||
|
||||
return [hawkAuthId, hawkAuthKey, algorithm];
|
||||
}
|
||||
|
||||
renderInputRow (label: string,
|
||||
property: string,
|
||||
onChange: Function): React.Element<*> {
|
||||
const {handleRender, handleGetRenderContext, request} = this.props;
|
||||
const id = label.replace(/ /g, '-');
|
||||
return (
|
||||
<tr key={id}>
|
||||
<td className="pad-right no-wrap valign-middle">
|
||||
<label htmlFor={id} className="label--small no-pad">
|
||||
{label}
|
||||
</label>
|
||||
</td>
|
||||
<td className="wide">
|
||||
<div className="form-control form-control--underlined no-margin">
|
||||
<OneLineEditor
|
||||
id={id}
|
||||
type="text"
|
||||
onChange={onChange}
|
||||
defaultValue={request.authentication[property] || ''}
|
||||
render={handleRender}
|
||||
getRenderContext={handleGetRenderContext}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
const fields = this.renderHawkAuthenticationFields();
|
||||
|
||||
return (
|
||||
<div className="pad">
|
||||
<table>
|
||||
<tbody>{fields}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default HawkAuth;
|
||||
94
package-lock.json
generated
94
package-lock.json
generated
@@ -1499,11 +1499,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
"hoek": "4.2.0"
|
||||
}
|
||||
},
|
||||
"boxen": {
|
||||
@@ -2478,11 +2478,21 @@
|
||||
"integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8="
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
|
||||
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
|
||||
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
|
||||
"requires": {
|
||||
"boom": "2.10.1"
|
||||
"boom": "5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
|
||||
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
|
||||
"requires": {
|
||||
"hoek": "4.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"crypto-browserify": {
|
||||
@@ -5610,14 +5620,14 @@
|
||||
}
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
||||
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
|
||||
"requires": {
|
||||
"boom": "2.10.1",
|
||||
"cryptiles": "2.0.5",
|
||||
"hoek": "2.16.3",
|
||||
"sntp": "1.0.9"
|
||||
"boom": "4.3.1",
|
||||
"cryptiles": "3.1.2",
|
||||
"hoek": "4.2.0",
|
||||
"sntp": "2.0.2"
|
||||
}
|
||||
},
|
||||
"highlight.js": {
|
||||
@@ -5642,9 +5652,9 @@
|
||||
}
|
||||
},
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
|
||||
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "1.2.0",
|
||||
@@ -10811,6 +10821,22 @@
|
||||
"uuid": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
}
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
|
||||
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
|
||||
"requires": {
|
||||
"boom": "2.10.1"
|
||||
}
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
|
||||
@@ -10829,6 +10855,30 @@
|
||||
"ajv": "4.11.8",
|
||||
"har-schema": "1.0.5"
|
||||
}
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
|
||||
"requires": {
|
||||
"boom": "2.10.1",
|
||||
"cryptiles": "2.0.5",
|
||||
"hoek": "2.16.3",
|
||||
"sntp": "1.0.9"
|
||||
}
|
||||
},
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11247,11 +11297,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
|
||||
"integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
"hoek": "4.2.0"
|
||||
}
|
||||
},
|
||||
"sockjs": {
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
"electron-devtools-installer": "^2.2.0",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"graphql": "^0.10.5",
|
||||
"hawk": "^6.0.2",
|
||||
"highlight.js": "^9.12.0",
|
||||
"hkdf": "^0.0.2",
|
||||
"html-entities": "^1.2.0",
|
||||
|
||||
Reference in New Issue
Block a user