Skip to content
This repository has been archived by the owner on Mar 27, 2019. It is now read-only.

Commit

Permalink
Merge pull request #1 from Lucretius/hook-into-vault
Browse files Browse the repository at this point in the history
Hook into vault
  • Loading branch information
DJ Enriquez authored Nov 8, 2016
2 parents b349ff8 + ab316ef commit a741cc5
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 66 deletions.
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM node:slim

MAINTAINER Team Lucretius

ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /app/ && cp -a /tmp/node_modules /app/

RUN npm install --silent -g webpack

ADD . /app
WORKDIR /app

RUN webpack && npm run build

EXPOSE 8000

CMD ["npm", "run", "serve"]
6 changes: 3 additions & 3 deletions app/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ injectTapEventPlugin();
window.CustomEvent = CustomEvent;
})();

const checkAuthToken = (nextState, replace, callback) => {
let vaultAuthToken = window.localStorage.getItem('vaultAuthenticationToken');
const checkAccessToken = (nextState, replace, callback) => {
let vaultAuthToken = window.localStorage.getItem('vaultAccessToken');
if (!vaultAuthToken) {
replace(`/login`)
}
Expand All @@ -41,7 +41,7 @@ ReactDOM.render((
<MuiThemeProvider muiTheme={muiTheme}>
<Router history={browserHistory}>
<Route path="/login" component={Login}/>
<Route path="/" component={Home} onEnter={checkAuthToken}>
<Route path="/" component={Home} onEnter={checkAccessToken}>
<Route path="*" component={Home}/>
</Route>
</Router>
Expand Down
97 changes: 36 additions & 61 deletions app/components/Home/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import Health from '../Health/Health.jsx';
import Settings from '../Settings/Settings.jsx';
import Snackbar from 'material-ui/Snackbar';
import { green500, red500, yellow500 } from 'material-ui/styles/colors.js'
import axios from 'axios';

export default class Home extends React.Component {
constructor(props) {
super(props);
this.renderContent = this.renderContent.bind(this);
this.state = {
secrets: [],
snackbarMessage: '',
snackbarOpen: false,
snackbarType: 'OK'
}
super(props);
this.renderContent = this.renderContent.bind(this);
this.state = {
secrets: [],
snackbarMessage: '',
snackbarOpen: false,
snackbarType: 'OK'
}
}

componentDidMount() {
Expand All @@ -42,69 +43,43 @@ export default class Home extends React.Component {

document.addEventListener("addedKey", (e) => {
let secrets = this.state.secrets;
secrets.push({ key: e.detail.key, value: e.detail.value});
secrets.push({ key: e.detail.key, value: e.detail.value });
this.setState({
secrets: secrets
});
});

document.addEventListener("deleteKey", (e) => {
let newSecrets = _.filter(this.state.secrets, x => x.key !== e.detail.key);
let newSecrets = _.filter(this.state.secrets, x => x.key !== e.detail.key);
this.setState({
secrets: newSecrets
});
});

this.setState({
secrets: [
{
key: 'fake_aws_secret',
value: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
},
{
key: 'fake_aws_id',
value: 'AKIAIOSFODNN7EXAMPLE'
},
{
key: 'key3',
value: 'val3'
},
{
key: 'key4',
value: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
},
{
key: 'key5',
value: 'AKIAIOSFODNN7EXAMPLE'
},
{
key: 'key6',
value: 'val3'
},
{
key: 'key7',
value: 'val3'
},
{
key: 'key8',
value: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
},
{
key: 'key9',
value: 'AKIAIOSFODNN7EXAMPLE'
},
{
key: 'key10',
value: 'val3'
}
]
})
var keys = [];
axios.get(`/listsecrets?vaultaddr=${encodeURI(window.localStorage.getItem("vaultUrl"))}&token=${encodeURI(window.localStorage.getItem("vaultAccessToken"))}`)
.then((resp) => {
console.log(resp.data.data);
keys = resp.data.data.keys;


var secrets = _.map(keys, (key) => {
return {
key: key,
value: ""
}
});

this.setState({
secrets: secrets
});
})
}

renderContent() {
switch(this.props.location.pathname) {
switch (this.props.location.pathname) {
case '/secrets':
return <Secrets secrets={this.state.secrets}/>
return <Secrets secrets={this.state.secrets} />
case '/health':
return <Health/>
case '/settings':
Expand All @@ -121,7 +96,7 @@ export default class Home extends React.Component {
}
}

render () {
render() {
let messageStyle = { backgroundColor: green500 };
if (this.state.snackbarType == 'warn') {
messageStyle = { backgroundColor: yellow500 };
Expand All @@ -136,10 +111,10 @@ export default class Home extends React.Component {
open={this.state.snackbarOpen}
message={this.state.snackbarMessage}
autoHideDuration={2000}
onRequestClose={() => this.setState({snackbarOpen: false})}
/>
<Header/>
<Menu pathname={this.props.location.pathname}/>
onRequestClose={() => this.setState({ snackbarOpen: false })}
/>
<Header />
<Menu pathname={this.props.location.pathname} />
<div id={styles.content}>
{this.renderContent()}
</div>
Expand Down
30 changes: 28 additions & 2 deletions app/components/Login/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Settings from 'material-ui/svg-icons/action/settings';
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import { browserHistory } from 'react-router';
import axios from 'axios';

export default class Login extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -41,12 +42,36 @@ export default class Login extends React.Component {

validateAuthToken(e) {
if (e.keyCode === 13) {
console.log(`Validating auth token: ${this.state.authToken}`);
if (!window.localStorage.getItem("vaultUrl")) {
this.setState({errorMessage: "No Vault url specified. Click the gear to edit your Vault url"});
return;
}
window.localStorage.setItem("vaultAuthenticationToken",this.state.authToken);
window.location.href = '/';
axios.post(
'/login',
{ "VaultUrl": window.localStorage.getItem("vaultUrl"), "Creds": {"Type": "GITHUB", "Token": this.state.authToken} }
)
.then((resp) => {
// { client_token: '145a495d-dc52-4539-1de8-94e819ba1317',
// accessor: '1275f43d-1287-7df2-d17a-6956181a5238',
// policies: [ 'default', 'insp-power-user' ],
// metadata: { org: 'Openmail', username: 'djenriquez' },
// lease_duration: 3600,
// renewable: true }
let accessToken = _.get(resp, 'data.client_token');
if(accessToken) {
window.localStorage.setItem("vaultAccessToken",accessToken);
console.log(`Fetched token: ${accessToken}`);
window.location.href = '/';
} else {
//No access token returned, error
}
})
.catch((err) => {
console.error(err.stack);
//something went wrong
});

}
}

Expand Down Expand Up @@ -111,3 +136,4 @@ export default class Login extends React.Component {
);
}
}

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
},
"dependencies": {
"axios": "^0.15.2",
"body-parser": "^1.15.2",
"copy-to-clipboard": "^3.0.5",
"express": "^4.14.0",
"lodash": "^4.16.6",
"material-ui": "^0.16.1",
"react": "^15.3.2",
Expand Down
47 changes: 47 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var axios = require('axios');
var _ = require('lodash');
var routeHandler = require('./src/routeHandler');

const PORT = 8000;

var app = express();
app.set('view engine','.html');
app.use('/assets', express.static('dist'));

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));

// parse application/json
app.use(bodyParser.json());

app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});

app.listen(PORT, () => {
console.log(`Vault UI listening on: ${PORT}`);
});


app.post('/login', (req,res) => {
routeHandler.login(req, res);
});

app.get('/listsecrets', (req, res) => {
routeHandler.listSecrets(req, res);
});

app.get('/secret', (req, res) => {
routeHandler.getSecret(req, res);
})

app.get('/')

app.get('*', function(req, res) {
res.sendFile(path.join(__dirname,'/index.html'));
});
93 changes: 93 additions & 0 deletions src/routeHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
'use strict';
var axios = require('axios');
var _ = require('lodash');

/* Returned body
"auth": {
"renewable": true,
"lease_duration": 2764800,
"metadata": {
"username": "vishalnayak",
"org": "hashicorp"
},
"policies": [
"default",
"dev-policy"
],
"accessor": "f93c4b2d-18b6-2b50-7a32-0fecf88237b8",
"client_token": "1977fceb-3bfa-6c71-4d1f-b64af98ac018"
}
*/
var login = function (req, res) {
let creds = _.get(req, "body.Creds");

let endpoint = '';
let body = {}

switch (creds.Type.toLowerCase()) {
case 'github':
endpoint = '/v1/auth/github/login';
body = {
token: creds.Token
};
}
axios.post(`${_.get(req, "body.VaultUrl")}${endpoint}`, body)
.then((resp) => {
res.json(resp.data.auth);
})
.catch((err) => {
console.error(err.stack);
});
};

/* Returned body
{
"auth": null,
"data": {
"keys": ["foo", "foo/"]
},
"lease_duration": 2764800,
"lease_id": "",
"renewable": false
}
*/
var listSecrets = function (req, res) {
let endpoint = '/v1/secret?list=true';
let vaultAddr = decodeURI(req.query['vaultaddr']);
let config = { headers : { 'X-Vault-Token': decodeURI(req.query['token']) } }
console.log(`${vaultAddr}${endpoint}`);
axios.get(`${vaultAddr}${endpoint}`, config)
.then((resp) => {
res.json(resp.data);
})
.catch((err) => {
console.error(err.stack);
});
}
/* Returned body
{
"foo": "bar"
}
Query params 'secret' and 'vaultaddr' must go through encodeURI()
*/
var getSecret = function (req, res) {
let endpoint = `/v1/secret/${decodeURI(req.query['secret'])}`;
let vaultAddr = decodeURI(req.query['vaultaddr']);
let config = { headers : { 'X-Vault-Token': req.query['token'] } }

axios.get(`${vaultAddr}${endpoint}`, config)
.then((resp) => {
res.json(resp.data.data);
})
.catch((err) => {
console.error(err.stack);
});
}

module.exports = (function () {
return {
login: login,
listSecrets: listSecrets,
getSecret: getSecret
}
})();

0 comments on commit a741cc5

Please sign in to comment.