Commit 6e4b854f authored by Carlos Tadeu Panato Junior's avatar Carlos Tadeu Panato Junior Committed by Saturnino Abril
Browse files

[PLT-8186] add support for ec2 instance profile authentication (#772)

parent ba5579de
......@@ -117,7 +117,9 @@ export default class EmailConnectionTestButton extends React.Component {
>
{contents}
</button>
{testMessage}
<div>
{testMessage}
</div>
</div>
</div>
</div>
......
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {testS3Connection} from 'mattermost-redux/actions/admin';
import S3ConnectionTest from './s3_connection_test.jsx';
export default connect(null, mapDispatchToProps)(S3ConnectionTest);
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
testS3Connection,
}, dispatch),
};
}
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import * as Utils from 'utils/utils.jsx';
export default class S3ConnectionTestButton extends React.Component {
static get propTypes() {
return {
config: PropTypes.object.isRequired,
getConfigFromState: PropTypes.func.isRequired,
disabled: PropTypes.bool.isRequired,
actions: PropTypes.shape({
testS3Connection: PropTypes.func.isRequired,
}).isRequired,
};
}
constructor(props) {
super(props);
this.state = {
testing: false,
success: false,
fail: null,
};
}
handleTestConnection = (e) => {
e.preventDefault();
this.setState({
testing: true,
success: false,
fail: null,
});
const config = JSON.parse(JSON.stringify(this.props.config));
this.props.getConfigFromState(config);
this.props.actions.testS3Connection(config).then(
(data) => {
if (data.error) {
let fail = data.error.message;
if (data.error.detailed_error) {
fail += ' - ' + data.error.detailed_error;
}
this.setState({
testing: false,
fail,
});
} else {
this.setState({
testing: false,
success: true,
});
}
}
);
}
render() {
let testMessage = null;
if (this.state.success) {
testMessage = (
<div className='alert alert-success'>
<i className='fa fa-check'/>
<FormattedMessage
id='admin.s3.s3Success'
defaultMessage='Connection was successful'
/>
</div>
);
} else if (this.state.fail) {
testMessage = (
<div className='alert alert-warning'>
<i className='fa fa-warning'/>
<FormattedMessage
id='admin.s3.s3Fail'
defaultMessage='Connection unsuccessful: {error}'
values={{
error: this.state.fail,
}}
/>
</div>
);
}
let contents = null;
if (this.state.testing) {
contents = (
<span>
<span className='fa fa-refresh icon--rotate'/>
{Utils.localizeMessage('admin.s3.testing', 'Testing...')}
</span>
);
} else {
contents = (
<FormattedMessage
id='admin.s3.connectionS3Test'
defaultMessage='Test Connection'
/>
);
}
return (
<div className='form-group s3-connection-test'>
<div className='col-sm-offset-4 col-sm-8'>
<div className='help-text'>
<button
className='btn btn-default'
onClick={this.handleTestConnection}
disabled={this.props.disabled}
>
{contents}
</button>
<div>
{testMessage}
</div>
</div>
</div>
</div>
);
}
}
......@@ -6,6 +6,8 @@ import {FormattedHTMLMessage, FormattedMessage} from 'react-intl';
import * as Utils from 'utils/utils.jsx';
import S3ConnectionTest from 'components/admin_console/s3_connection_test';
import AdminSettings from './admin_settings.jsx';
import BooleanSetting from './boolean_setting.jsx';
import DropdownSetting from './dropdown_setting.jsx';
......@@ -194,97 +196,97 @@ export default class StorageSettings extends AdminSettings {
disabled={this.state.driverName !== DRIVER_LOCAL}
/>
<TextSetting
id='amazonS3AccessKeyId'
id='amazonS3Bucket'
label={
<FormattedMessage
id='admin.image.amazonS3IdTitle'
defaultMessage='Amazon S3 Access Key ID:'
id='admin.image.amazonS3BucketTitle'
defaultMessage='Amazon S3 Bucket:'
/>
}
placeholder={Utils.localizeMessage('admin.image.amazonS3IdExample', 'Ex "AKIADTOVBGERKLCBV"')}
placeholder={Utils.localizeMessage('admin.image.amazonS3BucketExample', 'Ex "mattermost-media"')}
helpText={
<FormattedMessage
id='admin.image.amazonS3IdDescription'
defaultMessage='Obtain this credential from your Amazon EC2 administrator.'
id='admin.image.amazonS3BucketDescription'
defaultMessage='Name you selected for your S3 bucket in AWS.'
/>
}
value={this.state.amazonS3AccessKeyId}
value={this.state.amazonS3Bucket}
onChange={this.handleChange}
disabled={this.state.driverName !== DRIVER_S3}
/>
<TextSetting
id='amazonS3SecretAccessKey'
id='amazonS3Region'
label={
<FormattedMessage
id='admin.image.amazonS3SecretTitle'
defaultMessage='Amazon S3 Secret Access Key:'
id='admin.image.amazonS3RegionTitle'
defaultMessage='Amazon S3 Region:'
/>
}
placeholder={Utils.localizeMessage('admin.image.amazonS3SecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
placeholder={Utils.localizeMessage('admin.image.amazonS3RegionExample', 'Ex "us-east-1"')}
helpText={
<FormattedMessage
id='admin.image.amazonS3SecretDescription'
defaultMessage='Obtain this credential from your Amazon EC2 administrator.'
id='admin.image.amazonS3RegionDescription'
defaultMessage='AWS region you selected when creating your S3 bucket. If no region is set, Mattermost attempts to get the appropriate region from AWS, or sets it to "us-east-1" if none found.'
/>
}
value={this.state.amazonS3SecretAccessKey}
value={this.state.amazonS3Region}
onChange={this.handleChange}
disabled={this.state.driverName !== DRIVER_S3}
/>
<TextSetting
id='amazonS3Bucket'
id='amazonS3Endpoint'
label={
<FormattedMessage
id='admin.image.amazonS3BucketTitle'
defaultMessage='Amazon S3 Bucket:'
id='admin.image.amazonS3EndpointTitle'
defaultMessage='Amazon S3 Endpoint:'
/>
}
placeholder={Utils.localizeMessage('admin.image.amazonS3BucketExample', 'Ex "mattermost-media"')}
placeholder={Utils.localizeMessage('admin.image.amazonS3EndpointExample', 'Ex "s3.amazonaws.com"')}
helpText={
<FormattedMessage
id='admin.image.amazonS3BucketDescription'
defaultMessage='Name you selected for your S3 bucket in AWS.'
id='admin.image.amazonS3EndpointDescription'
defaultMessage='Hostname of your S3 Compatible Storage provider. Defaults to "s3.amazonaws.com".'
/>
}
value={this.state.amazonS3Bucket}
value={this.state.amazonS3Endpoint}
onChange={this.handleChange}
disabled={this.state.driverName !== DRIVER_S3}
/>
<TextSetting
id='amazonS3Region'
id='amazonS3AccessKeyId'
label={
<FormattedMessage
id='admin.image.amazonS3RegionTitle'
defaultMessage='Amazon S3 Region:'
id='admin.image.amazonS3IdTitle'
defaultMessage='Amazon S3 Access Key ID:'
/>
}
placeholder={Utils.localizeMessage('admin.image.amazonS3RegionExample', 'Ex "us-east-1"')}
placeholder={Utils.localizeMessage('admin.image.amazonS3IdExample', 'Ex "AKIADTOVBGERKLCBV"')}
helpText={
<FormattedMessage
id='admin.image.amazonS3RegionDescription'
defaultMessage='AWS region you selected when creating your S3 bucket. If no region is set, Mattermost attempts to get the appropriate region from AWS, or sets it to "us-east-1" if none found.'
<FormattedHTMLMessage
id='admin.image.amazonS3IdDescription'
defaultMessage='(Optional) Only required if you do not want to authenticate to S3 using an <a target="_blank" href="https://about.mattermost.com/default-iam-role">IAM role</a>. Enter the Access Key ID provided by your Amazon EC2 administrator.'
/>
}
value={this.state.amazonS3Region}
value={this.state.amazonS3AccessKeyId}
onChange={this.handleChange}
disabled={this.state.driverName !== DRIVER_S3}
/>
<TextSetting
id='amazonS3Endpoint'
id='amazonS3SecretAccessKey'
label={
<FormattedMessage
id='admin.image.amazonS3EndpointTitle'
defaultMessage='Amazon S3 Endpoint:'
id='admin.image.amazonS3SecretTitle'
defaultMessage='Amazon S3 Secret Access Key:'
/>
}
placeholder={Utils.localizeMessage('admin.image.amazonS3EndpointExample', 'Ex "s3.amazonaws.com"')}
placeholder={Utils.localizeMessage('admin.image.amazonS3SecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')}
helpText={
<FormattedMessage
id='admin.image.amazonS3EndpointDescription'
defaultMessage='Hostname of your S3 Compatible Storage provider. Defaults to "s3.amazonaws.com".'
id='admin.image.amazonS3SecretDescription'
defaultMessage='(Optional) The secret access key associated with your Amazon S3 Access Key ID.'
/>
}
value={this.state.amazonS3Endpoint}
value={this.state.amazonS3SecretAccessKey}
onChange={this.handleChange}
disabled={this.state.driverName !== DRIVER_S3}
/>
......@@ -325,6 +327,11 @@ export default class StorageSettings extends AdminSettings {
onChange={this.handleChange}
disabled={this.state.driverName !== DRIVER_S3}
/>
<S3ConnectionTest
config={this.props.config}
getConfigFromState={this.getConfigFromState}
disabled={this.state.driverName !== DRIVER_S3}
/>
<BooleanSetting
id='enableFileAttachments'
label={
......
......@@ -418,6 +418,10 @@
"admin.file_upload.uploadFile": "Upload",
"admin.files.images": "Images",
"admin.files.storage": "Storage",
"admin.s3.s3Success": "Connection was successful",
"admin.s3.s3Fail": "Connection unsuccessful: {error}",
"admin.s3.testing": "Testing...",
"admin.s3.connectionS3Test": "Test Connection",
"admin.general.configuration": "Configuration",
"admin.general.localization": "Localization",
"admin.general.localization.availableLocalesDescription": "Set which languages are available for users in Account Settings (leave this field blank to have all supported languages available). If you’re manually adding new languages, the <strong>Default Client Language</strong> must be added before saving this setting.<br /><br />Would like to help with translations? Join the <a href='http://translate.mattermost.com/' target='_blank'>Mattermost Translation Server</a> to contribute.",
......@@ -505,17 +509,17 @@
"admin.image.amazonS3EndpointDescription": "Hostname of your S3 Compatible Storage provider. Defaults to \"s3.amazonaws.com\".",
"admin.image.amazonS3EndpointExample": "E.g.: \"s3.amazonaws.com\"",
"admin.image.amazonS3EndpointTitle": "Amazon S3 Endpoint:",
"admin.image.amazonS3IdDescription": "Obtain this credential from your Amazon EC2 administrator.",
"admin.image.amazonS3IdDescription": "(Optional) Only required if you do not want to authenticate to S3 using an <a target='_blank' href=\"https://about.mattermost.com/default-iam-role\">IAM role</a>. Enter the Access Key ID provided by your Amazon EC2 administrator.",
"admin.image.amazonS3IdExample": "E.g.: \"AKIADTOVBGERKLCBV\"",
"admin.image.amazonS3IdTitle": "Amazon S3 Access Key ID:",
"admin.image.amazonS3RegionDescription": "AWS region you selected when creating your S3 bucket. If no region is set, Mattermost attempts to get the appropriate region from AWS, or sets it to 'us-east-1' if none found.",
"admin.image.amazonS3RegionExample": "E.g.: \"us-east-1\"",
"admin.image.amazonS3RegionTitle": "Amazon S3 Region:",
"admin.image.amazonS3SSEDescription": "When true, encrypt files in Amazon S3 using server-side encryption with Amazon S3-managed keys. See <a href=\"https://about.mattermost.com/default-server-side-encryption\">documentation</a> to learn more.",
"admin.image.amazonS3SSEDescription": "When true, encrypt files in Amazon S3 using server-side encryption with Amazon S3-managed keys. See <a href=\"https://about.mattermost.com/default-server-side-encryption\" target=\"_blank\">documentation</a> to learn more.",
"admin.image.amazonS3SSETitle": "Enable Server-Side Encryption for Amazon S3:",
"admin.image.amazonS3SSLDescription": "When false, allow insecure connections to Amazon S3. Defaults to secure connections only.",
"admin.image.amazonS3SSLTitle": "Enable Secure Amazon S3 Connections:",
"admin.image.amazonS3SecretDescription": "Obtain this credential from your Amazon EC2 administrator.",
"admin.image.amazonS3SecretDescription": "(Optional) The secret access key associated with your Amazon S3 Access Key ID.",
"admin.image.amazonS3SecretExample": "E.g.: \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"",
"admin.image.amazonS3SecretTitle": "Amazon S3 Secret Access Key:",
"admin.image.amazonS3TraceDescription": "(Development Mode) When true, log additional debugging information to the system logs.",
......
......@@ -578,6 +578,10 @@
margin-top: -15px;
}
.s3-connection-test {
margin-top: -15px;
}
.recycle-db {
margin-top: 50px !important;
}
......
......@@ -21,6 +21,7 @@ exports[`components/admin_console/email_connection_test/email_connection_test sh
values={Object {}}
/>
</button>
<div />
</div>
</div>
</div>
......@@ -47,6 +48,7 @@ exports[`components/admin_console/email_connection_test/email_connection_test sh
values={Object {}}
/>
</button>
<div />
</div>
</div>
</div>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/admin_console/s3_connection_test/s3_connection_test should match snapshot, disabled 1`] = `
<div
className="form-group s3-connection-test"
>
<div
className="col-sm-offset-4 col-sm-8"
>
<div
className="help-text"
>
<button
className="btn btn-default"
disabled={true}
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Test Connection"
id="admin.s3.connectionS3Test"
values={Object {}}
/>
</button>
<div />
</div>
</div>
</div>
`;
exports[`components/admin_console/s3_connection_test/s3_connection_test should match snapshot, enable 1`] = `
<div
className="form-group s3-connection-test"
>
<div
className="col-sm-offset-4 col-sm-8"
>
<div
className="help-text"
>
<button
className="btn btn-default"
disabled={false}
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Test Connection"
id="admin.s3.connectionS3Test"
values={Object {}}
/>
</button>
<div />
</div>
</div>
</div>
`;
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React from 'react';
import {shallow} from 'enzyme';
import S3ConnectionTestButton from 'components/admin_console/s3_connection_test/s3_connection_test.jsx';
describe('components/admin_console/s3_connection_test/s3_connection_test', () => {
test('should match snapshot, disabled', () => {
const baseProps = {
config: {},
getConfigFromState: jest.fn(),
disabled: true,
actions: {
testS3Connection: jest.fn(() => Promise.resolve({})),
},
};
const wrapper = shallow(
<S3ConnectionTestButton {...baseProps}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, enable', () => {
const baseProps = {
config: {},
getConfigFromState: jest.fn(),
disabled: false,
actions: {
testS3Connection: jest.fn(() => Promise.resolve({})),
},
};
const wrapper = shallow(
<S3ConnectionTestButton {...baseProps}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should have called handleTestConnection', () => {
const baseProps = {
config: {},
getConfigFromState: jest.fn(),
disabled: false,
actions: {
testS3Connection: jest.fn(() => Promise.resolve({})),
},
};
const wrapper = shallow(
<S3ConnectionTestButton {...baseProps}/>
);
const preventDefault = jest.fn();
wrapper.find('button').first().simulate('click', {preventDefault});
expect(baseProps.actions.testS3Connection).toHaveBeenCalledTimes(1);
});
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment