diff --git a/api/oauth.go b/api/oauth.go index f64fc638de..d41f526b43 100644 --- a/api/oauth.go +++ b/api/oauth.go @@ -26,9 +26,9 @@ func InitOAuth() { BaseRoutes.OAuth.Handle("/register", ApiUserRequired(registerOAuthApp)).Methods("POST") BaseRoutes.OAuth.Handle("/allow", ApiUserRequired(allowOAuth)).Methods("GET") - BaseRoutes.OAuth.Handle("/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") - BaseRoutes.OAuth.Handle("/{service:[A-Za-z]+}/login", AppHandlerIndependent(loginWithOAuth)).Methods("GET") - BaseRoutes.OAuth.Handle("/{service:[A-Za-z]+}/signup", AppHandlerIndependent(signupWithOAuth)).Methods("GET") + BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") + BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/login", AppHandlerIndependent(loginWithOAuth)).Methods("GET") + BaseRoutes.OAuth.Handle("/{service:[A-Za-z0-9]+}/signup", AppHandlerIndependent(signupWithOAuth)).Methods("GET") BaseRoutes.OAuth.Handle("/authorize", ApiUserRequired(authorizeOAuth)).Methods("GET") BaseRoutes.OAuth.Handle("/access_token", ApiAppHandler(getAccessToken)).Methods("POST") @@ -36,9 +36,9 @@ func InitOAuth() { BaseRoutes.Root.Handle("/access_token", ApiAppHandler(getAccessToken)).Methods("POST") // Handle all the old routes, to be later removed - BaseRoutes.Root.Handle("/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") - BaseRoutes.Root.Handle("/signup/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") - BaseRoutes.Root.Handle("/login/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") + BaseRoutes.Root.Handle("/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") + BaseRoutes.Root.Handle("/signup/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") + BaseRoutes.Root.Handle("/login/{service:[A-Za-z0-9]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET") } func registerOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) { @@ -624,7 +624,7 @@ func CompleteSwitchWithOAuth(c *Context, w http.ResponseWriter, r *http.Request, provider := einterfaces.GetOauthProvider(service) if provider == nil { c.Err = model.NewLocAppError("CompleteClaimWithOAuth", "api.user.complete_switch_with_oauth.unavailable.app_error", - map[string]interface{}{"Service": service}, "") + map[string]interface{}{"Service": strings.Title(service)}, "") return } else { ssoUser := provider.GetUserFromJson(userData) diff --git a/api/user.go b/api/user.go index f9d9820481..506c0ba44e 100644 --- a/api/user.go +++ b/api/user.go @@ -280,7 +280,7 @@ func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service var user *model.User provider := einterfaces.GetOauthProvider(service) if provider == nil { - c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.not_available.app_error", map[string]interface{}{"Service": service}, "") + c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.not_available.app_error", map[string]interface{}{"Service": strings.Title(service)}, "") return nil } else { user = provider.GetUserFromJson(userData) @@ -532,7 +532,7 @@ func LoginByOAuth(c *Context, w http.ResponseWriter, r *http.Request, service st provider := einterfaces.GetOauthProvider(service) if provider == nil { c.Err = model.NewLocAppError("LoginByOAuth", "api.user.login_by_oauth.not_available.app_error", - map[string]interface{}{"Service": service}, "") + map[string]interface{}{"Service": strings.Title(service)}, "") return nil } else { authData = provider.GetAuthDataFromJson(bytes.NewReader(buf.Bytes())) diff --git a/config/config.json b/config/config.json index 8f1bea3cac..22d500c3e8 100644 --- a/config/config.json +++ b/config/config.json @@ -142,10 +142,19 @@ "Enable": false, "Secret": "", "Id": "", - "Scope": "", - "AuthEndpoint": "", - "TokenEndpoint": "", - "UserApiEndpoint": "" + "Scope": "profile email", + "AuthEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", + "TokenEndpoint": "https://www.googleapis.com/oauth2/v4/token", + "UserApiEndpoint": "https://www.googleapis.com/plus/v1/people/me" + }, + "Office365Settings": { + "Enable": false, + "Secret": "", + "Id": "", + "Scope": "User.Read", + "AuthEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", + "TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/token", + "UserApiEndpoint": "https://graph.microsoft.com/v1.0/me" }, "LdapSettings": { "Enable": false, @@ -201,4 +210,4 @@ "AndroidAppDownloadLink": "https://about.mattermost.com/mattermost-android-app/", "IosAppDownloadLink": "https://about.mattermost.com/mattermost-ios-app/" } -} \ No newline at end of file +} diff --git a/i18n/en.json b/i18n/en.json index 5fad6d4523..3e792f88a1 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1669,7 +1669,7 @@ }, { "id": "api.user.complete_switch_with_oauth.unavailable.app_error", - "translation": "{{.Service}} oauth not available on this server" + "translation": "{{.Service}} SSO through OAuth 2.0 not available on this server" }, { "id": "api.user.create_oauth_user.already_attached.app_error", @@ -1685,7 +1685,7 @@ }, { "id": "api.user.create_oauth_user.not_available.app_error", - "translation": "{{.Service}} oauth not available on this server" + "translation": "{{.Service}} SSO through OAuth 2.0 not available on this server" }, { "id": "api.user.create_profile_image.default_font.app_error", @@ -1797,7 +1797,7 @@ }, { "id": "api.user.login_by_oauth.not_available.app_error", - "translation": "{{.Service}} oauth not avlailable on this server" + "translation": "{{.Service}} SSO through OAuth 2.0 not available on this server" }, { "id": "api.user.login_by_oauth.parse.app_error", diff --git a/model/config.go b/model/config.go index 05d574cb23..4b00e835d7 100644 --- a/model/config.go +++ b/model/config.go @@ -22,8 +22,9 @@ const ( PASSWORD_MAXIMUM_LENGTH = 64 PASSWORD_MINIMUM_LENGTH = 5 - SERVICE_GITLAB = "gitlab" - SERVICE_GOOGLE = "google" + SERVICE_GITLAB = "gitlab" + SERVICE_GOOGLE = "google" + SERVICE_OFFICE365 = "office365" WEBSERVER_MODE_REGULAR = "regular" WEBSERVER_MODE_GZIP = "gzip" @@ -287,6 +288,7 @@ type Config struct { SupportSettings SupportSettings GitLabSettings SSOSettings GoogleSettings SSOSettings + Office365Settings SSOSettings LdapSettings LdapSettings ComplianceSettings ComplianceSettings LocalizationSettings LocalizationSettings @@ -309,6 +311,8 @@ func (o *Config) GetSSOService(service string) *SSOSettings { return &o.GitLabSettings case SERVICE_GOOGLE: return &o.GoogleSettings + case SERVICE_OFFICE365: + return &o.Office365Settings } return nil diff --git a/model/license.go b/model/license.go index a77a7349ad..a60695890f 100644 --- a/model/license.go +++ b/model/license.go @@ -36,6 +36,7 @@ type Features struct { LDAP *bool `json:"ldap"` MFA *bool `json:"mfa"` GoogleSSO *bool `json:"google_sso"` + Office365SSO *bool `json:"office365_sso"` Compliance *bool `json:"compliance"` CustomBrand *bool `json:"custom_brand"` MHPNS *bool `json:"mhpns"` @@ -67,7 +68,12 @@ func (f *Features) SetDefaults() { if f.GoogleSSO == nil { f.GoogleSSO = new(bool) - *f.GoogleSSO = *f.FutureFeatures + *f.GoogleSSO = true + } + + if f.Office365SSO == nil { + f.Office365SSO = new(bool) + *f.Office365SSO = true } if f.Compliance == nil { diff --git a/utils/config.go b/utils/config.go index 39dbca4d82..9710684e84 100644 --- a/utils/config.go +++ b/utils/config.go @@ -238,7 +238,6 @@ func getClientConfig(c *model.Config) map[string]string { props["RequireEmailVerification"] = strconv.FormatBool(c.EmailSettings.RequireEmailVerification) props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable) - props["EnableSignUpWithGoogle"] = strconv.FormatBool(c.GoogleSettings.Enable) props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress) @@ -293,6 +292,14 @@ func getClientConfig(c *model.Config) map[string]string { props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText } + if *License.Features.GoogleSSO { + props["EnableSignUpWithGoogle"] = strconv.FormatBool(c.GoogleSettings.Enable) + } + + if *License.Features.Office365SSO { + props["EnableSignUpWithOffice365"] = strconv.FormatBool(c.Office365Settings.Enable) + } + if *License.Features.PasswordRequirements { props["PasswordMinimumLength"] = fmt.Sprintf("%v", *c.PasswordSettings.MinimumLength) props["PasswordRequireLowercase"] = strconv.FormatBool(*c.PasswordSettings.Lowercase) diff --git a/utils/license.go b/utils/license.go index 85d25e6ab8..971b05912f 100644 --- a/utils/license.go +++ b/utils/license.go @@ -123,6 +123,7 @@ func getClientLicense(l *model.License) map[string]string { props["MFA"] = strconv.FormatBool(*l.Features.MFA) props["SAML"] = strconv.FormatBool(*l.Features.SAML) props["GoogleSSO"] = strconv.FormatBool(*l.Features.GoogleSSO) + props["Office365SSO"] = strconv.FormatBool(*l.Features.Office365SSO) props["Compliance"] = strconv.FormatBool(*l.Features.Compliance) props["CustomBrand"] = strconv.FormatBool(*l.Features.CustomBrand) props["MHPNS"] = strconv.FormatBool(*l.Features.MHPNS) diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx index 5c02f419ed..d812b83fd2 100644 --- a/webapp/components/admin_console/admin_sidebar.jsx +++ b/webapp/components/admin_console/admin_sidebar.jsx @@ -175,6 +175,7 @@ export default class AdminSidebar extends React.Component { } render() { + let oauthSettings = null; let ldapSettings = null; let samlSettings = null; let complianceSettings = null; @@ -184,62 +185,6 @@ export default class AdminSidebar extends React.Component { let policy = null; if (window.mm_config.BuildEnterpriseReady === 'true') { - if (window.mm_license.IsLicensed === 'true') { - if (global.window.mm_license.LDAP === 'true') { - ldapSettings = ( - - } - /> - ); - } - - if (global.window.mm_license.SAML === 'true') { - samlSettings = ( - - } - /> - ); - } - - if (global.window.mm_license.Compliance === 'true') { - complianceSettings = ( - - } - /> - ); - } - - policy = ( - - } - /> - ); - } - license = ( + } + /> + ); + } + + if (global.window.mm_license.SAML === 'true') { + samlSettings = ( + + } + /> + ); + } + + if (global.window.mm_license.Compliance === 'true') { + complianceSettings = ( + + } + /> + ); + } + + oauthSettings = ( + + } + /> + ); + + policy = ( + + } + /> + ); + } else { + oauthSettings = ( + + } + /> + ); + } + if (window.mm_license.IsLicensed === 'true') { audits = ( } /> - - } - /> + {oauthSettings} {ldapSettings} {samlSettings} diff --git a/webapp/components/admin_console/oauth_settings.jsx b/webapp/components/admin_console/oauth_settings.jsx new file mode 100644 index 0000000000..627a8864b5 --- /dev/null +++ b/webapp/components/admin_console/oauth_settings.jsx @@ -0,0 +1,432 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import * as Utils from 'utils/utils.jsx'; +import Constants from 'utils/constants.jsx'; + +import AdminSettings from './admin_settings.jsx'; +import DropdownSetting from './dropdown_setting.jsx'; +import SettingsGroup from './settings_group.jsx'; +import TextSetting from './text_setting.jsx'; + +import React from 'react'; +import {FormattedHTMLMessage, FormattedMessage} from 'react-intl'; + +export default class OAuthSettings extends AdminSettings { + constructor(props) { + super(props); + + this.getConfigFromState = this.getConfigFromState.bind(this); + this.getStateFromConfig = this.getStateFromConfig.bind(this); + this.renderSettings = this.renderSettings.bind(this); + this.renderOffice365 = this.renderOffice365.bind(this); + this.renderGoogle = this.renderGoogle.bind(this); + this.renderGitLab = this.renderGitLab.bind(this); + this.changeType = this.changeType.bind(this); + } + + getConfigFromState(config) { + config.GitLabSettings.Enable = false; + config.GoogleSettings.Enable = false; + config.Office365Settings.Enable = false; + + if (this.state.oauthType === Constants.GITLAB_SERVICE) { + config.GitLabSettings.Enable = true; + config.GitLabSettings.Id = this.state.id; + config.GitLabSettings.Secret = this.state.secret; + config.GitLabSettings.UserApiEndpoint = this.state.userApiEndpoint; + config.GitLabSettings.AuthEndpoint = this.state.authEndpoint; + config.GitLabSettings.TokenEndpoint = this.state.tokenEndpoint; + } + + if (this.state.oauthType === Constants.GOOGLE_SERVICE) { + config.GoogleSettings.Enable = true; + config.GoogleSettings.Id = this.state.id; + config.GoogleSettings.Secret = this.state.secret; + config.GoogleSettings.UserApiEndpoint = this.state.userApiEndpoint; + config.GoogleSettings.AuthEndpoint = this.state.authEndpoint; + config.GoogleSettings.TokenEndpoint = this.state.tokenEndpoint; + config.GoogleSettings.Scope = 'profile email'; + } + + if (this.state.oauthType === Constants.OFFICE365_SERVICE) { + config.Office365Settings.Enable = true; + config.Office365Settings.Id = this.state.id; + config.Office365Settings.Secret = this.state.secret; + config.Office365Settings.UserApiEndpoint = this.state.userApiEndpoint; + config.Office365Settings.AuthEndpoint = this.state.authEndpoint; + config.Office365Settings.TokenEndpoint = this.state.tokenEndpoint; + config.Office365Settings.Scope = 'User.Read'; + } + + return config; + } + + getStateFromConfig(config) { + this.config = config; + + let oauthType = 'off'; + let settings = {}; + if (config.GitLabSettings.Enable) { + oauthType = Constants.GITLAB_SERVICE; + settings = config.GitLabSettings; + } else if (config.GoogleSettings.Enable) { + oauthType = Constants.GOOGLE_SERVICE; + settings = config.GoogleSettings; + } else if (config.Office365Settings.Enable) { + oauthType = Constants.OFFICE365_SERVICE; + settings = config.Office365Settings; + } + + return { + oauthType, + id: settings.Id, + secret: settings.Secret, + userApiEndpoint: settings.UserApiEndpoint, + authEndpoint: settings.AuthEndpoint, + tokenEndpoint: settings.TokenEndpoint + }; + } + + changeType(id, value) { + let settings = {}; + if (value === Constants.GITLAB_SERVICE) { + settings = this.config.GitLabSettings; + } else if (value === Constants.GOOGLE_SERVICE) { + settings = this.config.GoogleSettings; + } else if (value === Constants.OFFICE365_SERVICE) { + settings = this.config.Office365Settings; + } + + this.setState({ + id: settings.Id, + secret: settings.Secret, + userApiEndpoint: settings.UserApiEndpoint, + authEndpoint: settings.AuthEndpoint, + tokenEndpoint: settings.TokenEndpoint + }); + + this.handleChange(id, value); + } + + renderTitle() { + return ( +

+ +

+ ); + } + + renderGoogle() { + return ( +
+ + } + placeholder={Utils.localizeMessage('admin.google.clientIdExample', 'Ex "7602141235235-url0fhs1mayfasbmop5qlfns8dh4.apps.googleusercontent.com"')} + helpText={ + + } + value={this.state.id} + onChange={this.handleChange} + /> + + } + placeholder={Utils.localizeMessage('admin.google.clientSecretExample', 'Ex "H8sz0Az-dDs2p15-7QzD231"')} + helpText={ + + } + value={this.state.secret} + onChange={this.handleChange} + /> + + } + value='https://www.googleapis.com/plus/v1/people/me' + disabled={true} + /> + + } + value='https://accounts.google.com/o/oauth2/v2/auth' + disabled={true} + /> + + } + value='https://www.googleapis.com/oauth2/v4/token' + disabled={true} + /> +
+ ); + } + + renderOffice365() { + return ( +
+ + } + placeholder={Utils.localizeMessage('admin.office365.clientIdExample', 'Ex "adf3sfa2-ag3f-sn4n-ids0-sh1hdax192qq"')} + helpText={ + + } + value={this.state.id} + onChange={this.handleChange} + /> + + } + placeholder={Utils.localizeMessage('admin.office365.clientSecretExample', 'Ex "shAieM47sNBfgl20f8ci294"')} + helpText={ + + } + value={this.state.secret} + onChange={this.handleChange} + /> + + } + value='https://graph.microsoft.com/v1.0/me' + disabled={true} + /> + + } + value='https://login.microsoftonline.com/common/oauth2/v2.0/authorize' + disabled={true} + /> + + } + value='https://login.microsoftonline.com/common/oauth2/v2.0/token' + disabled={true} + /> +
+ ); + } + + renderGitLab() { + return ( +
+ + } + placeholder={Utils.localizeMessage('admin.gitlab.clientIdExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')} + helpText={ + + } + value={this.state.id} + onChange={this.handleChange} + /> + + } + placeholder={Utils.localizeMessage('admin.gitlab.clientSecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')} + helpText={ + + } + value={this.state.secret} + onChange={this.handleChange} + /> + + } + placeholder={Utils.localizeMessage('admin.gitlab.userExample', 'Ex "https:///api/v3/user"')} + helpText={ + + } + value={this.state.userApiEndpoint} + onChange={this.handleChange} + /> + + } + placeholder={Utils.localizeMessage('admin.gitlab.authExample', 'Ex "https:///oauth/authorize"')} + helpText={ + + } + value={this.state.authEndpoint} + onChange={this.handleChange} + /> + + } + placeholder={Utils.localizeMessage('admin.gitlab.tokenExample', 'Ex "https:///oauth/token"')} + helpText={ + + } + value={this.state.tokenEndpoint} + onChange={this.handleChange} + /> +
+ ); + } + + renderSettings() { + let contents; + let helpText; + if (this.state.oauthType === Constants.GITLAB_SERVICE) { + contents = this.renderGitLab(); + helpText = ( + + ); + } else if (this.state.oauthType === Constants.GOOGLE_SERVICE) { + contents = this.renderGoogle(); + helpText = ( + + ); + } else if (this.state.oauthType === Constants.OFFICE365_SERVICE) { + contents = this.renderOffice365(); + helpText = ( + + ); + } + + const oauthTypes = []; + oauthTypes.push({value: 'off', text: Utils.localizeMessage('admin.oauth.off', 'Do not allow sign-in via an OAuth 2.0 provider.')}); + oauthTypes.push({value: Constants.GITLAB_SERVICE, text: Utils.localizeMessage('admin.oauth.gitlab', 'GitLab')}); + if (global.window.mm_license.IsLicensed === 'true') { + if (global.window.mm_license.GoogleSSO === 'true') { + oauthTypes.push({value: Constants.GOOGLE_SERVICE, text: Utils.localizeMessage('admin.oauth.google', 'Google Apps')}); + } + if (global.window.mm_license.Office365SSO === 'true') { + oauthTypes.push({value: Constants.OFFICE365_SERVICE, text: Utils.localizeMessage('admin.oauth.office365', 'Office 365')}); + } + } + + return ( + + + } + helpText={helpText} + value={this.state.oauthType} + onChange={this.changeType} + /> + {contents} + + ); + } +} diff --git a/webapp/components/login/login_controller.jsx b/webapp/components/login/login_controller.jsx index bcd362f13b..4a4c5cb0ab 100644 --- a/webapp/components/login/login_controller.jsx +++ b/webapp/components/login/login_controller.jsx @@ -328,6 +328,7 @@ export default class LoginController extends React.Component { const ldapEnabled = this.state.ldapEnabled; const gitlabSigninEnabled = global.window.mm_config.EnableSignUpWithGitLab === 'true'; const googleSigninEnabled = global.window.mm_config.EnableSignUpWithGoogle === 'true'; + const office365SigninEnabled = global.window.mm_config.EnableSignUpWithOffice365 === 'true'; const samlSigninEnabled = this.state.samlEnabled; const usernameSigninEnabled = this.state.usernameSigninEnabled; const emailSigninEnabled = this.state.emailSigninEnabled; @@ -429,7 +430,7 @@ export default class LoginController extends React.Component { ); } - if ((emailSigninEnabled || usernameSigninEnabled || ldapEnabled) && (gitlabSigninEnabled || googleSigninEnabled || samlSigninEnabled)) { + if ((emailSigninEnabled || usernameSigninEnabled || ldapEnabled) && (gitlabSigninEnabled || googleSigninEnabled || samlSigninEnabled || office365SigninEnabled)) { loginControls.push(
@@ -484,7 +485,25 @@ export default class LoginController extends React.Component { defaultMessage='Google Apps' /> - + + ); + } + + if (office365SigninEnabled) { + loginControls.push( + + + + + + ); } diff --git a/webapp/components/signup_user_complete.jsx b/webapp/components/signup_user_complete.jsx index 254478e03a..3cd6fb27be 100644 --- a/webapp/components/signup_user_complete.jsx +++ b/webapp/components/signup_user_complete.jsx @@ -594,6 +594,24 @@ export default class SignupUserComplete extends React.Component { ); } + if (global.window.mm_config.EnableSignUpWithOffice365 === 'true') { + signupMessage.push( + + + + + + ); + } + if (global.window.mm_config.EnableSaml === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.SAML === 'true') { signupMessage.push( ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + inputs.push( +
+
+ +
+ {helpText} +
+ ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + inputs.push( +
+
+ +
+ {helpText} +
+ ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { inputs.push(
); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + describe = ( + + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + describe = ( + + ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { describe = ( + + +
+
+ ); + } + + if (global.window.mm_config.EnableSignUpWithGoogle === 'true') { + googleOption = ( +
+ + +
+
+ ); + } + + if (global.window.mm_config.EnableSignUpWithOffice365 === 'true') { + office365Option = ( +
+ + +
+
+ ); + } + + if (global.window.mm_config.EnableLdap === 'true') { + ldapOption = ( +
+ + + +
+
+ ); + } + + if (global.window.mm_config.EnableSaml === 'true') { + samlOption = ( +
+ + +
+
+ ); + } + } else if (global.window.mm_config.EnableSignUpWithEmail === 'true') { let link; if (user.auth_service === Constants.LDAP_SERVICE) { link = '/claim/ldap_to_email?email=' + encodeURIComponent(user.email); @@ -570,86 +657,15 @@ class SecurityTab extends React.Component { ); } - let gitlabOption; - if (global.window.mm_config.EnableSignUpWithGitLab === 'true' && user.auth_service === '') { - gitlabOption = ( -
- - -
-
- ); - } - - let googleOption; - if (global.window.mm_config.EnableSignUpWithGoogle === 'true' && user.auth_service === '') { - googleOption = ( -
- - -
-
- ); - } - - let ldapOption; - if (global.window.mm_config.EnableLdap === 'true' && user.auth_service === '') { - ldapOption = ( -
- - - -
-
- ); - } - - let samlOption; - if (global.window.mm_config.EnableSaml === 'true' && user.auth_service === '') { - samlOption = ( -
- - -
-
- ); - } - const inputs = []; inputs.push(
{emailOption} {gitlabOption} + {googleOption} + {office365Option} {ldapOption} {samlOption} - {googleOption}
); @@ -693,7 +709,21 @@ class SecurityTab extends React.Component { describe = ( + ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + describe = ( + + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + describe = ( + ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index e78548fc4d..9aa3a8e617 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -105,6 +105,7 @@ "admin.audits.title": "User Activity Logs", "admin.authentication.email": "Email Auth", "admin.authentication.gitlab": "GitLab", + "admin.authentication.oauth": "OAuth 2.0", "admin.authentication.saml": "SAML", "admin.banner.heading": "Note:", "admin.compliance.directoryDescription": "Directory to which compliance reports are written. If blank, will be set to ./data/.", @@ -273,6 +274,31 @@ "admin.gitlab.userDescription": "Enter https:///api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.", "admin.gitlab.userExample": "Ex \"https:///api/v3/user\"", "admin.gitlab.userTitle": "User API Endpoint:", + "admin.google.EnableHtmlDesc": "
  1. Log in to your Google account.
  2. Go to https://console.developers.google.com, click Credentials in the left hand sidebar and enter Mattermost - as the project name.
  3. Click the OAuth consent screen header and enter Mattermost as the Product name to show users. Click Save.
  4. Under the Credentials header, click Create credentials, choose OAuth client ID and select Web Application.
  5. Under Restrictions and Authorized redirect URIs enter /signup/google/complete (example: http://localhost:8065/signup/google/complete). Click Create.
  6. Save the client ID and client secret to later complete the fields below.
  7. Finally, go to Google+ API and click Enable. This might take a few minutes to propagate through Google's systems.
  8. Complete the Client ID and Client Secret fields below.
", + "admin.google.authTitle": "Auth Endpoint:", + "admin.google.clientIdDescription": "The Client ID you received when registering your application with Google.", + "admin.google.clientIdExample": "Ex \"7602141235235-url0fhs1mayfasbmop5qlfns8dh4.apps.googleusercontent.com\"", + "admin.google.clientIdTitle": "Client ID:", + "admin.google.clientSecretDescription": "The Client Secret you received when registering your application with Google.", + "admin.google.clientSecretExample": "Ex \"H8sz0Az-dDs2p15-7QzD231\"", + "admin.google.clientSecretTitle": "Client Secret:", + "admin.google.tokenTitle": "Token Endpoint:", + "admin.google.userTitle": "User API Endpoint:", + "admin.office365.EnableHtmlDesc": "
  1. Log in to your Microsoft or Office 365 account. Make sure it's the account on the same tenant that you would like users to log in with.
  2. Go to https://apps.dev.microsoft.com, click Add an app and use Mattermost - as the application name.
  3. Under Application Secrets, click Generate New Password and save it to later complete the field below.
  4. Under Platforms, click Add Platform, choose Web and enter /signup/office365/complete (example: http://localhost:8065/signup/office365/complete) under Redirect URIs. Also uncheck Allow Implicit Flow.
  5. Finally, click Save and complete the Application ID and Application Secret Password fields below.
", + "admin.office365.authTitle": "Auth Endpoint:", + "admin.office365.clientIdDescription": "The Application/Client ID you received when registering your application with Microsoft.", + "admin.office365.clientIdExample": "Ex \"adf3sfa2-ag3f-sn4n-ids0-sh1hdax192qq\"", + "admin.office365.clientIdTitle": "Application ID:", + "admin.office365.clientSecretDescription": "The Application Secret Password you generated when registering your application with Microsoft.", + "admin.office365.clientSecretExample": "Ex \"shAieM47sNBfgl20f8ci294\"", + "admin.office365.clientSecretTitle": "Application Secret Password:", + "admin.office365.tokenTitle": "Token Endpoint:", + "admin.office365.userTitle": "User API Endpoint:", + "admin.oauth.off": "Do not allow sign-in via an OAuth 2.0 provider", + "admin.oauth.gitlab": "GitLab", + "admin.oauth.google": "Google Apps", + "admin.oauth.office365": "Office 365", + "admin.oauth.select": "Select OAuth 2.0 service provider:", "admin.image.amazonS3BucketDescription": "Name you selected for your S3 bucket in AWS.", "admin.image.amazonS3BucketExample": "Ex \"mattermost-media\"", "admin.image.amazonS3BucketTitle": "Amazon S3 Bucket:", @@ -601,6 +627,7 @@ "admin.sidebar.login": "Login", "admin.sidebar.logs": "Logs", "admin.sidebar.notifications": "Notifications", + "admin.sidebar.oauth": "OAuth 2.0", "admin.sidebar.other": "OTHER", "admin.sidebar.password": "Password", "admin.sidebar.policy": "Policy", @@ -1174,6 +1201,7 @@ "login.forgot": "I forgot my password", "login.gitlab": "GitLab", "login.google": "Google Apps", + "login.office365": "Office 365", "login.invalidPassword": "Your password is incorrect.", "login.ldapUsername": "LDAP Username", "login.ldapUsernameLower": "LDAP username", @@ -1399,6 +1427,7 @@ "signup_user_completed.expired": "You've already completed the signup process for this invitation or this invitation has expired.", "signup_user_completed.gitlab": "with GitLab", "signup_user_completed.google": "with Google", + "signup_user_completed.office365": "with Office 365", "signup_user_completed.haveAccount": "Already have an account?", "signup_user_completed.invalid_invite": "The invite link was invalid. Please speak with your Administrator to receive an invitation.", "signup_user_completed.lets": "Let's create your account", @@ -1567,6 +1596,8 @@ "user.settings.general.confirmEmail": "Confirm Email", "user.settings.general.email": "Email", "user.settings.general.emailGitlabCantUpdate": "Login occurs through GitLab. Email cannot be updated. Email address used for notifications is {email}.", + "user.settings.general.emailGoogleCantUpdate": "Login occurs through Google. Email cannot be updated. Email address used for notifications is {email}.", + "user.settings.general.emailOffice365CantUpdate": "Login occurs through Office 365. Email cannot be updated. Email address used for notifications is {email}.", "user.settings.general.emailHelp1": "Email is used for sign-in, notifications, and password reset. Email requires verification if changed.", "user.settings.general.emailHelp2": "Email has been disabled by your system administrator. No notification emails will be sent until it is enabled.", "user.settings.general.emailHelp3": "Email is used for sign-in, notifications, and password reset.", @@ -1584,6 +1615,8 @@ "user.settings.general.imageUpdated": "Image last updated {date}", "user.settings.general.lastName": "Last Name", "user.settings.general.loginGitlab": "Login done through GitLab ({email})", + "user.settings.general.loginGoogle": "Login done through Google ({email})", + "user.settings.general.loginOffice365": "Login done through Office 365 ({email})", "user.settings.general.loginLdap": "Login done through LDAP ({email})", "user.settings.general.loginSaml": "Login done through SAML ({email})", "user.settings.general.newAddress": "New Address: {email}
Check your email to verify the above address.", @@ -1663,7 +1696,9 @@ "user.settings.security.currentPassword": "Current Password", "user.settings.security.currentPasswordError": "Please enter your current password", "user.settings.security.emailPwd": "Email and Password", - "user.settings.security.gitlab": "GitLab SSO", + "user.settings.security.gitlab": "GitLab", + "user.settings.security.google": "Google", + "user.settings.security.office365": "Office 365", "user.settings.security.lastUpdated": "Last updated {date} at {time}", "user.settings.security.ldap": "LDAP", "user.settings.security.loginGitlab": "Login done through Gitlab", @@ -1698,6 +1733,7 @@ "user.settings.security.switchEmail": "Switch to using email and password", "user.settings.security.switchGitlab": "Switch to using GitLab SSO", "user.settings.security.switchGoogle": "Switch to using Google SSO", + "user.settings.security.switchOffice365": "Switch to using Office 365 SSO", "user.settings.security.switchLdap": "Switch to using LDAP", "user.settings.security.switchSaml": "Switch to using SAML SSO", "user.settings.security.title": "Security Settings", diff --git a/webapp/images/office365Logo.png b/webapp/images/office365Logo.png new file mode 100644 index 0000000000..59670460e8 Binary files /dev/null and b/webapp/images/office365Logo.png differ diff --git a/webapp/routes/route_admin_console.jsx b/webapp/routes/route_admin_console.jsx index 1465bfa6b8..291ba65f8a 100644 --- a/webapp/routes/route_admin_console.jsx +++ b/webapp/routes/route_admin_console.jsx @@ -14,6 +14,7 @@ import PolicySettings from 'components/admin_console/policy_settings.jsx'; import LogSettings from 'components/admin_console/log_settings.jsx'; import EmailAuthenticationSettings from 'components/admin_console/email_authentication_settings.jsx'; import GitLabSettings from 'components/admin_console/gitlab_settings.jsx'; +import OAuthSettings from 'components/admin_console/oauth_settings.jsx'; import LdapSettings from 'components/admin_console/ldap_settings.jsx'; import SamlSettings from 'components/admin_console/saml_settings.jsx'; import SignupSettings from 'components/admin_console/signup_settings.jsx'; @@ -88,6 +89,10 @@ export default ( path='gitlab' component={GitLabSettings} /> +