initial server implementation for using google as a single-sign-on oauth service
Этот коммит содержится в:
@@ -1314,9 +1314,15 @@ func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, te
|
||||
|
||||
clientId := utils.Cfg.SSOSettings[service].Id
|
||||
endpoint := utils.Cfg.SSOSettings[service].AuthEndpoint
|
||||
scope := utils.Cfg.SSOSettings[service].Scope
|
||||
state := model.HashPassword(clientId)
|
||||
|
||||
authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri+"?team="+teamName) + "&state=" + url.QueryEscape(state)
|
||||
|
||||
if len(scope) > 0 {
|
||||
authUrl += "&scope=" + utils.UrlEncode(scope)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, authUrl, http.StatusFound)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,19 @@
|
||||
"Allow": false,
|
||||
"Secret" : "",
|
||||
"Id": "",
|
||||
"Scope": "",
|
||||
"AuthEndpoint": "",
|
||||
"TokenEndpoint": "",
|
||||
"UserApiEndpoint": ""
|
||||
},
|
||||
"google": {
|
||||
"Allow": true,
|
||||
"Secret": "hWN1kiPeyihN6nHr36j0oDqx",
|
||||
"Id": "974585606220-ek5q66olpagb069pkg9ok0d7h8djeov6.apps.googleusercontent.com",
|
||||
"Scope": "email profile",
|
||||
"AuthEndpoint": "https://accounts.google.com/o/oauth2/auth",
|
||||
"TokenEndpoint": "https://www.googleapis.com/oauth2/v3/token",
|
||||
"UserApiEndpoint": "https://www.googleapis.com/plus/v1/people/me"
|
||||
}
|
||||
},
|
||||
"SqlSettings": {
|
||||
|
||||
57
model/gitlab.go
Обычный файл
57
model/gitlab.go
Обычный файл
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
USER_AUTH_SERVICE_GITLAB = "gitlab"
|
||||
)
|
||||
|
||||
type GitLabUser struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func UserFromGitLabUser(glu *GitLabUser) *User {
|
||||
user := &User{}
|
||||
user.Username = glu.Username
|
||||
splitName := strings.Split(glu.Name, " ")
|
||||
if len(splitName) == 2 {
|
||||
user.FirstName = splitName[0]
|
||||
user.LastName = splitName[1]
|
||||
} else if len(splitName) >= 2 {
|
||||
user.FirstName = splitName[0]
|
||||
user.LastName = strings.Join(splitName[1:], " ")
|
||||
} else {
|
||||
user.FirstName = glu.Name
|
||||
}
|
||||
user.Email = glu.Email
|
||||
user.AuthData = strconv.FormatInt(glu.Id, 10)
|
||||
user.AuthService = USER_AUTH_SERVICE_GITLAB
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func GitLabUserFromJson(data io.Reader) *GitLabUser {
|
||||
decoder := json.NewDecoder(data)
|
||||
var glu GitLabUser
|
||||
err := decoder.Decode(&glu)
|
||||
if err == nil {
|
||||
return &glu
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (glu *GitLabUser) GetAuthData() string {
|
||||
return strconv.FormatInt(glu.Id, 10)
|
||||
}
|
||||
54
model/google.go
Обычный файл
54
model/google.go
Обычный файл
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
USER_AUTH_SERVICE_GOOGLE = "google"
|
||||
)
|
||||
|
||||
type GoogleUser struct {
|
||||
Id string `json:"id"`
|
||||
Nickname string `json:"nickname"`
|
||||
Emails []map[string]string `json:"emails"`
|
||||
Names map[string]string `json:"name"`
|
||||
}
|
||||
|
||||
func UserFromGoogleUser(gu *GoogleUser) *User {
|
||||
user := &User{}
|
||||
user.Username = gu.Nickname
|
||||
user.FirstName = gu.Names["givenName"]
|
||||
user.LastName = gu.Names["familyName"]
|
||||
user.Nickname = gu.Nickname
|
||||
|
||||
for _, e := range gu.Emails {
|
||||
if e["type"] == "account" {
|
||||
user.Email = e["value"]
|
||||
}
|
||||
}
|
||||
|
||||
user.AuthData = gu.Id
|
||||
user.AuthService = USER_AUTH_SERVICE_GOOGLE
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func GoogleUserFromJson(data io.Reader) *GoogleUser {
|
||||
decoder := json.NewDecoder(data)
|
||||
var gu GoogleUser
|
||||
err := decoder.Decode(&gu)
|
||||
if err == nil {
|
||||
return &gu
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (gu *GoogleUser) GetAuthData() string {
|
||||
return gu.Id
|
||||
}
|
||||
@@ -8,24 +8,22 @@ import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
ROLE_ADMIN = "admin"
|
||||
ROLE_SYSTEM_ADMIN = "system_admin"
|
||||
ROLE_SYSTEM_SUPPORT = "system_support"
|
||||
USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
|
||||
USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute
|
||||
USER_OFFLINE = "offline"
|
||||
USER_AWAY = "away"
|
||||
USER_ONLINE = "online"
|
||||
USER_NOTIFY_ALL = "all"
|
||||
USER_NOTIFY_MENTION = "mention"
|
||||
USER_NOTIFY_NONE = "none"
|
||||
BOT_USERNAME = "valet"
|
||||
USER_AUTH_SERVICE_GITLAB = "gitlab"
|
||||
ROLE_ADMIN = "admin"
|
||||
ROLE_SYSTEM_ADMIN = "system_admin"
|
||||
ROLE_SYSTEM_SUPPORT = "system_support"
|
||||
USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
|
||||
USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute
|
||||
USER_OFFLINE = "offline"
|
||||
USER_AWAY = "away"
|
||||
USER_ONLINE = "online"
|
||||
USER_NOTIFY_ALL = "all"
|
||||
USER_NOTIFY_MENTION = "mention"
|
||||
USER_NOTIFY_NONE = "none"
|
||||
BOT_USERNAME = "valet"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@@ -54,13 +52,6 @@ type User struct {
|
||||
FailedAttempts int `json:"failed_attempts"`
|
||||
}
|
||||
|
||||
type GitLabUser struct {
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// IsValid validates the user and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (u *User) IsValid() *AppError {
|
||||
@@ -355,38 +346,3 @@ func IsUsernameValid(username string) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func UserFromGitLabUser(glu *GitLabUser) *User {
|
||||
user := &User{}
|
||||
user.Username = glu.Username
|
||||
splitName := strings.Split(glu.Name, " ")
|
||||
if len(splitName) == 2 {
|
||||
user.FirstName = splitName[0]
|
||||
user.LastName = splitName[1]
|
||||
} else if len(splitName) >= 2 {
|
||||
user.FirstName = splitName[0]
|
||||
user.LastName = strings.Join(splitName[1:], " ")
|
||||
} else {
|
||||
user.FirstName = glu.Name
|
||||
}
|
||||
user.Email = glu.Email
|
||||
user.AuthData = strconv.FormatInt(glu.Id, 10)
|
||||
user.AuthService = USER_AUTH_SERVICE_GITLAB
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func GitLabUserFromJson(data io.Reader) *GitLabUser {
|
||||
decoder := json.NewDecoder(data)
|
||||
var glu GitLabUser
|
||||
err := decoder.Decode(&glu)
|
||||
if err == nil {
|
||||
return &glu
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (glu *GitLabUser) GetAuthData() string {
|
||||
return strconv.FormatInt(glu.Id, 10)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ type SSOSetting struct {
|
||||
Allow bool
|
||||
Secret string
|
||||
Id string
|
||||
Scope string
|
||||
AuthEndpoint string
|
||||
TokenEndpoint string
|
||||
UserApiEndpoint string
|
||||
|
||||
@@ -53,13 +53,13 @@ func InitWeb() {
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/", api.AppHandler(login)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/login", api.AppHandler(login)).Methods("GET")
|
||||
|
||||
// Bug in gorilla.mux pervents us from using regex here.
|
||||
// Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/login/{service}", api.AppHandler(loginWithOAuth)).Methods("GET")
|
||||
mainrouter.Handle("/login/{service:[A-Za-z]+}/complete", api.AppHandlerIndependent(loginCompleteOAuth)).Methods("GET")
|
||||
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/logout", api.AppHandler(logout)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/reset_password", api.AppHandler(resetPassword)).Methods("GET")
|
||||
// Bug in gorilla.mux pervents us from using regex here.
|
||||
// Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/channels/{channelname}", api.UserRequired(getChannel)).Methods("GET")
|
||||
|
||||
// Anything added here must have an _ in it so it does not conflict with team names
|
||||
@@ -67,7 +67,7 @@ func InitWeb() {
|
||||
mainrouter.Handle("/signup_user_complete/", api.AppHandlerIndependent(signupUserComplete)).Methods("GET")
|
||||
mainrouter.Handle("/signup_team_confirm/", api.AppHandlerIndependent(signupTeamConfirm)).Methods("GET")
|
||||
|
||||
// Bug in gorilla.mux pervents us from using regex here.
|
||||
// Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/signup/{service}", api.AppHandler(signupWithOAuth)).Methods("GET")
|
||||
mainrouter.Handle("/signup/{service:[A-Za-z]+}/complete", api.AppHandlerIndependent(signupCompleteOAuth)).Methods("GET")
|
||||
|
||||
@@ -532,6 +532,9 @@ func signupCompleteOAuth(c *api.Context, w http.ResponseWriter, r *http.Request)
|
||||
if service == model.USER_AUTH_SERVICE_GITLAB {
|
||||
glu := model.GitLabUserFromJson(body)
|
||||
user = model.UserFromGitLabUser(glu)
|
||||
} else if service == model.USER_AUTH_SERVICE_GOOGLE {
|
||||
gu := model.GoogleUserFromJson(body)
|
||||
user = model.UserFromGoogleUser(gu)
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user