| @@ -40,7 +40,7 @@ const ( | |||
| LoginDLDAP // 5 | |||
| LoginOAuth2 // 6 | |||
| LoginSSPI // 7 | |||
| LoginCloubBrain // 8 | |||
| LoginCloudBrain // 8 | |||
| ) | |||
| // LoginNames contains the name of LoginType values. | |||
| @@ -51,7 +51,7 @@ var LoginNames = map[LoginType]string{ | |||
| LoginPAM: "PAM", | |||
| LoginOAuth2: "OAuth2", | |||
| LoginSSPI: "SPNEGO with SSPI", | |||
| LoginCloubBrain: "Cloud Brain", | |||
| LoginCloudBrain: "Cloud Brain", | |||
| } | |||
| // SecurityProtocolNames contains the name of SecurityProtocol values. | |||
| @@ -202,6 +202,8 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) { | |||
| source.Cfg = new(OAuth2Config) | |||
| case LoginSSPI: | |||
| source.Cfg = new(SSPIConfig) | |||
| case LoginCloudBrain: | |||
| source.Cfg = new(CloudBrainConfig) | |||
| default: | |||
| panic("unrecognized login source type: " + com.ToStr(*val)) | |||
| } | |||
| @@ -717,7 +719,7 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource) | |||
| user, err = LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig)) | |||
| case LoginPAM: | |||
| user, err = LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig)) | |||
| case LoginCloubBrain: | |||
| case LoginCloudBrain: | |||
| user, err = LoginViaCloudBrain(user, login, password, source) | |||
| default: | |||
| return nil, ErrUnsupportedLoginType | |||
| @@ -831,12 +833,16 @@ func LoginViaCloudBrain(user *User, login, password string, source *LoginSource) | |||
| } | |||
| if user != nil { | |||
| //todo: update token | |||
| user.Token = token | |||
| return user, UpdateUserCols(user, "token") | |||
| } | |||
| cloudBrainUser, err := cloudbrain.GetUserInfo(token, login) | |||
| cloudBrainUser, err := cloudbrain.GetUserInfo(login, token) | |||
| if err != nil { | |||
| log.Error("GetUserInfo(%s) failed: %v", login, err) | |||
| return nil, err | |||
| } | |||
| if len(cloudBrainUser.Email) == 0 { | |||
| cloudBrainUser.Email = fmt.Sprintf("%s@cloudbrain", login) | |||
| @@ -31,7 +31,7 @@ type RespAuth struct { | |||
| type RespToken struct { | |||
| Code string `json:"code"` | |||
| Message string `json:"message"` | |||
| Message string `json:"msg"` | |||
| Payload PayloadToken `json:"payload"` | |||
| } | |||
| @@ -43,7 +43,7 @@ type PayloadToken struct { | |||
| type RespUserInfo struct { | |||
| Code string `json:"code"` | |||
| Message string `json:"message"` | |||
| Message string `json:"msg"` | |||
| Payload PayloadUserInfo `json:"payload"` | |||
| } | |||
| @@ -71,6 +71,8 @@ func UserValidate(username string, password string) (string, error) { | |||
| return "", err | |||
| } | |||
| defer resp.Body.Close() | |||
| body,err := ioutil.ReadAll(resp.Body) | |||
| if err != nil { | |||
| log.Error("read resp body failed:" + err.Error()) | |||
| @@ -109,6 +111,8 @@ func GetUserInfo(username string, token string) (*CloudBrainUser, error) { | |||
| return nil, err | |||
| } | |||
| defer resp.Body.Close() | |||
| body,err := ioutil.ReadAll(resp.Body) | |||
| if err != nil { | |||
| log.Error("read resp body failed:", err.Error()) | |||
| @@ -192,6 +192,7 @@ no_reply_address_helper=具有隐藏电子邮件地址的用户的域名。例 | |||
| [home] | |||
| uname_holder=登录名或电子邮箱地址 | |||
| uname_holder_cloud_brain=云脑登录名 | |||
| password_holder=密码 | |||
| switch_dashboard_context=切换控制面板用户 | |||
| my_repos=项目列表 | |||
| @@ -267,6 +268,7 @@ twofa_passcode_incorrect=你的验证码不正确。如果你丢失了你的设 | |||
| twofa_scratch_token_incorrect=你的验证口令不正确。 | |||
| login_userpass=登录 | |||
| login_openid=OpenID | |||
| login_cloudbrain=云脑用户登录 | |||
| oauth_signup_tab=注册帐号 | |||
| oauth_signup_title=添加电子邮件和密码 (用于帐号恢复) | |||
| oauth_signup_submit=完成账号 | |||
| @@ -305,6 +305,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| // ***** START: User ***** | |||
| m.Group("/user", func() { | |||
| m.Get("/login", user.SignIn) | |||
| m.Get("/login/cloud_brain", user.SignInCloudBrain) | |||
| m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost) | |||
| m.Group("", func() { | |||
| m.Combo("/login/openid"). | |||
| @@ -36,6 +36,8 @@ const ( | |||
| tplMustChangePassword = "user/auth/change_passwd" | |||
| // tplSignIn template for sign in page | |||
| tplSignIn base.TplName = "user/auth/signin" | |||
| // tplSignIn template for sign in page | |||
| tplSignInCloudBrain base.TplName = "user/auth/signin_cloud_brain" | |||
| // tplSignUp template path for sign up page | |||
| tplSignUp base.TplName = "user/auth/signup" | |||
| // TplActivate template path for activate user | |||
| @@ -143,10 +145,28 @@ func SignIn(ctx *context.Context) { | |||
| ctx.Data["PageIsSignIn"] = true | |||
| ctx.Data["PageIsLogin"] = true | |||
| ctx.Data["EnableSSPI"] = models.IsSSPIEnabled() | |||
| ctx.Data["EnableCloudBrain"] = true | |||
| ctx.HTML(200, tplSignIn) | |||
| } | |||
| // SignInCloudBrain render sign in page | |||
| func SignInCloudBrain(ctx *context.Context) { | |||
| ctx.Data["Title"] = ctx.Tr("sign_in") | |||
| // Check auto-login. | |||
| if checkAutoLogin(ctx) { | |||
| return | |||
| } | |||
| ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" | |||
| ctx.Data["PageIsSignIn"] = true | |||
| ctx.Data["PageIsCloudBrainLogin"] = true | |||
| ctx.Data["EnableCloudBrain"] = true | |||
| ctx.HTML(200, tplSignInCloudBrain) | |||
| } | |||
| // SignInPost response for sign in request | |||
| func SignInPost(ctx *context.Context, form auth.SignInForm) { | |||
| ctx.Data["Title"] = ctx.Tr("sign_in") | |||
| @@ -0,0 +1,10 @@ | |||
| {{template "base/head" .}} | |||
| <div class="user signin"> | |||
| {{template "user/auth/signin_navbar" .}} | |||
| <div class="ui container"> | |||
| <div class="ui raised very padded text container segment"> | |||
| {{template "user/auth/signin_cloudbrain" .}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -0,0 +1,55 @@ | |||
| <style> | |||
| .full.height{background-color: #F9F9F9;} | |||
| .ui.left:not(.action){ float:none;} | |||
| .ui.left{ float:none;} | |||
| .ui.secondary.pointing.menu{ border-bottom:none;} | |||
| </style> | |||
| {{template "base/alert" .}} | |||
| <div class="ui centered grid"> | |||
| <div class="sixteen wide mobile ten wide tablet ten wide computer column"> | |||
| <div class="ui bottom aligned two column grid"> | |||
| <div class="column"> | |||
| <h2 class="ui header"> | |||
| {{.i18n.Tr "auth.login_userpass"}} | |||
| </h2> | |||
| </div> | |||
| </div> | |||
| <div class="ui grid"> | |||
| <div class="column"> | |||
| <form class="ui form" action="{{.SignInLink}}" method="post"> | |||
| {{.CsrfTokenHtml}} | |||
| <div class="field"> | |||
| <div class="ui left icon input {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}"> | |||
| <i class="user icon"></i> | |||
| <input id="user_name" name="user_name" value="{{.user_name}}" placeholder="{{.i18n.Tr "home.uname_holder_cloud_brain"}}" autofocus required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <div class="ui left icon input {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}"> | |||
| <i class="lock icon"></i> | |||
| <input id="password" name="password" type="password" value="{{.password}}" placeholder="{{.i18n.Tr "password"}}" autocomplete="off" required> | |||
| </div> | |||
| </div> | |||
| <div class="two fields inline"> | |||
| <div class="field"> | |||
| <div class="ui checkbox"> | |||
| <label>{{.i18n.Tr "auth.remember_me"}}</label> | |||
| <input name="remember" type="checkbox"> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="ui hidden divider"></div> | |||
| <div class="center aligned field"> | |||
| <button class="fluid large ui blue button"> | |||
| {{.i18n.Tr "sign_in"}} | |||
| </button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -1,8 +1,11 @@ | |||
| {{if or .EnableOpenIDSignIn .EnableSSPI}} | |||
| {{if or .EnableOpenIDSignIn .EnableSSPI .EnableCloudBrain}} | |||
| <div class="ui secondary pointing tabular top attached borderless menu new-menu navbar"> | |||
| <a class="{{if .PageIsLogin}}active{{end}} item" rel="nofollow" href="{{AppSubUrl}}/user/login"> | |||
| {{.i18n.Tr "auth.login_userpass"}} | |||
| </a> | |||
| <a class="{{if .PageIsCloudBrainLogin}}active{{end}} item" rel="nofollow" href="{{AppSubUrl}}/user/login/cloud_brain"> | |||
| {{.i18n.Tr "auth.login_cloudbrain"}} | |||
| </a> | |||
| {{if .EnableOpenIDSignIn}} | |||
| <a class="{{if .PageIsLoginOpenID}}active{{end}} item" rel="nofollow" href="{{AppSubUrl}}/user/login/openid"> | |||
| <i class="fa fa-openid"></i> | |||