diff options
author | Christopher Speller <crspeller@gmail.com> | 2016-04-07 10:38:36 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-04-07 10:38:36 -0400 |
commit | 0a2341efd208ba8a9ddd69f647b0df4286829604 (patch) | |
tree | 7ef89c6d1fd0a2fcbd48c78987b1ad95085147d9 | |
parent | 32bc97f8559a3a1b9c9237dbb3640f9eac6daf98 (diff) | |
download | chat-0a2341efd208ba8a9ddd69f647b0df4286829604.tar.gz chat-0a2341efd208ba8a9ddd69f647b0df4286829604.tar.bz2 chat-0a2341efd208ba8a9ddd69f647b0df4286829604.zip |
Adding TLS options to LDAP
-rw-r--r-- | config/config.json | 4 | ||||
-rw-r--r-- | i18n/en.json | 6 | ||||
-rw-r--r-- | model/config.go | 20 | ||||
-rw-r--r-- | webapp/components/admin_console/boolean_setting.jsx | 62 | ||||
-rw-r--r-- | webapp/components/admin_console/connection_security_dropdown_setting.jsx | 94 | ||||
-rw-r--r-- | webapp/components/admin_console/dropdown_setting.jsx | 47 | ||||
-rw-r--r-- | webapp/components/admin_console/email_settings.jsx | 76 | ||||
-rw-r--r-- | webapp/components/admin_console/ldap_settings.jsx | 32 | ||||
-rw-r--r-- | webapp/components/admin_console/setting.jsx | 28 | ||||
-rw-r--r-- | webapp/i18n/en.json | 20 |
10 files changed, 303 insertions, 86 deletions
diff --git a/config/config.json b/config/config.json index 27c697be0..d5f82674f 100644 --- a/config/config.json +++ b/config/config.json @@ -132,6 +132,7 @@ "Enable": false, "LdapServer": "", "LdapPort": 389, + "ConnectionSecurity": "", "BaseDN": "", "BindUsername": "", "BindPassword": "", @@ -141,6 +142,7 @@ "EmailAttribute": "", "UsernameAttribute": "", "IdAttribute": "", + "SkipCertificateVerification": false, "QueryTimeout": 60 }, "ComplianceSettings": { @@ -148,4 +150,4 @@ "Directory": "./data/", "EnableDaily": false } -}
\ No newline at end of file +} diff --git a/i18n/en.json b/i18n/en.json index ae473df5d..5d154001c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2244,6 +2244,10 @@ "translation": "Invalid maximum open connection for SQL settings. Must be a positive number." }, { + "id": "model.config.is_valid.ldap_security.app_error", + "translation": "Invalid connection security for LDAP settings. Must be '', 'TLS', or 'STARTTLS'" + }, + { "id": "model.file_info.get.gif.app_error", "translation": "Could not decode gif." }, @@ -3827,4 +3831,4 @@ "id": "web.watcher_fail.error", "translation": "Failed to add directory to watcher %v" } -]
\ No newline at end of file +] diff --git a/model/config.go b/model/config.go index 666b2770b..29bc536dc 100644 --- a/model/config.go +++ b/model/config.go @@ -162,12 +162,13 @@ type TeamSettings struct { type LdapSettings struct { // Basic - Enable *bool - LdapServer *string - LdapPort *int - BaseDN *string - BindUsername *string - BindPassword *string + Enable *bool + LdapServer *string + LdapPort *int + ConnectionSecurity *string + BaseDN *string + BindUsername *string + BindPassword *string // Filtering UserFilter *string @@ -180,7 +181,8 @@ type LdapSettings struct { IdAttribute *string // Advanced - QueryTimeout *int + SkipCertificateVerification *bool + QueryTimeout *int } type ComplianceSettings struct { @@ -526,6 +528,10 @@ func (o *Config) IsValid() *AppError { return NewLocAppError("Config.IsValid", "model.config.is_valid.rate_sec.app_error", nil, "") } + if !(*o.LdapSettings.ConnectionSecurity == CONN_SECURITY_NONE || *o.LdapSettings.ConnectionSecurity == CONN_SECURITY_TLS || *o.LdapSettings.ConnectionSecurity == CONN_SECURITY_STARTTLS) { + return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "") + } + return nil } diff --git a/webapp/components/admin_console/boolean_setting.jsx b/webapp/components/admin_console/boolean_setting.jsx new file mode 100644 index 000000000..99d508d68 --- /dev/null +++ b/webapp/components/admin_console/boolean_setting.jsx @@ -0,0 +1,62 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; + +import Setting from './setting.jsx'; + +import {FormattedMessage} from 'react-intl'; + +export default class BooleanSetting extends React.Component { + render() { + return ( + <Setting label={this.props.label}> + <label className='radio-inline'> + <input + type='radio' + value='true' + checked={this.props.currentValue} + onChange={this.props.handleChange} + disabled={this.props.isDisabled} + /> + {this.props.trueText} + </label> + <label className='radio-inline'> + <input + type='radio' + value='false' + checked={!this.props.currentValue} + onChange={this.props.handleChange} + disabled={this.props.isDisabled} + /> + {this.props.falseText} + </label> + {this.props.helpText} + </Setting> + ); + } +} +BooleanSetting.defaultProps = { + trueText: ( + <FormattedMessage + id='admin.ldap.true' + defaultMessage='true' + /> + ), + falseText: ( + <FormattedMessage + id='admin.ldap.false' + defaultMessage='false' + /> + ) +}; + +BooleanSetting.propTypes = { + label: React.PropTypes.node.isRequired, + currentValue: React.PropTypes.bool.isRequired, + trueText: React.PropTypes.node, + falseText: React.PropTypes.node, + isDisabled: React.PropTypes.bool.isRequired, + handleChange: React.PropTypes.func.isRequired, + helpText: React.PropTypes.node.isRequired +}; diff --git a/webapp/components/admin_console/connection_security_dropdown_setting.jsx b/webapp/components/admin_console/connection_security_dropdown_setting.jsx new file mode 100644 index 000000000..e00abf304 --- /dev/null +++ b/webapp/components/admin_console/connection_security_dropdown_setting.jsx @@ -0,0 +1,94 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; +import * as Utils from 'utils/utils.jsx'; + +import DropdownSetting from './dropdown_setting.jsx'; +import {FormattedMessage} from 'react-intl'; + +const CONNECTION_SECURITY_HELP_TEXT = ( + <div className='help-text'> + <table + className='table table-bordered' + cellPadding='5' + > + <tbody> + <tr> + <td className='help-text'> + <FormattedMessage + id='admin.connectionSecurityNone' + defaultMessage='None' + /> + </td> + <td className='help-text'> + <FormattedMessage + id='admin.connectionSecurityNoneDescription' + defaultMessage='Mattermost will connect over an unsecure connection.' + /> + </td> + </tr> + <tr> + <td className='help-text'> + <FormattedMessage + id='admin.connectionSecurityTls' + defaultMessage='TLS' + /> + </td> + <td className='help-text'> + <FormattedMessage + id='admin.connectionSecurityTlsDescription' + defaultMessage='Encrypts the communication between Mattermost and your server.' + /> + </td> + </tr> + <tr> + <td className='help-text'> + <FormattedMessage + id='admin.connectionSecurityStart' + defaultMessage='STARTTLS' + /> + </td> + <td className='help-text'> + <FormattedMessage + id='admin.connectionSecurityStartDescription' + defaultMessage='Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.' + /> + </td> + </tr> + </tbody> + </table> + </div> +); + +export default class ConnectionSecurityDropdownSetting extends React.Component { + render() { + return ( + <DropdownSetting + values={[ + {value: '', text: Utils.localizeMessage('admin.connectionSecurityNone', 'None')}, + {value: 'TLS', text: Utils.localizeMessage('admin.connectionSecurityTls', 'TLS (Recommended)')}, + {value: 'STARTTLS', text: Utils.localizeMessage('admin.connectionSecurityStart')} + ]} + label={ + <FormattedMessage + id='admin.connectionSecurityTitle' + defaultMessage='Connection Security:' + /> + } + currentValue={this.props.currentValue} + handleChange={this.props.handleChange} + isDisabled={this.props.isDisabled} + helpText={CONNECTION_SECURITY_HELP_TEXT} + /> + ); + } +} +ConnectionSecurityDropdownSetting.defaultProps = { +}; + +ConnectionSecurityDropdownSetting.propTypes = { + currentValue: React.PropTypes.string.isRequired, + handleChange: React.PropTypes.func.isRequired, + isDisabled: React.PropTypes.bool.isRequired +}; diff --git a/webapp/components/admin_console/dropdown_setting.jsx b/webapp/components/admin_console/dropdown_setting.jsx new file mode 100644 index 000000000..d96c3cef8 --- /dev/null +++ b/webapp/components/admin_console/dropdown_setting.jsx @@ -0,0 +1,47 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; + +import Setting from './setting.jsx'; + +export default class DropdownSetting extends React.Component { + render() { + const options = []; + for (const {value, text} of this.props.values) { + options.push( + <option + value={value} + key={value} + > + {text} + </option> + ); + } + + return ( + <Setting label={this.props.label}> + <select + className='form-control' + value={this.props.currentValue} + onChange={this.props.handleChange} + disabled={this.props.isDisabled} + > + {options} + </select> + {this.props.helpText} + </Setting> + ); + } +} +DropdownSetting.defaultProps = { +}; + +DropdownSetting.propTypes = { + values: React.PropTypes.array.isRequired, + label: React.PropTypes.node.isRequired, + currentValue: React.PropTypes.string.isRequired, + handleChange: React.PropTypes.func.isRequired, + isDisabled: React.PropTypes.bool.isRequired, + helpText: React.PropTypes.node.isRequired +}; diff --git a/webapp/components/admin_console/email_settings.jsx b/webapp/components/admin_console/email_settings.jsx index e591b636d..8df48b206 100644 --- a/webapp/components/admin_console/email_settings.jsx +++ b/webapp/components/admin_console/email_settings.jsx @@ -6,6 +6,7 @@ import ReactDOM from 'react-dom'; import * as Client from 'utils/client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import crypto from 'crypto'; +import ConnectionSecurityDropdownSetting from './connection_security_dropdown_setting.jsx'; import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl'; @@ -34,18 +35,6 @@ var holders = defineMessages({ id: 'admin.email.smtpPortExample', defaultMessage: 'Ex: "25", "465"' }, - connectionSecurityNone: { - id: 'admin.email.connectionSecurityNone', - defaultMessage: 'None' - }, - connectionSecurityTls: { - id: 'admin.email.connectionSecurityTls', - defaultMessage: 'TLS (Recommended)' - }, - connectionSecurityStart: { - id: 'admin.email.connectionSecurityStart', - defaultMessage: 'STARTTLS' - }, inviteSaltExample: { id: 'admin.email.inviteSaltExample', defaultMessage: 'Ex "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"' @@ -96,7 +85,8 @@ class EmailSettings extends React.Component { serverError: null, emailSuccess: null, emailFail: null, - pushNotificationContents: this.props.config.EmailSettings.PushNotificationContents + pushNotificationContents: this.props.config.EmailSettings.PushNotificationContents, + connectionSecurity: this.props.config.EmailSettings.ConnectionSecurity }; } @@ -138,7 +128,7 @@ class EmailSettings extends React.Component { config.EmailSettings.SMTPPort = ReactDOM.findDOMNode(this.refs.SMTPPort).value.trim(); config.EmailSettings.SMTPUsername = ReactDOM.findDOMNode(this.refs.SMTPUsername).value.trim(); config.EmailSettings.SMTPPassword = ReactDOM.findDOMNode(this.refs.SMTPPassword).value.trim(); - config.EmailSettings.ConnectionSecurity = ReactDOM.findDOMNode(this.refs.ConnectionSecurity).value.trim(); + config.EmailSettings.ConnectionSecurity = this.state.connectionSecurity.trim(); config.EmailSettings.InviteSalt = ReactDOM.findDOMNode(this.refs.InviteSalt).value.trim(); if (config.EmailSettings.InviteSalt === '') { @@ -703,61 +693,13 @@ class EmailSettings extends React.Component { </div> </div> + <ConnectionSecurityDropdownSetting + currentValue={this.state.connectionSecurity} + handleChange={(e) => this.setState({connectionSecurity: e.target.value, saveNeeded: true})} + isDisabled={!this.state.sendEmailNotifications} + /> <div className='form-group'> - <label - className='control-label col-sm-4' - htmlFor='ConnectionSecurity' - > - <FormattedMessage - id='admin.email.connectionSecurityTitle' - defaultMessage='Connection Security:' - /> - </label> <div className='col-sm-8'> - <select - className='form-control' - id='ConnectionSecurity' - ref='ConnectionSecurity' - defaultValue={this.props.config.EmailSettings.ConnectionSecurity} - onChange={this.handleChange} - disabled={!this.state.sendEmailNotifications} - > - <option value=''>{formatMessage(holders.connectionSecurityNone)}</option> - <option value='TLS'>{formatMessage(holders.connectionSecurityTls)}</option> - <option value='STARTTLS'>{formatMessage(holders.connectionSecurityStart)}</option> - </select> - <div className='help-text'> - <table - className='table table-bordered' - cellPadding='5' - > - <tbody> - <tr><td className='help-text'> - <FormattedMessage - id='admin.email.connectionSecurityNone' - defaultMessage='None' - /> - </td><td className='help-text'> - <FormattedMessage - id='admin.email.connectionSecurityNoneDescription' - defaultMessage='Mattermost will send email over an unsecure connection.' - /> - </td></tr> - <tr><td className='help-text'>{'TLS'}</td><td className='help-text'> - <FormattedMessage - id='admin.email.connectionSecurityTlsDescription' - defaultMessage='Encrypts the communication between Mattermost and your email server.' - /> - </td></tr> - <tr><td className='help-text'>{'STARTTLS'}</td><td className='help-text'> - <FormattedMessage - id='admin.email.connectionSecurityStartDescription' - defaultMessage='Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.' - /> - </td></tr> - </tbody> - </table> - </div> <div className='help-text'> <button className='btn btn-default' diff --git a/webapp/components/admin_console/ldap_settings.jsx b/webapp/components/admin_console/ldap_settings.jsx index 190f707b9..85651c60d 100644 --- a/webapp/components/admin_console/ldap_settings.jsx +++ b/webapp/components/admin_console/ldap_settings.jsx @@ -8,6 +8,8 @@ import * as Utils from 'utils/utils.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import {FormattedMessage, FormattedHTMLMessage} from 'react-intl'; +import ConnectionSecurityDropdownSetting from './connection_security_dropdown_setting.jsx'; +import BooleanSetting from './boolean_setting.jsx'; const DEFAULT_LDAP_PORT = 389; const DEFAULT_QUERY_TIMEOUT = 60; @@ -26,7 +28,9 @@ class LdapSettings extends React.Component { this.state = { saveNeeded: false, serverError: null, - enable: this.props.config.LdapSettings.Enable + enable: this.props.config.LdapSettings.Enable, + connectionSecurity: this.props.config.LdapSettings.ConnectionSecurity, + skipCertificateVerification: this.props.config.LdapSettings.SkipCertificateVerification }; } handleChange() { @@ -61,6 +65,8 @@ class LdapSettings extends React.Component { config.LdapSettings.UsernameAttribute = this.refs.UsernameAttribute.value.trim(); config.LdapSettings.IdAttribute = this.refs.IdAttribute.value.trim(); config.LdapSettings.UserFilter = this.refs.UserFilter.value.trim(); + config.LdapSettings.ConnectionSecurity = this.state.connectionSecurity.trim(); + config.LdapSettings.SkipCertificateVerification = this.state.skipCertificateVerification; let QueryTimeout = DEFAULT_QUERY_TIMEOUT; if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.QueryTimeout).value, 10))) { @@ -251,6 +257,11 @@ class LdapSettings extends React.Component { </p> </div> </div> + <ConnectionSecurityDropdownSetting + currentValue={this.state.connectionSecurity} + handleChange={(e) => this.setState({connectionSecurity: e.target.value, saveNeeded: true})} + isDisabled={!this.state.enable} + /> <div className='form-group'> <label className='control-label col-sm-4' @@ -512,6 +523,25 @@ class LdapSettings extends React.Component { </p> </div> </div> + <BooleanSetting + label={ + <FormattedMessage + id='admin.ldap.skipCertificateVerification' + defaultMessage='Skip Certificate Verification' + /> + } + currentValue={this.state.skipCertificateVerification} + isDisabled={!this.state.enable} + handleChange={(e) => this.setState({skipCertificateVerification: e.target.value.trim() === 'true', saveNeeded: true})} + helpText={ + <p className='help-text'> + <FormattedMessage + id='admin.ldap.skipCertificateVerificationDesc' + defaultMessage='Skips the certificate verificaiton step for TLS or STARTTLS connections. Not recommented for production enviroments where TLS is required. For testing only.' + /> + </p> + } + /> <div className='form-group'> <label className='control-label col-sm-4' diff --git a/webapp/components/admin_console/setting.jsx b/webapp/components/admin_console/setting.jsx new file mode 100644 index 000000000..3e8c59b5d --- /dev/null +++ b/webapp/components/admin_console/setting.jsx @@ -0,0 +1,28 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; + +export default class Setting extends React.Component { + render() { + return ( + <div className='form-group'> + <label + className='control-label col-sm-4' + > + {this.props.label} + </label> + <div className='col-sm-8'> + {this.props.children} + </div> + </div> + ); + } +} +Setting.defaultProps = { +}; + +Setting.propTypes = { + label: React.PropTypes.node.isRequired, + children: React.PropTypes.node.isRequired +}; diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 7914fd1c7..12671284a 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -124,14 +124,14 @@ "admin.email.allowSignupTitle": "Allow Sign Up With Email: ", "admin.email.allowUsernameSignInDescription": "When true, Mattermost allows users to sign in using their username and password. This setting is typically only used when email verification is disabled.", "admin.email.allowUsernameSignInTitle": "Allow Sign In With Username: ", - "admin.email.connectionSecurityNone": "None", - "admin.email.connectionSecurityNoneDescription": "Mattermost will send email over an unsecure connection.", - "admin.email.connectionSecurityStart": "STARTTLS", - "admin.email.connectionSecurityStartDescription": "Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.", - "admin.email.connectionSecurityTest": "Test Connection", - "admin.email.connectionSecurityTitle": "Connection Security:", - "admin.email.connectionSecurityTls": "TLS (Recommended)", - "admin.email.connectionSecurityTlsDescription": "Encrypts the communication between Mattermost and your email server.", + "admin.connectionSecurityNone": "None", + "admin.connectionSecurityNoneDescription": "Mattermost will connect over an unsecure connection.", + "admin.connectionSecurityStart": "STARTTLS", + "admin.connectionSecurityStartDescription": "Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.", + "admin.connectionSecurityTest": "Test Connection", + "admin.connectionSecurityTitle": "Connection Security:", + "admin.connectionSecurityTls": "TLS", + "admin.connectionSecurityTlsDescription": "Encrypts the communication between Mattermost and your server.", "admin.email.emailFail": "Connection unsuccessful: {error}", "admin.email.emailSettings": "Email Settings", "admin.email.emailSuccess": "No errors were reported while sending an email. Please check your inbox to make sure.", @@ -279,6 +279,8 @@ "admin.ldap.queryDesc": "The timeout value for queries to the LDAP server. Increase if you are getting timeout errors caused by a slow LDAP server.", "admin.ldap.queryEx": "Ex \"60\"", "admin.ldap.queryTitle": "Query Timeout (seconds):", + "admin.ldap.skipCertificateVerification": "Skip Vertificate Verification", + "admin.ldap.skipCertificateVerificationDesc": "Skips the certificate verificaiton step for TLS or STARTTLS connections. Not recommented for production enviroments where TLS is required. For testing only.", "admin.ldap.save": "Save", "admin.ldap.saving": "Saving Config...", "admin.ldap.serverDesc": "The domain or IP address of LDAP server.", @@ -1423,4 +1425,4 @@ "web.footer.terms": "Terms", "web.header.back": "Back", "web.root.singup_info": "All team communication in one place, searchable and accessible anywhere" -}
\ No newline at end of file +} |