mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-26 17:18:19 +00:00
added org and open registration
This commit is contained in:
parent
ebd547deac
commit
53eac09f34
5 changed files with 341 additions and 165 deletions
|
@ -334,16 +334,6 @@ func start(c *cli.Context) error {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupConfig(c *cli.Context) *server.Config {
|
|
||||||
return &server.Config{
|
|
||||||
Open: c.Bool("open"),
|
|
||||||
Yaml: c.String("yaml"),
|
|
||||||
Secret: c.String("agent-secret"),
|
|
||||||
Admins: c.StringSlice("admin"),
|
|
||||||
Orgs: c.StringSlice("orgs"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupCache(c *cli.Context) cache.Cache {
|
func setupCache(c *cli.Context) cache.Cache {
|
||||||
return cache.NewTTL(
|
return cache.NewTTL(
|
||||||
c.Duration("cache-ttl"),
|
c.Duration("cache-ttl"),
|
||||||
|
@ -444,6 +434,24 @@ func setupGithub(c *cli.Context) (remote.Remote, error) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupConfig(c *cli.Context) *server.Config {
|
||||||
|
return &server.Config{
|
||||||
|
Open: c.Bool("open"),
|
||||||
|
Yaml: c.String("yaml"),
|
||||||
|
Secret: c.String("agent-secret"),
|
||||||
|
Admins: sliceToMap(c.StringSlice("admin")),
|
||||||
|
Orgs: sliceToMap(c.StringSlice("orgs")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sliceToMap(s []string) map[string]bool {
|
||||||
|
v := map[string]bool{}
|
||||||
|
for _, ss := range s {
|
||||||
|
v[ss] = true
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func printSecret(c *cli.Context) error {
|
func printSecret(c *cli.Context) error {
|
||||||
secret := c.String("agent-secret")
|
secret := c.String("agent-secret")
|
||||||
if secret == "" {
|
if secret == "" {
|
||||||
|
|
|
@ -77,3 +77,9 @@ func HandlerAgent(v string) gin.HandlerFunc {
|
||||||
c.Set(k, v)
|
c.Set(k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToConfig returns the config from the Context
|
||||||
|
func ToConfig(c *gin.Context) *Config {
|
||||||
|
v := c.MustGet("config")
|
||||||
|
return v.(*Config)
|
||||||
|
}
|
||||||
|
|
161
server/login.go
Normal file
161
server/login.go
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/drone/drone/model"
|
||||||
|
"github.com/drone/drone/remote"
|
||||||
|
"github.com/drone/drone/shared/crypto"
|
||||||
|
"github.com/drone/drone/shared/httputil"
|
||||||
|
"github.com/drone/drone/shared/token"
|
||||||
|
"github.com/drone/drone/store"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetLogin(c *gin.Context) {
|
||||||
|
|
||||||
|
// when dealing with redirects we may need to adjust the content type. I
|
||||||
|
// cannot, however, remember why, so need to revisit this line.
|
||||||
|
c.Writer.Header().Del("Content-Type")
|
||||||
|
|
||||||
|
tmpuser, err := remote.Login(c, c.Writer, c.Request)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("cannot authenticate user. %s", err)
|
||||||
|
c.Redirect(303, "/login?error=oauth_error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// this will happen when the user is redirected by the remote provider as
|
||||||
|
// part of the authorization workflow.
|
||||||
|
if tmpuser == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
config := ToConfig(c)
|
||||||
|
|
||||||
|
// get the user from the database
|
||||||
|
u, err := store.GetUserLogin(c, tmpuser.Login)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// if self-registration is disabled we should return a not authorized error
|
||||||
|
if !config.Open {
|
||||||
|
logrus.Errorf("cannot register %s. registration closed", tmpuser.Login)
|
||||||
|
c.Redirect(303, "/login?error=access_denied")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the user account
|
||||||
|
u = &model.User{
|
||||||
|
Login: tmpuser.Login,
|
||||||
|
Token: tmpuser.Token,
|
||||||
|
Secret: tmpuser.Secret,
|
||||||
|
Email: tmpuser.Email,
|
||||||
|
Avatar: tmpuser.Avatar,
|
||||||
|
Hash: crypto.Rand(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the user into the database
|
||||||
|
if err := store.CreateUser(c, u); err != nil {
|
||||||
|
logrus.Errorf("cannot insert %s. %s", u.Login, err)
|
||||||
|
c.Redirect(303, "/login?error=internal_error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the user meta data and authorization data.
|
||||||
|
u.Token = tmpuser.Token
|
||||||
|
u.Secret = tmpuser.Secret
|
||||||
|
u.Email = tmpuser.Email
|
||||||
|
u.Avatar = tmpuser.Avatar
|
||||||
|
|
||||||
|
if err := store.UpdateUser(c, u); err != nil {
|
||||||
|
logrus.Errorf("cannot update %s. %s", u.Login, err)
|
||||||
|
c.Redirect(303, "/login?error=internal_error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Orgs) != 0 {
|
||||||
|
teams, terr := remote.Teams(c, u)
|
||||||
|
if terr != nil {
|
||||||
|
logrus.Errorf("cannot verify team membership for %s. %s.", tmpuser.Login, terr)
|
||||||
|
c.Redirect(303, "/login?error=access_denied")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var member bool
|
||||||
|
for _, team := range teams {
|
||||||
|
if config.Orgs[team.Login] {
|
||||||
|
member = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !member {
|
||||||
|
logrus.Errorf("cannot verify team membership for %s. %s.", tmpuser.Login, terr)
|
||||||
|
c.Redirect(303, "/login?error=access_denied")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exp := time.Now().Add(time.Hour * 72).Unix()
|
||||||
|
token := token.New(token.SessToken, u.Login)
|
||||||
|
tokenstr, err := token.SignExpires(u.Hash, exp)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("cannot create token for %s. %s", u.Login, err)
|
||||||
|
c.Redirect(303, "/login?error=internal_error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr)
|
||||||
|
redirect := httputil.GetCookie(c.Request, "user_last")
|
||||||
|
if len(redirect) == 0 {
|
||||||
|
redirect = "/"
|
||||||
|
}
|
||||||
|
c.Redirect(303, redirect)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLogout(c *gin.Context) {
|
||||||
|
httputil.DelCookie(c.Writer, c.Request, "user_sess")
|
||||||
|
httputil.DelCookie(c.Writer, c.Request, "user_last")
|
||||||
|
c.Redirect(303, "/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLoginToken(c *gin.Context) {
|
||||||
|
in := &tokenPayload{}
|
||||||
|
err := c.Bind(in)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
login, err := remote.Auth(c, in.Access, in.Refresh)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusUnauthorized, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := store.GetUserLogin(c, login)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusNotFound, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exp := time.Now().Add(time.Hour * 72).Unix()
|
||||||
|
token := token.New(token.SessToken, user.Login)
|
||||||
|
tokenstr, err := token.SignExpires(user.Hash, exp)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IndentedJSON(http.StatusOK, &tokenPayload{
|
||||||
|
Access: tokenstr,
|
||||||
|
Expires: exp - time.Now().Unix(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenPayload struct {
|
||||||
|
Access string `json:"access_token,omitempty"`
|
||||||
|
Refresh string `json:"refresh_token,omitempty"`
|
||||||
|
Expires int64 `json:"expires_in,omitempty"`
|
||||||
|
}
|
|
@ -27,11 +27,11 @@ import (
|
||||||
|
|
||||||
// Config defines system configuration parameters.
|
// Config defines system configuration parameters.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Open bool // Enables open registration
|
Open bool // Enables open registration
|
||||||
Yaml string // Customize the Yaml configuration file name
|
Yaml string // Customize the Yaml configuration file name
|
||||||
Secret string // Secret token used to authenticate agents
|
Secret string // Secret token used to authenticate agents
|
||||||
Admins []string // Administrative users
|
Admins map[string]bool // Administrative users
|
||||||
Orgs []string // Organization whitelist
|
Orgs map[string]bool // Organization whitelist
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server defines the server configuration.
|
// Server defines the server configuration.
|
||||||
|
@ -75,7 +75,7 @@ func (s *Server) Handler() http.Handler {
|
||||||
e.GET("/repos", web.ShowAllRepos)
|
e.GET("/repos", web.ShowAllRepos)
|
||||||
e.GET("/login", web.ShowLogin)
|
e.GET("/login", web.ShowLogin)
|
||||||
e.GET("/login/form", web.ShowLoginForm)
|
e.GET("/login/form", web.ShowLoginForm)
|
||||||
e.GET("/logout", web.GetLogout)
|
e.GET("/logout", GetLogout)
|
||||||
|
|
||||||
// TODO below will Go away with React UI
|
// TODO below will Go away with React UI
|
||||||
settings := e.Group("/settings")
|
settings := e.Group("/settings")
|
||||||
|
@ -172,9 +172,9 @@ func (s *Server) Handler() http.Handler {
|
||||||
|
|
||||||
auth := e.Group("/authorize")
|
auth := e.Group("/authorize")
|
||||||
{
|
{
|
||||||
auth.GET("", web.GetLogin)
|
auth.GET("", GetLogin)
|
||||||
auth.POST("", web.GetLogin)
|
auth.POST("", GetLogin)
|
||||||
auth.POST("/token", web.GetLoginToken)
|
auth.POST("/token", GetLoginToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
queue := e.Group("/api/queue")
|
queue := e.Group("/api/queue")
|
||||||
|
|
293
web/login.go
293
web/login.go
|
@ -1,148 +1,149 @@
|
||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
//
|
||||||
"net/http"
|
// import (
|
||||||
"time"
|
// "net/http"
|
||||||
|
// "time"
|
||||||
"github.com/gin-gonic/gin"
|
//
|
||||||
|
// "github.com/drone/drone/model"
|
||||||
log "github.com/Sirupsen/logrus"
|
// "github.com/drone/drone/remote"
|
||||||
"github.com/drone/drone/model"
|
// "github.com/drone/drone/shared/crypto"
|
||||||
"github.com/drone/drone/remote"
|
// "github.com/drone/drone/shared/httputil"
|
||||||
"github.com/drone/drone/shared/crypto"
|
// "github.com/drone/drone/shared/token"
|
||||||
"github.com/drone/drone/shared/httputil"
|
// "github.com/drone/drone/store"
|
||||||
"github.com/drone/drone/shared/token"
|
//
|
||||||
"github.com/drone/drone/store"
|
// "github.com/Sirupsen/logrus"
|
||||||
)
|
// "github.com/gin-gonic/gin"
|
||||||
|
// )
|
||||||
func GetLogin(c *gin.Context) {
|
//
|
||||||
remote := remote.FromContext(c)
|
// func GetLogin(c *gin.Context) {
|
||||||
|
// remote := remote.FromContext(c)
|
||||||
// when dealing with redirects we may need
|
//
|
||||||
// to adjust the content type. I cannot, however,
|
// // when dealing with redirects we may need
|
||||||
// remember why, so need to revisit this line.
|
// // to adjust the content type. I cannot, however,
|
||||||
c.Writer.Header().Del("Content-Type")
|
// // remember why, so need to revisit this line.
|
||||||
|
// c.Writer.Header().Del("Content-Type")
|
||||||
tmpuser, err := remote.Login(c.Writer, c.Request)
|
//
|
||||||
if err != nil {
|
// tmpuser, err := remote.Login(c.Writer, c.Request)
|
||||||
log.Errorf("cannot authenticate user. %s", err)
|
// if err != nil {
|
||||||
c.Redirect(303, "/login?error=oauth_error")
|
// logrus.Errorf("cannot authenticate user. %s", err)
|
||||||
return
|
// c.Redirect(303, "/login?error=oauth_error")
|
||||||
}
|
// return
|
||||||
// this will happen when the user is redirected by
|
// }
|
||||||
// the remote provide as part of the oauth dance.
|
// // this will happen when the user is redirected by
|
||||||
if tmpuser == nil {
|
// // the remote provide as part of the oauth dance.
|
||||||
return
|
// if tmpuser == nil {
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
var open = false // TODO get this from context
|
//
|
||||||
|
// var open = false // TODO get this from context
|
||||||
// get the user from the database
|
//
|
||||||
u, err := store.GetUserLogin(c, tmpuser.Login)
|
// // get the user from the database
|
||||||
if err != nil {
|
// u, err := store.GetUserLogin(c, tmpuser.Login)
|
||||||
|
// if err != nil {
|
||||||
// if self-registration is disabled we should
|
//
|
||||||
// return a notAuthorized error. the only exception
|
// // if self-registration is disabled we should
|
||||||
// is if no users exist yet in the system we'll proceed.
|
// // return a notAuthorized error. the only exception
|
||||||
if !open {
|
// // is if no users exist yet in the system we'll proceed.
|
||||||
log.Errorf("cannot register %s. registration closed", tmpuser.Login)
|
// if !open {
|
||||||
c.Redirect(303, "/login?error=access_denied")
|
// logrus.Errorf("cannot register %s. registration closed", tmpuser.Login)
|
||||||
return
|
// c.Redirect(303, "/login?error=access_denied")
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
// create the user account
|
//
|
||||||
u = &model.User{}
|
// // create the user account
|
||||||
u.Login = tmpuser.Login
|
// u = &model.User{}
|
||||||
u.Token = tmpuser.Token
|
// u.Login = tmpuser.Login
|
||||||
u.Secret = tmpuser.Secret
|
// u.Token = tmpuser.Token
|
||||||
u.Email = tmpuser.Email
|
// u.Secret = tmpuser.Secret
|
||||||
u.Avatar = tmpuser.Avatar
|
// u.Email = tmpuser.Email
|
||||||
u.Hash = crypto.Rand()
|
// u.Avatar = tmpuser.Avatar
|
||||||
|
// u.Hash = crypto.Rand()
|
||||||
// insert the user into the database
|
//
|
||||||
if err := store.CreateUser(c, u); err != nil {
|
// // insert the user into the database
|
||||||
log.Errorf("cannot insert %s. %s", u.Login, err)
|
// if err := store.CreateUser(c, u); err != nil {
|
||||||
c.Redirect(303, "/login?error=internal_error")
|
// logrus.Errorf("cannot insert %s. %s", u.Login, err)
|
||||||
return
|
// c.Redirect(303, "/login?error=internal_error")
|
||||||
}
|
// return
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
// update the user meta data and authorization
|
//
|
||||||
// data and cache in the datastore.
|
// // update the user meta data and authorization
|
||||||
u.Token = tmpuser.Token
|
// // data and cache in the datastore.
|
||||||
u.Secret = tmpuser.Secret
|
// u.Token = tmpuser.Token
|
||||||
u.Email = tmpuser.Email
|
// u.Secret = tmpuser.Secret
|
||||||
u.Avatar = tmpuser.Avatar
|
// u.Email = tmpuser.Email
|
||||||
|
// u.Avatar = tmpuser.Avatar
|
||||||
if err := store.UpdateUser(c, u); err != nil {
|
//
|
||||||
log.Errorf("cannot update %s. %s", u.Login, err)
|
// if err := store.UpdateUser(c, u); err != nil {
|
||||||
c.Redirect(303, "/login?error=internal_error")
|
// logrus.Errorf("cannot update %s. %s", u.Login, err)
|
||||||
return
|
// c.Redirect(303, "/login?error=internal_error")
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
exp := time.Now().Add(time.Hour * 72).Unix()
|
//
|
||||||
token := token.New(token.SessToken, u.Login)
|
// exp := time.Now().Add(time.Hour * 72).Unix()
|
||||||
tokenstr, err := token.SignExpires(u.Hash, exp)
|
// token := token.New(token.SessToken, u.Login)
|
||||||
if err != nil {
|
// tokenstr, err := token.SignExpires(u.Hash, exp)
|
||||||
log.Errorf("cannot create token for %s. %s", u.Login, err)
|
// if err != nil {
|
||||||
c.Redirect(303, "/login?error=internal_error")
|
// logrus.Errorf("cannot create token for %s. %s", u.Login, err)
|
||||||
return
|
// c.Redirect(303, "/login?error=internal_error")
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr)
|
//
|
||||||
redirect := httputil.GetCookie(c.Request, "user_last")
|
// httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr)
|
||||||
if len(redirect) == 0 {
|
// redirect := httputil.GetCookie(c.Request, "user_last")
|
||||||
redirect = "/"
|
// if len(redirect) == 0 {
|
||||||
}
|
// redirect = "/"
|
||||||
c.Redirect(303, redirect)
|
// }
|
||||||
|
// c.Redirect(303, redirect)
|
||||||
}
|
//
|
||||||
|
// }
|
||||||
func GetLogout(c *gin.Context) {
|
//
|
||||||
|
// func GetLogout(c *gin.Context) {
|
||||||
httputil.DelCookie(c.Writer, c.Request, "user_sess")
|
//
|
||||||
httputil.DelCookie(c.Writer, c.Request, "user_last")
|
// httputil.DelCookie(c.Writer, c.Request, "user_sess")
|
||||||
c.Redirect(303, "/login")
|
// httputil.DelCookie(c.Writer, c.Request, "user_last")
|
||||||
}
|
// c.Redirect(303, "/login")
|
||||||
|
// }
|
||||||
func GetLoginToken(c *gin.Context) {
|
//
|
||||||
remote := remote.FromContext(c)
|
// func GetLoginToken(c *gin.Context) {
|
||||||
|
// remote := remote.FromContext(c)
|
||||||
in := &tokenPayload{}
|
//
|
||||||
err := c.Bind(in)
|
// in := &tokenPayload{}
|
||||||
if err != nil {
|
// err := c.Bind(in)
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
// if err != nil {
|
||||||
return
|
// c.AbortWithError(http.StatusBadRequest, err)
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
login, err := remote.Auth(in.Access, in.Refresh)
|
//
|
||||||
if err != nil {
|
// login, err := remote.Auth(in.Access, in.Refresh)
|
||||||
c.AbortWithError(http.StatusUnauthorized, err)
|
// if err != nil {
|
||||||
return
|
// c.AbortWithError(http.StatusUnauthorized, err)
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
user, err := store.GetUserLogin(c, login)
|
//
|
||||||
if err != nil {
|
// user, err := store.GetUserLogin(c, login)
|
||||||
c.AbortWithError(http.StatusNotFound, err)
|
// if err != nil {
|
||||||
return
|
// c.AbortWithError(http.StatusNotFound, err)
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
exp := time.Now().Add(time.Hour * 72).Unix()
|
//
|
||||||
token := token.New(token.SessToken, user.Login)
|
// exp := time.Now().Add(time.Hour * 72).Unix()
|
||||||
tokenstr, err := token.SignExpires(user.Hash, exp)
|
// token := token.New(token.SessToken, user.Login)
|
||||||
if err != nil {
|
// tokenstr, err := token.SignExpires(user.Hash, exp)
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
// if err != nil {
|
||||||
return
|
// c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
c.IndentedJSON(http.StatusOK, &tokenPayload{
|
//
|
||||||
Access: tokenstr,
|
// c.IndentedJSON(http.StatusOK, &tokenPayload{
|
||||||
Expires: exp - time.Now().Unix(),
|
// Access: tokenstr,
|
||||||
})
|
// Expires: exp - time.Now().Unix(),
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
type tokenPayload struct {
|
//
|
||||||
Access string `json:"access_token,omitempty"`
|
// type tokenPayload struct {
|
||||||
Refresh string `json:"refresh_token,omitempty"`
|
// Access string `json:"access_token,omitempty"`
|
||||||
Expires int64 `json:"expires_in,omitempty"`
|
// Refresh string `json:"refresh_token,omitempty"`
|
||||||
}
|
// Expires int64 `json:"expires_in,omitempty"`
|
||||||
|
// }
|
||||||
|
|
Loading…
Reference in a new issue