github.com/nhannv/mattermost-server@v5.11.1+incompatible/app/login.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "fmt" 8 "net/http" 9 "strings" 10 "time" 11 12 "github.com/avct/uasurfer" 13 "github.com/mattermost/mattermost-server/model" 14 "github.com/mattermost/mattermost-server/plugin" 15 "github.com/mattermost/mattermost-server/store" 16 ) 17 18 func (a *App) CheckForClientSideCert(r *http.Request) (string, string, string) { 19 pem := r.Header.Get("X-SSL-Client-Cert") // mapped to $ssl_client_cert from nginx 20 subject := r.Header.Get("X-SSL-Client-Cert-Subject-DN") // mapped to $ssl_client_s_dn from nginx 21 email := "" 22 23 if len(subject) > 0 { 24 for _, v := range strings.Split(subject, "/") { 25 kv := strings.Split(v, "=") 26 if len(kv) == 2 && kv[0] == "emailAddress" { 27 email = kv[1] 28 } 29 } 30 } 31 32 return pem, subject, email 33 } 34 35 func (a *App) AuthenticateUserForLogin(id, loginId, password, mfaToken string, ldapOnly bool) (user *model.User, err *model.AppError) { 36 // Do statistics 37 defer func() { 38 if a.Metrics != nil { 39 if user == nil || err != nil { 40 a.Metrics.IncrementLoginFail() 41 } else { 42 a.Metrics.IncrementLogin() 43 } 44 } 45 }() 46 47 if len(password) == 0 { 48 return nil, model.NewAppError("AuthenticateUserForLogin", "api.user.login.blank_pwd.app_error", nil, "", http.StatusBadRequest) 49 } 50 51 // Get the MM user we are trying to login 52 if user, err = a.GetUserForLogin(id, loginId); err != nil { 53 return nil, err 54 } 55 56 // If client side cert is enable and it's checking as a primary source 57 // then trust the proxy and cert that the correct user is supplied and allow 58 // them access 59 if *a.Config().ExperimentalSettings.ClientSideCertEnable && *a.Config().ExperimentalSettings.ClientSideCertCheck == model.CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH { 60 // Unless the user is a bot. 61 if err = checkUserNotBot(user); err != nil { 62 return nil, err 63 } 64 65 return user, nil 66 } 67 68 // and then authenticate them 69 if user, err = a.authenticateUser(user, password, mfaToken); err != nil { 70 return nil, err 71 } 72 73 return user, nil 74 } 75 76 func (a *App) GetUserForLogin(id, loginId string) (*model.User, *model.AppError) { 77 enableUsername := *a.Config().EmailSettings.EnableSignInWithUsername 78 enableEmail := *a.Config().EmailSettings.EnableSignInWithEmail 79 80 // If we are given a userID then fail if we can't find a user with that ID 81 if len(id) != 0 { 82 user, err := a.GetUser(id) 83 if err != nil { 84 if err.Id != store.MISSING_ACCOUNT_ERROR { 85 err.StatusCode = http.StatusInternalServerError 86 return nil, err 87 } 88 err.StatusCode = http.StatusBadRequest 89 return nil, err 90 } 91 return user, nil 92 } 93 94 // Try to get the user by username/email 95 if result := <-a.Srv.Store.User().GetForLogin(loginId, enableUsername, enableEmail); result.Err == nil { 96 return result.Data.(*model.User), nil 97 } 98 99 // Try to get the user with LDAP if enabled 100 if *a.Config().LdapSettings.Enable && a.Ldap != nil { 101 if ldapUser, err := a.Ldap.GetUser(loginId); err == nil { 102 if user, err := a.GetUserByAuth(ldapUser.AuthData, model.USER_AUTH_SERVICE_LDAP); err == nil { 103 return user, nil 104 } 105 return ldapUser, nil 106 } 107 } 108 109 return nil, model.NewAppError("GetUserForLogin", "store.sql_user.get_for_login.app_error", nil, "", http.StatusBadRequest) 110 } 111 112 func (a *App) DoLogin(w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) (*model.Session, *model.AppError) { 113 if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { 114 var rejectionReason string 115 pluginContext := a.PluginContext() 116 pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { 117 rejectionReason = hooks.UserWillLogIn(pluginContext, user) 118 return rejectionReason == "" 119 }, plugin.UserWillLogInId) 120 121 if rejectionReason != "" { 122 return nil, model.NewAppError("DoLogin", "Login rejected by plugin: "+rejectionReason, nil, "", http.StatusBadRequest) 123 } 124 } 125 126 session := &model.Session{UserId: user.Id, Roles: user.GetRawRoles(), DeviceId: deviceId, IsOAuth: false} 127 session.GenerateCSRF() 128 129 if len(deviceId) > 0 { 130 session.SetExpireInDays(*a.Config().ServiceSettings.SessionLengthMobileInDays) 131 132 // A special case where we logout of all other sessions with the same Id 133 if err := a.RevokeSessionsForDeviceId(user.Id, deviceId, ""); err != nil { 134 err.StatusCode = http.StatusInternalServerError 135 return nil, err 136 } 137 } else { 138 session.SetExpireInDays(*a.Config().ServiceSettings.SessionLengthWebInDays) 139 } 140 141 ua := uasurfer.Parse(r.UserAgent()) 142 143 plat := getPlatformName(ua) 144 os := getOSName(ua) 145 bname := getBrowserName(ua, r.UserAgent()) 146 bversion := getBrowserVersion(ua, r.UserAgent()) 147 148 session.AddProp(model.SESSION_PROP_PLATFORM, plat) 149 session.AddProp(model.SESSION_PROP_OS, os) 150 session.AddProp(model.SESSION_PROP_BROWSER, fmt.Sprintf("%v/%v", bname, bversion)) 151 152 var err *model.AppError 153 if session, err = a.CreateSession(session); err != nil { 154 err.StatusCode = http.StatusInternalServerError 155 return nil, err 156 } 157 158 w.Header().Set(model.HEADER_TOKEN, session.Token) 159 160 if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { 161 a.Srv.Go(func() { 162 pluginContext := a.PluginContext() 163 pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { 164 hooks.UserHasLoggedIn(pluginContext, user) 165 return true 166 }, plugin.UserHasLoggedInId) 167 }) 168 } 169 170 return session, nil 171 } 172 173 func (a *App) AttachSessionCookies(w http.ResponseWriter, r *http.Request, session *model.Session) { 174 secure := false 175 if GetProtocol(r) == "https" { 176 secure = true 177 } 178 179 maxAge := *a.Config().ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24 180 domain := a.GetCookieDomain() 181 expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0) 182 sessionCookie := &http.Cookie{ 183 Name: model.SESSION_COOKIE_TOKEN, 184 Value: session.Token, 185 Path: "/", 186 MaxAge: maxAge, 187 Expires: expiresAt, 188 HttpOnly: true, 189 Domain: domain, 190 Secure: secure, 191 } 192 193 userCookie := &http.Cookie{ 194 Name: model.SESSION_COOKIE_USER, 195 Value: session.UserId, 196 Path: "/", 197 MaxAge: maxAge, 198 Expires: expiresAt, 199 Domain: domain, 200 Secure: secure, 201 } 202 203 csrfCookie := &http.Cookie{ 204 Name: model.SESSION_COOKIE_CSRF, 205 Value: session.GetCSRF(), 206 Path: "/", 207 MaxAge: maxAge, 208 Expires: expiresAt, 209 Domain: domain, 210 Secure: secure, 211 } 212 213 http.SetCookie(w, sessionCookie) 214 http.SetCookie(w, userCookie) 215 http.SetCookie(w, csrfCookie) 216 } 217 218 func GetProtocol(r *http.Request) string { 219 if r.Header.Get(model.HEADER_FORWARDED_PROTO) == "https" || r.TLS != nil { 220 return "https" 221 } 222 return "http" 223 }