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

Commit

Permalink
Integrate wrapping in generic secret backend
Browse files Browse the repository at this point in the history
  • Loading branch information
Matteo Sessa committed Feb 18, 2017
1 parent 21616a4 commit ac71bb6
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 38 deletions.
8 changes: 5 additions & 3 deletions app/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import Health from './components/Health/Health.jsx';
import PolicyManager from './components/Policies/Manage.jsx';
import Settings from './components/Settings/Settings.jsx';
import ResponseWrapper from './components/ResponseWrapper/ResponseWrapper.jsx';
import TokenAuthBackend from './components/Authentication/Token/Token.jsx'
import AwsEc2AuthBackend from './components/Authentication/AwsEc2/AwsEc2.jsx'
import GithubAuthBackend from './components/Authentication/Github/Github.jsx'
import TokenAuthBackend from './components/Authentication/Token/Token.jsx';
import AwsEc2AuthBackend from './components/Authentication/AwsEc2/AwsEc2.jsx';
import GithubAuthBackend from './components/Authentication/Github/Github.jsx';
import SecretUnwrapper from './components/shared/Wrapping/Unwrapper';

injectTapEventPlugin();

Expand Down Expand Up @@ -50,6 +51,7 @@ ReactDOM.render((
<MuiThemeProvider muiTheme={muiTheme}>
<Router history={browserHistory}>
<Route path="/login" component={Login}/>
<Route path="/unwrap" component={SecretUnwrapper}/>
<Route path="/" component={App} onEnter={checkAccessToken}>
<Route path="/secrets/generic/:namespace(/**)" component={SecretsGeneric}/>
<Route path="/auth/token/:namespace" component={TokenAuthBackend}/>
Expand Down
11 changes: 6 additions & 5 deletions app/components/Authentication/Token/Token.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import _ from 'lodash';
import styles from './token.css';
import sharedStyles from '../../shared/styles.css';
import { red500, orange500, green100, green400, red300, white } from 'material-ui/styles/colors.js'
import RaisedButton from 'material-ui/RaisedButton';
import { Table, TableBody, TableFooter, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table';
Expand Down Expand Up @@ -802,7 +803,7 @@ export default class TokenAuthBackend extends React.Component {
actions={NewTokenCodeDialogActions}
>

<div className={styles.newTokenCodeEmitted}>
<div className={sharedStyles.newTokenCodeEmitted}>
<TextField
fullWidth={true}
disabled={true}
Expand All @@ -829,11 +830,11 @@ export default class TokenAuthBackend extends React.Component {
<Paper zDepth={5}>
<Tabs>
<Tab label="Manage Tokens" >
<Paper className={styles.TabInfoSection} zDepth={0}>
<Paper className={sharedStyles.TabInfoSection} zDepth={0}>
Here you can create new tokens and list active tokens.<br />
Existing tokens are represented by their respective Accessor ID.
</Paper>
<Paper className={styles.accessorListSection} zDepth={0}>
<Paper className={sharedStyles.TabContentSection} zDepth={0}>
<Toolbar>
<ToolbarGroup firstChild={true}>
<FlatButton
Expand Down Expand Up @@ -901,11 +902,11 @@ export default class TokenAuthBackend extends React.Component {
</Paper>
</Tab>
<Tab label="Manage Roles" >
<Paper className={styles.TabInfoSection} zDepth={0}>
<Paper className={sharedStyles.TabInfoSection} zDepth={0}>
Here you can create, list and edit token roles.<br />
Roles can enforce specific behaviors when creating new tokens.
</Paper>
<Paper className={styles.rolesListSection} zDepth={0}>
<Paper className={sharedStyles.TabContentSection} zDepth={0}>
<Toolbar>
<ToolbarGroup firstChild={true}>
<FlatButton
Expand Down
26 changes: 0 additions & 26 deletions app/components/Authentication/Token/token.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,6 @@ span.policiesList > div > div > div {
padding-right: 3%;
}

.newTokenCodeEmitted input {
text-align: center;
font-family: monospace !important;
font-size: 150% !important;
color: black !important;
cursor: crosshair !important;
}

.newTokenCodeEmitted {
text-align: center;
}

.accessorListSection {
padding: 10px;
}

.rolesListSection {
padding: 10px;
}

.TabInfoSection {
padding: 10px;
text-align: center;
font-style: italic;
}

.classActionDelete {
position: absolute !important;
right: 4px;
Expand Down
9 changes: 9 additions & 0 deletions app/components/Secrets/Generic/Generic.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import TextField from 'material-ui/TextField';
import { green500, green400, red500, red300, yellow500, white } from 'material-ui/styles/colors.js'
import { callVaultApi, tokenHasCapabilities } from '../../shared/VaultUtils.jsx'
import JsonEditor from '../../shared/JsonEditor.jsx';
import SecretWrapper from '../../shared/Wrapping/Wrapper.jsx'
import { browserHistory, Link } from 'react-router'


Expand Down Expand Up @@ -51,6 +52,7 @@ class GenericSecretBackend extends React.Component {
openEditObjectModal: false,
openDeleteModal: false,
deletingKey: '',
wrapPath: null,
useRootKey: window.localStorage.getItem("useRootKey") === 'true' || false,
rootKey: window.localStorage.getItem("secretsRootKey") || '',
}
Expand Down Expand Up @@ -265,6 +267,10 @@ class GenericSecretBackend extends React.Component {

renderEditObjectDialog() {
const actions = [
<FlatButton label="Wrap" primary={false} onTouchTap={() => {
this.setState({ wrapPath: this.state.currentLogicalPath });
}
} />,
<FlatButton label="Cancel" primary={true} onTouchTap={() => {
this.setState({ openEditObjectModal: false, secretContent: '' });
browserHistory.push(this.getBaseDir(this.props.location.pathname));
Expand Down Expand Up @@ -413,6 +419,9 @@ class GenericSecretBackend extends React.Component {
{this.renderEditObjectDialog()}
{this.renderNewObjectDialog()}
{this.renderDeleteConfirmationDialog()}
<SecretWrapper path={this.state.wrapPath} onModalClose={() => {
this.setState({wrapPath: null})
}}/>
<Tabs>
<Tab label="Browse Secrets" >
<Paper className={sharedStyles.TabInfoSection} zDepth={0}>
Expand Down
1 change: 0 additions & 1 deletion app/components/shared/JsonEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class JsonEditor extends React.Component {
mode: this.props.mode,
modes: this.props.modes,
schema: this.props.schema,
height: this.props.height,
onChange: this.handleInputChange,
};

Expand Down
6 changes: 3 additions & 3 deletions app/components/shared/VaultUtils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ function getCachedCapabilities(path) {
}
}

function callVaultApi(method, path, query = {}, data, headers = {}) {
function callVaultApi(method, path, query = {}, data, headers = {}, vaultToken = null, vaultUrl = null) {

var instance = axios.create({
baseURL: '/v1/',
params: { "vaultaddr": window.localStorage.getItem("vaultUrl") },
headers: { "X-Vault-Token": window.localStorage.getItem("vaultAccessToken") }
params: { "vaultaddr": vaultUrl || window.localStorage.getItem("vaultUrl") },
headers: { "X-Vault-Token": vaultToken || window.localStorage.getItem("vaultAccessToken") }
});

return instance.request({
Expand Down
58 changes: 58 additions & 0 deletions app/components/shared/Wrapping/Unwrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { PropTypes, Component } from 'react'
import _ from 'lodash';
import { callVaultApi } from '../VaultUtils.jsx'
import Dialog from 'material-ui/Dialog';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
import copy from 'copy-to-clipboard';
import FontIcon from 'material-ui/FontIcon';
import FlatButton from 'material-ui/FlatButton';
import JsonEditor from '../JsonEditor.jsx';
import styles from './unwrapper.css';

export default class SecretUnwrapper extends Component {
static propTypes = {
location: PropTypes.object,
};

constructor(props) {
super(props)

this.state = {
headerMsg: 'Displaying data wrapped with token',
editorContent: null,
error: false,
};
}



componentDidMount() {
callVaultApi('post', 'sys/wrapping/unwrap', null, null, null, this.props.location.query.token, this.props.location.query.vaultUrl)
.then((resp) => {
this.setState({
editorContent: resp.data.data
})
})
.catch((err) => {
this.setState({
headerMsg: `Server returned error ${err.response.status} while unwrapping token`,
error: true,
})
})
}

render() {
return (
<div id={styles.container}>
<div className={this.state.error ? styles.redgradient : styles.bwgradient} id={styles.cell}>
<h4>{this.state.headerMsg}</h4>
<h2>{this.props.location.query.token}</h2>
</div>
<div id={styles.content}>
{this.state.editorContent && <JsonEditor rootName={this.props.location.query.token} modes={['view']} mode={'view'} height={"500px"} value={this.state.editorContent} />}
</div>
</div>
)
}
}
87 changes: 87 additions & 0 deletions app/components/shared/Wrapping/Wrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { PropTypes, Component } from 'react'
import _ from 'lodash';
import { callVaultApi } from '../VaultUtils.jsx'
import Dialog from 'material-ui/Dialog';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
import copy from 'copy-to-clipboard';
import FontIcon from 'material-ui/FontIcon';
import FlatButton from 'material-ui/FlatButton';
import sharedStyles from '../styles.css';

export default class SecretWrapper extends Component {
static propTypes = {
path: PropTypes.string,
onReceiveResponse: PropTypes.func,
onReceiveError: PropTypes.func,
onModalClose: PropTypes.func
}

static defaultProps = {
path: null,
onReceiveResponse: () => { },
onReceiveError: () => { },
onModalClose: () => { }
}

constructor(props) {
super(props)
}

state = {
wrapInfo: {},
};

componentDidUpdate(prevProps) {
if (!_.isEqual(prevProps.path, this.props.path) && this.props.path) {
callVaultApi('get', this.props.path, null, null, { 'X-Vault-Wrap-TTL': '10m' })
.then((response) => {
this.setState({ wrapInfo: response.data.wrap_info });
this.props.onReceiveResponse(response.data.wrap_info);
})
.catch((err) => {
this.props.onReceiveError(err);
})
}
}

render() {
let vaultUrl = encodeURI(window.localStorage.getItem("vaultUrl"));
let tokenValue = '';
let urlValue = '';
if (this.state.wrapInfo) {
let loc = window.location;
tokenValue = this.state.wrapInfo.token;
urlValue = `${loc.protocol}//${loc.hostname}${(loc.port ? ":" + loc.port : "")}/unwrap?token=${tokenValue}&vaultUrl=${vaultUrl}`;
}

return (
<Dialog
title="Data has been wrapped"
modal={true}
open={!_.isEmpty(this.state.wrapInfo)}
actions={<FlatButton label="Close" primary={true} onTouchTap={() => {this.props.onModalClose(); this.setState({ wrapInfo: {} })}} />}
onRequestClose={this.props.onModalClose}
>
<div className={sharedStyles.newTokenCodeEmitted}>
<TextField
fullWidth={true}
disabled={true}
floatingLabelText="This is a single-use unwrap token to read the wrapped data"
defaultValue={tokenValue}
/>
<RaisedButton icon={<FontIcon className="fa fa-clipboard" />} label="Copy to Clipboard" onTouchTap={() => { copy(tokenValue) }} />
</div >
<div className={sharedStyles.newUrlEmitted}>
<TextField
fullWidth={true}
disabled={true}
floatingLabelText="Use this URL if you want to display the wrapped data using Vault UI"
defaultValue={urlValue}
/>
<RaisedButton icon={<FontIcon className="fa fa-clipboard" />} label="Copy to Clipboard" onTouchTap={() => { copy(urlValue) }} />
</div>
</Dialog >
)
}
}
42 changes: 42 additions & 0 deletions app/components/shared/Wrapping/unwrapper.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#container {
position: relative;
height: 100%;
width: 100%;
}

#cell {
text-align: center;
margin-bottom: 20px;
margin-top: 20px;
padding-top: 5px;
padding-bottom: 5px;
}

.bwgradient {
background: radial-gradient(circle, black, black, white);
}

.redgradient {
background: radial-gradient(circle, darkred, darkred, white);
}

#cell h4 {
color: lightgray;
text-transform: full-width;
}

#cell h2 {
font-family: monospace;
color: #c2daff;
}

#content {
/*display: inline-block;
text-align: center;
align-content: center;*/

width: 80%;
margin: 0 auto;

/*margin: auto;*/
}
22 changes: 22 additions & 0 deletions app/components/shared/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,25 @@
.listStyle span {
font-family: monospace !important;
}

.newTokenCodeEmitted {
/*text-align: center;*/
}

.newTokenCodeEmitted input {
/*text-align: center;*/
font-family: monospace !important;
font-size: 150% !important;
color: black !important;
cursor: crosshair !important;
}

.newUrlEmitted {
/*text-align: center;*/
}

.newUrlEmitted input {
font-size: 15px !important;
color: black !important;
cursor: crosshair !important;
}

0 comments on commit ac71bb6

Please sign in to comment.