mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
573 lines
26 KiB
JavaScript
573 lines
26 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
import React from 'react';
|
|
|
|
import AdminSettings from './admin_settings.jsx';
|
|
import BooleanSetting from './boolean_setting.jsx';
|
|
import TextSetting from './text_setting.jsx';
|
|
import FileUploadSetting from './file_upload_setting.jsx';
|
|
import RemoveFileSetting from './remove_file_setting.jsx';
|
|
|
|
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
|
|
import SettingsGroup from './settings_group.jsx';
|
|
|
|
import * as Utils from 'utils/utils.jsx';
|
|
|
|
import {samlCertificateStatus, uploadCertificateFile, removeCertificateFile} from 'actions/admin_actions.jsx';
|
|
|
|
export default class SamlSettings extends AdminSettings {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.getConfigFromState = this.getConfigFromState.bind(this);
|
|
|
|
this.renderSettings = this.renderSettings.bind(this);
|
|
this.uploadCertificate = this.uploadCertificate.bind(this);
|
|
this.removeCertificate = this.removeCertificate.bind(this);
|
|
}
|
|
|
|
getConfigFromState(config) {
|
|
config.SamlSettings.Enable = this.state.enable;
|
|
config.SamlSettings.Verify = this.state.verify;
|
|
config.SamlSettings.Encrypt = this.state.encrypt;
|
|
config.SamlSettings.IdpUrl = this.state.idpUrl;
|
|
config.SamlSettings.IdpDescriptorUrl = this.state.idpDescriptorUrl;
|
|
config.SamlSettings.AssertionConsumerServiceURL = this.state.assertionConsumerServiceURL;
|
|
config.SamlSettings.IdpCertificateFile = this.state.idpCertificateFile;
|
|
config.SamlSettings.PublicCertificateFile = this.state.publicCertificateFile;
|
|
config.SamlSettings.PrivateKeyFile = this.state.privateKeyFile;
|
|
config.SamlSettings.FirstNameAttribute = this.state.firstNameAttribute;
|
|
config.SamlSettings.LastNameAttribute = this.state.lastNameAttribute;
|
|
config.SamlSettings.EmailAttribute = this.state.emailAttribute;
|
|
config.SamlSettings.UsernameAttribute = this.state.usernameAttribute;
|
|
config.SamlSettings.NicknameAttribute = this.state.nicknameAttribute;
|
|
config.SamlSettings.PositionAttribute = this.state.positionAttribute;
|
|
config.SamlSettings.LocaleAttribute = this.state.localeAttribute;
|
|
config.SamlSettings.LoginButtonText = this.state.loginButtonText;
|
|
|
|
return config;
|
|
}
|
|
|
|
getStateFromConfig(config) {
|
|
const settings = config.SamlSettings;
|
|
|
|
return {
|
|
enable: settings.Enable,
|
|
verify: settings.Verify,
|
|
encrypt: settings.Encrypt,
|
|
idpUrl: settings.IdpUrl,
|
|
idpDescriptorUrl: settings.IdpDescriptorUrl,
|
|
assertionConsumerServiceURL: settings.AssertionConsumerServiceURL,
|
|
idpCertificateFile: settings.IdpCertificateFile,
|
|
publicCertificateFile: settings.PublicCertificateFile,
|
|
privateKeyFile: settings.PrivateKeyFile,
|
|
firstNameAttribute: settings.FirstNameAttribute,
|
|
lastNameAttribute: settings.LastNameAttribute,
|
|
emailAttribute: settings.EmailAttribute,
|
|
usernameAttribute: settings.UsernameAttribute,
|
|
nicknameAttribute: settings.NicknameAttribute,
|
|
positionAttribute: settings.PositionAttribute,
|
|
localeAttribute: settings.LocaleAttribute,
|
|
loginButtonText: settings.LoginButtonText
|
|
};
|
|
}
|
|
|
|
componentWillMount() {
|
|
samlCertificateStatus(
|
|
(data) => {
|
|
const files = {};
|
|
if (!data.IdpCertificateFile) {
|
|
files.idpCertificateFile = '';
|
|
}
|
|
|
|
if (!data.PublicCertificateFile) {
|
|
files.publicCertificateFile = '';
|
|
}
|
|
|
|
if (!data.PrivateKeyFile) {
|
|
files.privateKeyFile = '';
|
|
}
|
|
this.setState(files);
|
|
}
|
|
);
|
|
}
|
|
|
|
uploadCertificate(id, file, callback) {
|
|
uploadCertificateFile(
|
|
file,
|
|
() => {
|
|
const fileName = file.name;
|
|
this.handleChange(id, fileName);
|
|
this.setState({[id]: fileName, [`${id}Error`]: null});
|
|
if (callback && typeof callback === 'function') {
|
|
callback();
|
|
}
|
|
},
|
|
(error) => {
|
|
if (callback && typeof callback === 'function') {
|
|
callback(error.message);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
removeCertificate(id, callback) {
|
|
removeCertificateFile(
|
|
this.state[id],
|
|
() => {
|
|
this.handleChange(id, '');
|
|
this.setState({[id]: null, [`${id}Error`]: null});
|
|
},
|
|
(error) => {
|
|
if (callback && typeof callback === 'function') {
|
|
callback();
|
|
}
|
|
this.setState({[id]: null, [`${id}Error`]: error.message});
|
|
}
|
|
);
|
|
}
|
|
|
|
renderTitle() {
|
|
return (
|
|
<FormattedMessage
|
|
id='admin.authentication.saml'
|
|
defaultMessage='SAML'
|
|
/>
|
|
);
|
|
}
|
|
|
|
renderSettings() {
|
|
const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.SAML === 'true';
|
|
if (!licenseEnabled) {
|
|
return null;
|
|
}
|
|
|
|
let idpCert;
|
|
let privKey;
|
|
let pubCert;
|
|
|
|
if (this.state.idpCertificateFile) {
|
|
idpCert = (
|
|
<RemoveFileSetting
|
|
id='idpCertificateFile'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.idpCertificateFileTitle'
|
|
defaultMessage='Identity Provider Public Certificate:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.idpCertificateFileRemoveDesc'
|
|
defaultMessage='Remove the public authentication certificate issued by your Identity Provider.'
|
|
/>
|
|
}
|
|
removeButtonText={Utils.localizeMessage('admin.saml.remove.idp_certificate', 'Remove Identity Provider Certificate')}
|
|
removingText={Utils.localizeMessage('admin.saml.removing.certificate', 'Removing Certificate...')}
|
|
fileName={this.state.idpCertificateFile}
|
|
onSubmit={this.removeCertificate}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
);
|
|
} else {
|
|
idpCert = (
|
|
<FileUploadSetting
|
|
id='idpCertificateFile'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.idpCertificateFileTitle'
|
|
defaultMessage='Identity Provider Public Certificate:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.idpCertificateFileDesc'
|
|
defaultMessage='The public authentication certificate issued by your Identity Provider.'
|
|
/>
|
|
}
|
|
uploadingText={Utils.localizeMessage('admin.saml.uploading.certificate', 'Uploading Certificate...')}
|
|
disabled={!this.state.enable}
|
|
fileType='.crt,.cer'
|
|
onSubmit={this.uploadCertificate}
|
|
error={this.state.idpCertificateFileError}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (this.state.privateKeyFile) {
|
|
privKey = (
|
|
<RemoveFileSetting
|
|
id='privateKeyFile'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.privateKeyFileTitle'
|
|
defaultMessage='Service Provider Private Key:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.privateKeyFileFileRemoveDesc'
|
|
defaultMessage='Remove the private key used to decrypt SAML Assertions from the Identity Provider.'
|
|
/>
|
|
}
|
|
removeButtonText={Utils.localizeMessage('admin.saml.remove.privKey', 'Remove Service Provider Private Key')}
|
|
removingText={Utils.localizeMessage('admin.saml.removing.privKey', 'Removing Private Key...')}
|
|
fileName={this.state.privateKeyFile}
|
|
onSubmit={this.removeCertificate}
|
|
disabled={!this.state.enable || !this.state.encrypt}
|
|
/>
|
|
);
|
|
} else {
|
|
privKey = (
|
|
<FileUploadSetting
|
|
id='privateKeyFile'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.privateKeyFileTitle'
|
|
defaultMessage='Service Provider Private Key:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.privateKeyFileFileDesc'
|
|
defaultMessage='The private key used to decrypt SAML Assertions from the Identity Provider.'
|
|
/>
|
|
}
|
|
uploadingText={Utils.localizeMessage('admin.saml.uploading.privateKey', 'Uploading Private Key...')}
|
|
disabled={!this.state.enable || !this.state.encrypt}
|
|
fileType='.key'
|
|
onSubmit={this.uploadCertificate}
|
|
error={this.state.privateKeyFileError}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (this.state.publicCertificateFile) {
|
|
pubCert = (
|
|
<RemoveFileSetting
|
|
id='publicCertificateFile'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.publicCertificateFileTitle'
|
|
defaultMessage='Service Provider Public Certificate:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.publicCertificateFileRemoveDesc'
|
|
defaultMessage='Remove the certificate used to generate the signature on a SAML request to the Identity Provider for a service provider initiated SAML login, when Mattermost is the Service Provider.'
|
|
/>
|
|
}
|
|
removeButtonText={Utils.localizeMessage('admin.saml.remove.sp_certificate', 'Remove Service Provider Certificate')}
|
|
removingText={Utils.localizeMessage('admin.saml.removing.certificate', 'Removing Certificate...')}
|
|
fileName={this.state.publicCertificateFile}
|
|
onSubmit={this.removeCertificate}
|
|
disabled={!this.state.enable || !this.state.encrypt}
|
|
/>
|
|
);
|
|
} else {
|
|
pubCert = (
|
|
<FileUploadSetting
|
|
id='publicCertificateFile'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.publicCertificateFileTitle'
|
|
defaultMessage='Service Provider Public Certificate:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.publicCertificateFileDesc'
|
|
defaultMessage='The certificate used to generate the signature on a SAML request to the Identity Provider for a service provider initiated SAML login, when Mattermost is the Service Provider.'
|
|
/>
|
|
}
|
|
uploadingText={Utils.localizeMessage('admin.saml.uploading.certificate', 'Uploading Certificate...')}
|
|
disabled={!this.state.enable || !this.state.encrypt}
|
|
fileType='.crt,.cer'
|
|
onSubmit={this.uploadCertificate}
|
|
error={this.state.publicCertificateFileError}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<SettingsGroup>
|
|
<div className='banner'>
|
|
<div className='banner__content'>
|
|
<FormattedHTMLMessage
|
|
id='admin.saml.bannerDesc'
|
|
defaultMessage='User attributes in SAML server, including user deactivation or removal, are updated in Mattermost during user login. Learn more at: <a href=\"https://docs.mattermost.com/deployment/sso-saml.html\">https://docs.mattermost.com/deployment/sso-saml.html</a>'
|
|
/>
|
|
</div>
|
|
</div>
|
|
<BooleanSetting
|
|
id='enable'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.enableTitle'
|
|
defaultMessage='Enable Login With SAML:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedHTMLMessage
|
|
id='admin.saml.enableDescription'
|
|
defaultMessage='When true, Mattermost allows login using SAML. Please see <a href="http://docs.mattermost.com/deployment/sso-saml.html" target="_blank">documentation</a> to learn more about configuring SAML for Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.enable}
|
|
onChange={this.handleChange}
|
|
/>
|
|
<TextSetting
|
|
id='idpUrl'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.idpUrlTitle'
|
|
defaultMessage='SAML SSO URL:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.idpUrlEx', 'Ex "https://idp.example.org/SAML2/SSO/Login"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.idpUrlDesc'
|
|
defaultMessage='The URL where Mattermost sends a SAML request to start login sequence.'
|
|
/>
|
|
}
|
|
value={this.state.idpUrl}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='idpDescriptorUrl'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.idpDescriptorUrlTitle'
|
|
defaultMessage='Identity Provider Issuer URL:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.idpDescriptorUrlEx', 'Ex "https://idp.example.org/SAML2/issuer"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.idpDescriptorUrlDesc'
|
|
defaultMessage='The issuer URL for the Identity Provider you use for SAML requests.'
|
|
/>
|
|
}
|
|
value={this.state.idpDescriptorUrl}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
{idpCert}
|
|
<BooleanSetting
|
|
id='verify'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.verifyTitle'
|
|
defaultMessage='Verify Signature:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.verifyDescription'
|
|
defaultMessage='When false, Mattermost will not verify that the signature sent from a SAML Response matches the Service Provider Login URL. Not recommended for production environments. For testing only.'
|
|
/>
|
|
}
|
|
value={this.state.verify}
|
|
disabled={!this.state.enable}
|
|
onChange={this.handleChange}
|
|
/>
|
|
<TextSetting
|
|
id='assertionConsumerServiceURL'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.assertionConsumerServiceURLTitle'
|
|
defaultMessage='Service Provider Login URL:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.assertionConsumerServiceURLEx', 'Ex "https://<your-mattermost-url>/login/sso/saml"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.assertionConsumerServiceURLDesc'
|
|
defaultMessage='Enter https://<your-mattermost-url>/login/sso/saml. Make sure you use HTTP or HTTPS in your URL depending on your server configuration. This field is also known as the Assertion Consumer Service URL.'
|
|
/>
|
|
}
|
|
value={this.state.assertionConsumerServiceURL}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable || !this.state.verify}
|
|
/>
|
|
<BooleanSetting
|
|
id='encrypt'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.encryptTitle'
|
|
defaultMessage='Enable Encryption:'
|
|
/>
|
|
}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.encryptDescription'
|
|
defaultMessage='When false, Mattermost will not decrypt SAML Assertions encrypted with your Service Provider Public Certificate. Not recommended for production environments. For testing only.'
|
|
/>
|
|
}
|
|
value={this.state.encrypt}
|
|
disabled={!this.state.enable}
|
|
onChange={this.handleChange}
|
|
/>
|
|
{privKey}
|
|
{pubCert}
|
|
<TextSetting
|
|
id='emailAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.emailAttrTitle'
|
|
defaultMessage='Email Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.emailAttrEx', 'Ex "Email" or "PrimaryEmail"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.emailAttrDesc'
|
|
defaultMessage='The attribute in the SAML Assertion that will be used to populate the email addresses of users in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.emailAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='usernameAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.usernameAttrTitle'
|
|
defaultMessage='Username Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.usernameAttrEx', 'Ex "Username"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.usernameAttrDesc'
|
|
defaultMessage='The attribute in the SAML Assertion that will be used to populate the username field in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.usernameAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='firstNameAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.firstnameAttrTitle'
|
|
defaultMessage='First Name Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.firstnameAttrEx', 'Ex "FirstName"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.firstnameAttrDesc'
|
|
defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the first name of users in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.firstNameAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='lastNameAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.lastnameAttrTitle'
|
|
defaultMessage='Last Name Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.lastnameAttrEx', 'Ex "LastName"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.lastnameAttrDesc'
|
|
defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the last name of users in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.lastNameAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='nicknameAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.nicknameAttrTitle'
|
|
defaultMessage='Nickname Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.nicknameAttrEx', 'Ex "Nickname"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.nicknameAttrDesc'
|
|
defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the nickname of users in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.nicknameAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='positionAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.positionAttrTitle'
|
|
defaultMessage='Position Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.positionAttrEx', 'E.g.: "Role"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.positionAttrDesc'
|
|
defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the position of users in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.positionAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='localeAttribute'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.localeAttrTitle'
|
|
defaultMessage='Preferred Language Attribute:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.localeAttrEx', 'Ex "Locale" or "PrimaryLanguage"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.localeAttrDesc'
|
|
defaultMessage='(Optional) The attribute in the SAML Assertion that will be used to populate the language of users in Mattermost.'
|
|
/>
|
|
}
|
|
value={this.state.localeAttribute}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
<TextSetting
|
|
id='loginButtonText'
|
|
label={
|
|
<FormattedMessage
|
|
id='admin.saml.loginButtonTextTitle'
|
|
defaultMessage='Login Button Text:'
|
|
/>
|
|
}
|
|
placeholder={Utils.localizeMessage('admin.saml.loginButtonTextEx', 'Ex "With OKTA"')}
|
|
helpText={
|
|
<FormattedMessage
|
|
id='admin.saml.loginButtonTextDesc'
|
|
defaultMessage='(Optional) The text that appears in the login button on the login page. Defaults to "With SAML".'
|
|
/>
|
|
}
|
|
value={this.state.loginButtonText}
|
|
onChange={this.handleChange}
|
|
disabled={!this.state.enable}
|
|
/>
|
|
</SettingsGroup>
|
|
);
|
|
}
|
|
}
|