diff options
-rw-r--r-- | api/oauth.go | 14 | ||||
-rw-r--r-- | api/user.go | 4 | ||||
-rw-r--r-- | config/config.json | 19 | ||||
-rw-r--r-- | i18n/en.json | 6 | ||||
-rw-r--r-- | model/config.go | 8 | ||||
-rw-r--r-- | model/license.go | 8 | ||||
-rw-r--r-- | utils/config.go | 9 | ||||
-rw-r--r-- | utils/license.go | 1 | ||||
-rw-r--r-- | webapp/components/admin_console/admin_sidebar.jsx | 129 | ||||
-rw-r--r-- | webapp/components/admin_console/oauth_settings.jsx | 432 | ||||
-rw-r--r-- | webapp/components/login/login_controller.jsx | 27 | ||||
-rw-r--r-- | webapp/components/signup_user_complete.jsx | 18 | ||||
-rw-r--r-- | webapp/components/user_settings/user_settings_general.jsx | 56 | ||||
-rw-r--r-- | webapp/components/user_settings/user_settings_security.jsx | 192 | ||||
-rw-r--r-- | webapp/i18n/en.json | 38 | ||||
-rw-r--r-- | webapp/images/office365Logo.png | bin | 0 -> 633 bytes | |||
-rw-r--r-- | webapp/routes/route_admin_console.jsx | 5 | ||||
-rw-r--r-- | webapp/sass/routes/_signup.scss | 17 | ||||
-rw-r--r-- | webapp/utils/constants.jsx | 1 |
19 files changed, 821 insertions, 163 deletions
diff --git a/api/oauth.go b/api/oauth.go index f64fc638d..d41f526b4 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 f9d982048..506c0ba44 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 8f1bea3ca..22d500c3e 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 5fad6d452..3e792f88a 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 05d574cb2..4b00e835d 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 a77a7349a..a60695890 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 39dbca4d8..9710684e8 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 85d25e6ab..971b05912 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 5c02f419e..d812b83fd 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,69 +185,93 @@ 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 = ( - <AdminSidebarSection - name='ldap' - title={ - <FormattedMessage - id='admin.sidebar.ldap' - defaultMessage='LDAP' - /> - } + license = ( + <AdminSidebarSection + name='license' + title={ + <FormattedMessage + id='admin.sidebar.license' + defaultMessage='Edition and License' /> - ); - } + } + /> + ); + } - if (global.window.mm_license.SAML === 'true') { - samlSettings = ( - <AdminSidebarSection - name='saml' - title={ - <FormattedMessage - id='admin.sidebar.saml' - defaultMessage='SAML' - /> - } - /> - ); - } + if (window.mm_license.IsLicensed === 'true') { + if (global.window.mm_license.LDAP === 'true') { + ldapSettings = ( + <AdminSidebarSection + name='ldap' + title={ + <FormattedMessage + id='admin.sidebar.ldap' + defaultMessage='LDAP' + /> + } + /> + ); + } - if (global.window.mm_license.Compliance === 'true') { - complianceSettings = ( - <AdminSidebarSection - name='compliance' - title={ - <FormattedMessage - id='admin.sidebar.compliance' - defaultMessage='Compliance' - /> - } - /> - ); - } + if (global.window.mm_license.SAML === 'true') { + samlSettings = ( + <AdminSidebarSection + name='saml' + title={ + <FormattedMessage + id='admin.sidebar.saml' + defaultMessage='SAML' + /> + } + /> + ); + } - policy = ( + if (global.window.mm_license.Compliance === 'true') { + complianceSettings = ( <AdminSidebarSection - name='policy' + name='compliance' title={ <FormattedMessage - id='admin.sidebar.policy' - defaultMessage='Policy' + id='admin.sidebar.compliance' + defaultMessage='Compliance' /> } /> ); } - license = ( + oauthSettings = ( <AdminSidebarSection - name='license' + name='oauth' title={ <FormattedMessage - id='admin.sidebar.license' - defaultMessage='Edition and License' + id='admin.sidebar.oauth' + defaultMessage='OAuth 2.0' + /> + } + /> + ); + + policy = ( + <AdminSidebarSection + name='policy' + title={ + <FormattedMessage + id='admin.sidebar.policy' + defaultMessage='Policy' + /> + } + /> + ); + } else { + oauthSettings = ( + <AdminSidebarSection + name='gitlab' + title={ + <FormattedMessage + id='admin.sidebar.gitlab' + defaultMessage='GitLab' /> } /> @@ -396,15 +421,7 @@ export default class AdminSidebar extends React.Component { /> } /> - <AdminSidebarSection - name='gitlab' - title={ - <FormattedMessage - id='admin.sidebar.gitlab' - defaultMessage='GitLab' - /> - } - /> + {oauthSettings} {ldapSettings} {samlSettings} </AdminSidebarSection> diff --git a/webapp/components/admin_console/oauth_settings.jsx b/webapp/components/admin_console/oauth_settings.jsx new file mode 100644 index 000000000..627a8864b --- /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 ( + <h3> + <FormattedMessage + id='admin.authentication.oauth' + defaultMessage='OAuth 2.0' + /> + </h3> + ); + } + + renderGoogle() { + return ( + <div> + <TextSetting + id='id' + label={ + <FormattedMessage + id='admin.google.clientIdTitle' + defaultMessage='Client ID:' + /> + } + placeholder={Utils.localizeMessage('admin.google.clientIdExample', 'Ex "7602141235235-url0fhs1mayfasbmop5qlfns8dh4.apps.googleusercontent.com"')} + helpText={ + <FormattedMessage + id='admin.google.clientIdDescription' + defaultMessage='The Client ID you received when registering your application with Google.' + /> + } + value={this.state.id} + onChange={this.handleChange} + /> + <TextSetting + id='secret' + label={ + <FormattedMessage + id='admin.google.clientSecretTitle' + defaultMessage='Client Secret:' + /> + } + placeholder={Utils.localizeMessage('admin.google.clientSecretExample', 'Ex "H8sz0Az-dDs2p15-7QzD231"')} + helpText={ + <FormattedMessage + id='admin.google.clientSecretDescription' + defaultMessage='The Client Secret you received when registering your application with Google.' + /> + } + value={this.state.secret} + onChange={this.handleChange} + /> + <TextSetting + id='userApiEndpoint' + label={ + <FormattedMessage + id='admin.google.userTitle' + defaultMessage='User API Endpoint:' + /> + } + value='https://www.googleapis.com/plus/v1/people/me' + disabled={true} + /> + <TextSetting + id='authEndpoint' + label={ + <FormattedMessage + id='admin.google.authTitle' + defaultMessage='Auth Endpoint:' + /> + } + value='https://accounts.google.com/o/oauth2/v2/auth' + disabled={true} + /> + <TextSetting + id='tokenEndpoint' + label={ + <FormattedMessage + id='admin.google.tokenTitle' + defaultMessage='Token Endpoint:' + /> + } + value='https://www.googleapis.com/oauth2/v4/token' + disabled={true} + /> + </div> + ); + } + + renderOffice365() { + return ( + <div> + <TextSetting + id='id' + label={ + <FormattedMessage + id='admin.office365.clientIdTitle' + defaultMessage='Application ID:' + /> + } + placeholder={Utils.localizeMessage('admin.office365.clientIdExample', 'Ex "adf3sfa2-ag3f-sn4n-ids0-sh1hdax192qq"')} + helpText={ + <FormattedMessage + id='admin.office365.clientIdDescription' + defaultMessage='The Application/Client ID you received when registering your application with Microsoft.' + /> + } + value={this.state.id} + onChange={this.handleChange} + /> + <TextSetting + id='secret' + label={ + <FormattedMessage + id='admin.office365.clientSecretTitle' + defaultMessage='Application Secret Password:' + /> + } + placeholder={Utils.localizeMessage('admin.office365.clientSecretExample', 'Ex "shAieM47sNBfgl20f8ci294"')} + helpText={ + <FormattedMessage + id='admin.office365.clientSecretDescription' + defaultMessage='The Application Secret Password you generated when registering your application with Microsoft.' + /> + } + value={this.state.secret} + onChange={this.handleChange} + /> + <TextSetting + id='userApiEndpoint' + label={ + <FormattedMessage + id='admin.office365.userTitle' + defaultMessage='User API Endpoint:' + /> + } + value='https://graph.microsoft.com/v1.0/me' + disabled={true} + /> + <TextSetting + id='authEndpoint' + label={ + <FormattedMessage + id='admin.office365.authTitle' + defaultMessage='Auth Endpoint:' + /> + } + value='https://login.microsoftonline.com/common/oauth2/v2.0/authorize' + disabled={true} + /> + <TextSetting + id='tokenEndpoint' + label={ + <FormattedMessage + id='admin.office365.tokenTitle' + defaultMessage='Token Endpoint:' + /> + } + value='https://login.microsoftonline.com/common/oauth2/v2.0/token' + disabled={true} + /> + </div> + ); + } + + renderGitLab() { + return ( + <div> + <TextSetting + id='id' + label={ + <FormattedMessage + id='admin.gitlab.clientIdTitle' + defaultMessage='Application ID:' + /> + } + placeholder={Utils.localizeMessage('admin.gitlab.clientIdExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')} + helpText={ + <FormattedMessage + id='admin.gitlab.clientIdDescription' + defaultMessage='Obtain this value via the instructions above for logging into GitLab' + /> + } + value={this.state.id} + onChange={this.handleChange} + /> + <TextSetting + id='secret' + label={ + <FormattedMessage + id='admin.gitlab.clientSecretTitle' + defaultMessage='Application Secret Key:' + /> + } + placeholder={Utils.localizeMessage('admin.gitlab.clientSecretExample', 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"')} + helpText={ + <FormattedMessage + id='admin.gitab.clientSecretDescription' + defaultMessage='Obtain this value via the instructions above for logging into GitLab.' + /> + } + value={this.state.secret} + onChange={this.handleChange} + /> + <TextSetting + id='userApiEndpoint' + label={ + <FormattedMessage + id='admin.gitlab.userTitle' + defaultMessage='User API Endpoint:' + /> + } + placeholder={Utils.localizeMessage('admin.gitlab.userExample', 'Ex "https://<your-gitlab-url>/api/v3/user"')} + helpText={ + <FormattedMessage + id='admin.gitlab.userDescription' + defaultMessage='Enter https://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.' + /> + } + value={this.state.userApiEndpoint} + onChange={this.handleChange} + /> + <TextSetting + id='authEndpoint' + label={ + <FormattedMessage + id='admin.gitlab.authTitle' + defaultMessage='Auth Endpoint:' + /> + } + placeholder={Utils.localizeMessage('admin.gitlab.authExample', 'Ex "https://<your-gitlab-url>/oauth/authorize"')} + helpText={ + <FormattedMessage + id='admin.gitlab.authDescription' + defaultMessage='Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.' + /> + } + value={this.state.authEndpoint} + onChange={this.handleChange} + /> + <TextSetting + id='tokenEndpoint' + label={ + <FormattedMessage + id='admin.gitlab.tokenTitle' + defaultMessage='Token Endpoint:' + /> + } + placeholder={Utils.localizeMessage('admin.gitlab.tokenExample', 'Ex "https://<your-gitlab-url>/oauth/token"')} + helpText={ + <FormattedMessage + id='admin.gitlab.tokenDescription' + defaultMessage='Enter https://<your-gitlab-url>/oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.' + /> + } + value={this.state.tokenEndpoint} + onChange={this.handleChange} + /> + </div> + ); + } + + renderSettings() { + let contents; + let helpText; + if (this.state.oauthType === Constants.GITLAB_SERVICE) { + contents = this.renderGitLab(); + helpText = ( + <FormattedHTMLMessage + id='admin.gitlab.EnableHtmlDesc' + defaultMessage='<ol><li>Log in to your GitLab account and go to Profile Settings -> Applications.</li><li>Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". </li><li>Then use "Application Secret Key" and "Application ID" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>' + /> + ); + } else if (this.state.oauthType === Constants.GOOGLE_SERVICE) { + contents = this.renderGoogle(); + helpText = ( + <FormattedHTMLMessage + id='admin.google.EnableHtmlDesc' + defaultMessage="<ol><li><a href='https://accounts.google.com/login'>Log in</a> to your Google account.</li><li>Go to <a href='https://console.developers.google.com'>https://console.developers.google.com</a>, click <strong>Credentials</strong> in the left hand sidebar and enter <strong>Mattermost - <your-company-name></strong> as the project name.</li><li>Click the <strong>OAuth consent screen</strong> header and enter <strong>Mattermost</strong> as the <strong>Product name to show users</strong>. Click <strong>Save</strong>.</li><li>Under the <strong>Credentials</strong> header, click <strong>Create credentials</strong>, choose <strong>OAuth client ID</strong> and select <strong>Web Application</strong>.</li><li>Under <strong>Restrictions</strong> and <strong>Authorized redirect URIs</strong> enter <strong><your-mattermost-url>/signup/google/complete</strong> (example: http://localhost:8065/signup/google/complete). Click <strong>Create</strong>.</li><li>Save the <strong>client ID</strong> and <strong>client secret</strong> to later complete the fields below.</li><li>Finally, go to <a href='https://console.developers.google.com/apis/api/plus/overview'>Google+ API</a> and click <strong>Enable</strong>. This might take a few minutes to propagate through Google's systems.</li><li>Complete the <strong>Client ID</strong> and <strong>Client Secret</strong> fields below.</li></ol>" + /> + ); + } else if (this.state.oauthType === Constants.OFFICE365_SERVICE) { + contents = this.renderOffice365(); + helpText = ( + <FormattedHTMLMessage + id='admin.office365.EnableHtmlDesc' + defaultMessage="<ol><li><a href='https://login.microsoftonline.com/'>Log in</a> to your Microsoft or Office 365 account. Make sure it's the account on the same <a href='https://msdn.microsoft.com/en-us/library/azure/jj573650.aspx#Anchor_0'>tenant</a> that you would like users to log in with.</li><li>Go to <a href='https://apps.dev.microsoft.com'>https://apps.dev.microsoft.com</a>, click <strong>Add an app</strong> and use <strong>Mattermost - <your-company-name></strong> as the application name.</li><li>Under <strong>Application Secrets</strong>, click <strong>Generate New Password</strong> and save it to later complete the field below.</li><li>Under <strong>Platforms</strong>, click <strong>Add Platform</strong>, choose <strong>Web</strong> and enter <strong><your-mattermost-url>/signup/office365/complete</strong> (example: http://localhost:8065/signup/office365/complete) under <strong>Redirect URIs</strong>. Also uncheck <strong>Allow Implicit Flow</strong>.</li><li>Finally, click <strong>Save</strong> and complete the <strong>Application ID</strong> and <strong>Application Secret Password</strong> fields below.</li></ol>" + /> + ); + } + + 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 ( + <SettingsGroup> + <DropdownSetting + id='oauthType' + values={oauthTypes} + label={ + <FormattedMessage + id='admin.oauth.select' + defaultMessage='Select OAuth 2.0 Service Provider:' + /> + } + helpText={helpText} + value={this.state.oauthType} + onChange={this.changeType} + /> + {contents} + </SettingsGroup> + ); + } +} diff --git a/webapp/components/login/login_controller.jsx b/webapp/components/login/login_controller.jsx index bcd362f13..4a4c5cb0a 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( <div key='divider' @@ -472,10 +473,10 @@ export default class LoginController extends React.Component { if (googleSigninEnabled) { loginControls.push( - <Link + <a className='btn btn-custom-login google' key='google' - to={Client.getOAuthRoute() + '/google/login'} + href={Client.getOAuthRoute() + '/google/login' + this.props.location.search} > <span className='icon'/> <span> @@ -484,7 +485,25 @@ export default class LoginController extends React.Component { defaultMessage='Google Apps' /> </span> - </Link> + </a> + ); + } + + if (office365SigninEnabled) { + loginControls.push( + <a + className='btn btn-custom-login office365' + key='office365' + href={Client.getOAuthRoute() + '/office365/login' + this.props.location.search} + > + <span className='icon'/> + <span> + <FormattedMessage + id='login.office365' + defaultMessage='Office 365' + /> + </span> + </a> ); } diff --git a/webapp/components/signup_user_complete.jsx b/webapp/components/signup_user_complete.jsx index 254478e03..3cd6fb27b 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( + <a + className='btn btn-custom-login office365' + key='office365' + href={Client.getOAuthRoute() + '/office365/signup' + window.location.search + '&team=' + encodeURIComponent(this.state.teamName)} + > + <span className='icon'/> + <span> + <FormattedMessage + id='signup_user_completed.office365' + defaultMessage='with Office 365' + /> + </span> + </a> + ); + } + if (global.window.mm_config.EnableSaml === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.SAML === 'true') { signupMessage.push( <a diff --git a/webapp/components/user_settings/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general.jsx index 8dce4deed..d1c195c7e 100644 --- a/webapp/components/user_settings/user_settings_general.jsx +++ b/webapp/components/user_settings/user_settings_general.jsx @@ -419,6 +419,42 @@ class UserSettingsGeneralTab extends React.Component { {helpText} </div> ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + inputs.push( + <div + key='oauthEmailInfo' + className='form-group' + > + <div className='setting-list__hint'> + <FormattedMessage + id='user.settings.general.emailGoogleCantUpdate' + defaultMessage='Login occurs through Google Apps. Email cannot be updated. Email address used for notifications is {email}.' + values={{ + email: this.state.email + }} + /> + </div> + {helpText} + </div> + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + inputs.push( + <div + key='oauthEmailInfo' + className='form-group' + > + <div className='setting-list__hint'> + <FormattedMessage + id='user.settings.general.emailOffice365CantUpdate' + defaultMessage='Login occurs through Office 365. Email cannot be updated. Email address used for notifications is {email}.' + values={{ + email: this.state.email + }} + /> + </div> + {helpText} + </div> + ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { inputs.push( <div @@ -511,6 +547,26 @@ class UserSettingsGeneralTab extends React.Component { }} /> ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + describe = ( + <FormattedMessage + id='user.settings.general.loginGoogle' + defaultMessage='Login done through Google Apps ({email})' + values={{ + email: this.state.email + }} + /> + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + describe = ( + <FormattedMessage + id='user.settings.general.loginOffice365' + defaultMessage='Login done through Office 365 ({email})' + values={{ + email: this.state.email + }} + /> + ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { describe = ( <FormattedMessage diff --git a/webapp/components/user_settings/user_settings_security.jsx b/webapp/components/user_settings/user_settings_security.jsx index a4f02a614..428c88e25 100644 --- a/webapp/components/user_settings/user_settings_security.jsx +++ b/webapp/components/user_settings/user_settings_security.jsx @@ -1,7 +1,6 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import $ from 'jquery'; import SettingItemMin from '../setting_item_min.jsx'; import SettingItemMax from '../setting_item_max.jsx'; import AccessHistoryModal from '../access_history_modal.jsx'; @@ -9,13 +8,14 @@ import ActivityLogModal from '../activity_log_modal.jsx'; import ToggleModalButton from '../toggle_modal_button.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; -import TeamStore from 'stores/team_store.jsx'; import Client from 'client/web_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; +import $ from 'jquery'; +import React from 'react'; import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedTime, FormattedDate} from 'react-intl'; import {Link} from 'react-router/es6'; @@ -42,8 +42,6 @@ const holders = defineMessages({ } }); -import React from 'react'; - class SecurityTab extends React.Component { constructor(props) { super(props); @@ -543,10 +541,99 @@ class SecurityTab extends React.Component { const user = this.props.user; if (this.props.activeSection === 'signin') { - const teamName = TeamStore.getCurrent().name; - let emailOption; - if (global.window.mm_config.EnableSignUpWithEmail === 'true' && user.auth_service !== '') { + let gitlabOption; + let googleOption; + let office365Option; + let ldapOption; + let samlOption; + + if (user.auth_service === '') { + if (global.window.mm_config.EnableSignUpWithGitLab === 'true') { + gitlabOption = ( + <div className='padding-bottom x2'> + <Link + className='btn btn-primary' + to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GITLAB_SERVICE} + > + <FormattedMessage + id='user.settings.security.switchGitlab' + defaultMessage='Switch to using GitLab SSO' + /> + </Link> + <br/> + </div> + ); + } + + if (global.window.mm_config.EnableSignUpWithGoogle === 'true') { + googleOption = ( + <div className='padding-bottom x2'> + <Link + className='btn btn-primary' + to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GOOGLE_SERVICE} + > + <FormattedMessage + id='user.settings.security.switchGoogle' + defaultMessage='Switch to using Google SSO' + /> + </Link> + <br/> + </div> + ); + } + + if (global.window.mm_config.EnableSignUpWithOffice365 === 'true') { + office365Option = ( + <div className='padding-bottom x2'> + <Link + className='btn btn-primary' + to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.OFFICE365_SERVICE} + > + <FormattedMessage + id='user.settings.security.switchOffice365' + defaultMessage='Switch to using Office 365 SSO' + /> + </Link> + <br/> + </div> + ); + } + + if (global.window.mm_config.EnableLdap === 'true') { + ldapOption = ( + <div className='padding-bottom x2'> + <Link + className='btn btn-primary' + to={'/claim/email_to_ldap?email=' + encodeURIComponent(user.email)} + > + <FormattedMessage + id='user.settings.security.switchLdap' + defaultMessage='Switch to using LDAP' + /> + </Link> + <br/> + </div> + ); + } + + if (global.window.mm_config.EnableSaml === 'true') { + samlOption = ( + <div className='padding-bottom x2'> + <Link + className='btn btn-primary' + to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.SAML_SERVICE} + > + <FormattedMessage + id='user.settings.security.switchSaml' + defaultMessage='Switch to using SAML SSO' + /> + </Link> + <br/> + </div> + ); + } + } 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 = ( - <div className='padding-bottom x2'> - <Link - className='btn btn-primary' - to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GITLAB_SERVICE} - > - <FormattedMessage - id='user.settings.security.switchGitlab' - defaultMessage='Switch to using GitLab SSO' - /> - </Link> - <br/> - </div> - ); - } - - let googleOption; - if (global.window.mm_config.EnableSignUpWithGoogle === 'true' && user.auth_service === '') { - googleOption = ( - <div className='padding-bottom x2'> - <Link - className='btn btn-primary' - to={'/' + teamName + '/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GOOGLE_SERVICE} - > - <FormattedMessage - id='user.settings.security.switchGoogle' - defaultMessage='Switch to using Google SSO' - /> - </Link> - <br/> - </div> - ); - } - - let ldapOption; - if (global.window.mm_config.EnableLdap === 'true' && user.auth_service === '') { - ldapOption = ( - <div className='padding-bottom x2'> - <Link - className='btn btn-primary' - to={'/claim/email_to_ldap?email=' + encodeURIComponent(user.email)} - > - <FormattedMessage - id='user.settings.security.switchLdap' - defaultMessage='Switch to using LDAP' - /> - </Link> - <br/> - </div> - ); - } - - let samlOption; - if (global.window.mm_config.EnableSaml === 'true' && user.auth_service === '') { - samlOption = ( - <div className='padding-bottom x2'> - <Link - className='btn btn-primary' - to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.SAML_SERVICE} - > - <FormattedMessage - id='user.settings.security.switchSaml' - defaultMessage='Switch to using SAML SSO' - /> - </Link> - <br/> - </div> - ); - } - const inputs = []; inputs.push( <div key='userSignInOption'> {emailOption} {gitlabOption} + {googleOption} + {office365Option} {ldapOption} {samlOption} - {googleOption} </div> ); @@ -693,7 +709,21 @@ class SecurityTab extends React.Component { describe = ( <FormattedMessage id='user.settings.security.gitlab' - defaultMessage='GitLab SSO' + defaultMessage='GitLab' + /> + ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + describe = ( + <FormattedMessage + id='user.settings.security.google' + defaultMessage='Google' + /> + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + describe = ( + <FormattedMessage + id='user.settings.security.office365' + defaultMessage='Office 365' /> ); } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) { diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index e78548fc4..9aa3a8e61 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://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.", "admin.gitlab.userExample": "Ex \"https://<your-gitlab-url>/api/v3/user\"", "admin.gitlab.userTitle": "User API Endpoint:", + "admin.google.EnableHtmlDesc": "<ol><li><a href='https://accounts.google.com/login'>Log in</a> to your Google account.</li><li>Go to <a href='https://console.developers.google.com'>https://console.developers.google.com</a>, click <strong>Credentials</strong> in the left hand sidebar and enter <strong>Mattermost - <your-company-name></strong> as the project name.</li><li>Click the <strong>OAuth consent screen</strong> header and enter <strong>Mattermost</strong> as the <strong>Product name to show users</strong>. Click <strong>Save</strong>.</li><li>Under the <strong>Credentials</strong> header, click <strong>Create credentials</strong>, choose <strong>OAuth client ID</strong> and select <strong>Web Application</strong>.</li><li>Under <strong>Restrictions</strong> and <strong>Authorized redirect URIs</strong> enter <strong><your-mattermost-url>/signup/google/complete</strong> (example: http://localhost:8065/signup/google/complete). Click <strong>Create</strong>.</li><li>Save the <strong>client ID</strong> and <strong>client secret</strong> to later complete the fields below.</li><li>Finally, go to <a href='https://console.developers.google.com/apis/api/plus/overview'>Google+ API</a> and click <strong>Enable</strong>. This might take a few minutes to propagate through Google's systems.</li><li>Complete the <strong>Client ID</strong> and <strong>Client Secret</strong> fields below.</li></ol>", + "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": "<ol><li><a href='https://login.microsoftonline.com/'>Log in</a> to your Microsoft or Office 365 account. Make sure it's the account on the same <a href='https://msdn.microsoft.com/en-us/library/azure/jj573650.aspx#Anchor_0'>tenant</a> that you would like users to log in with.</li><li>Go to <a href='https://apps.dev.microsoft.com'>https://apps.dev.microsoft.com</a>, click <strong>Add an app</strong> and use <strong>Mattermost - <your-company-name></strong> as the application name.</li><li>Under <strong>Application Secrets</strong>, click <strong>Generate New Password</strong> and save it to later complete the field below.</li><li>Under <strong>Platforms</strong>, click <strong>Add Platform</strong>, choose <strong>Web</strong> and enter <strong><your-mattermost-url>/signup/office365/complete</strong> (example: http://localhost:8065/signup/office365/complete) under <strong>Redirect URIs</strong>. Also uncheck <strong>Allow Implicit Flow</strong>.</li><li>Finally, click <strong>Save</strong> and complete the <strong>Application ID</strong> and <strong>Application Secret Password</strong> fields below.</li></ol>", + "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}<br />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 Binary files differnew file mode 100644 index 000000000..59670460e --- /dev/null +++ b/webapp/images/office365Logo.png diff --git a/webapp/routes/route_admin_console.jsx b/webapp/routes/route_admin_console.jsx index 1465bfa6b..291ba65f8 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'; @@ -89,6 +90,10 @@ export default ( component={GitLabSettings} /> <Route + path='oauth' + component={OAuthSettings} + /> + <Route path='ldap' component={LdapSettings} /> diff --git a/webapp/sass/routes/_signup.scss b/webapp/sass/routes/_signup.scss index 804e4c890..8315f8890 100644 --- a/webapp/sass/routes/_signup.scss +++ b/webapp/sass/routes/_signup.scss @@ -256,6 +256,23 @@ } } + &.office365 { + background: #0079d6; + + &:hover { + background: darken(#0079d6, 10%); + } + + span { + vertical-align: middle; + } + + .icon { + margin-left:-10px; + background-image: url('../images/office365Logo.png'); + } + } + &.ldap { background: #dd4b39; diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index 2b7a1564e..6c0014ac7 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -267,6 +267,7 @@ export const Constants = { OFFTOPIC_CHANNEL_UI_NAME: 'Off-Topic', GITLAB_SERVICE: 'gitlab', GOOGLE_SERVICE: 'google', + OFFICE365_SERVICE: 'office365', EMAIL_SERVICE: 'email', LDAP_SERVICE: 'ldap', SAML_SERVICE: 'saml', |