diff --git a/pkg/api/admin_accounts.go b/pkg/api/admin_accounts.go new file mode 100644 index 00000000000..f897930ea7e --- /dev/null +++ b/pkg/api/admin_accounts.go @@ -0,0 +1,20 @@ +package api + +import ( + "github.com/torkelo/grafana-pro/pkg/bus" + "github.com/torkelo/grafana-pro/pkg/middleware" + m "github.com/torkelo/grafana-pro/pkg/models" +) + +func AdminSearchAccounts(c *middleware.Context) { + // query := c.QueryStrings("q") + // page := c.QueryStrings("p") + + query := m.SearchAccountsQuery{Query: "", Page: 0, Limit: 20} + if err := bus.Dispatch(&query); err != nil { + c.JsonApiErr(500, "Failed to fetch collaboratos", err) + return + } + + c.JSON(200, query.Result) +} diff --git a/pkg/api/api.go b/pkg/api/api.go index 5d1898e33e0..3d4f7e0e9c6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -9,20 +9,21 @@ import ( // Register adds http routes func Register(m *macaron.Macaron) { - auth := middleware.Auth() + reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true}) + reqAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqAdmin: false}) // not logged in views - m.Get("/", auth, Index) + m.Get("/", reqSignedIn, Index) m.Post("/logout", LogoutPost) m.Post("/login", LoginPost) m.Get("/login/:name", OAuthLogin) m.Get("/login", Index) // authed views - m.Get("/account/", auth, Index) - m.Get("/account/datasources/", auth, Index) - m.Get("/admin", auth, Index) - m.Get("/dashboard/*", auth, Index) + m.Get("/account/", reqSignedIn, Index) + m.Get("/account/datasources/", reqSignedIn, Index) + m.Get("/admin", reqSignedIn, Index) + m.Get("/dashboard/*", reqSignedIn, Index) // sign up m.Get("/signup", Index) @@ -47,7 +48,7 @@ func Register(m *macaron.Macaron) { m.Group("/datasources", func() { m.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(UpdateDataSource) m.Delete("/:id", DeleteDataSource) - m.Any("/proxy/:id/*", auth, ProxyDataSourceRequest) + m.Any("/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest) }) // Dashboard m.Group("/dashboard", func() { @@ -57,11 +58,16 @@ func Register(m *macaron.Macaron) { // Search m.Get("/search/", Search) // metrics - m.Get("/metrics/test", auth, GetTestMetrics) - }, auth) + m.Get("/metrics/test", GetTestMetrics) + }, reqSignedIn) + + // admin api + m.Group("/api/admin", func() { + m.Get("/accounts", AdminSearchAccounts) + }, reqAdmin) // rendering - m.Get("/render/*", auth, RenderToPng) + m.Get("/render/*", reqSignedIn, RenderToPng) m.NotFound(NotFound) } diff --git a/pkg/middleware/auth.go b/pkg/middleware/auth.go index f958a73f45e..d9837395689 100644 --- a/pkg/middleware/auth.go +++ b/pkg/middleware/auth.go @@ -12,27 +12,44 @@ import ( "github.com/torkelo/grafana-pro/pkg/setting" ) -func authGetRequestAccountId(c *Context) (int64, error) { +type AuthOptions struct { + ReqAdmin bool + ReqSignedIn bool +} + +func getRequestAccountId(c *Context) (int64, error) { accountId := c.Session.Get("accountId") - urlQuery := c.Req.URL.Query() + if accountId != nil { + return accountId.(int64), nil + } - // TODO: check that this is a localhost request + // localhost render query + urlQuery := c.Req.URL.Query() if len(urlQuery["render"]) > 0 { accId, _ := strconv.ParseInt(urlQuery["accountId"][0], 10, 64) c.Session.Set("accountId", accId) accountId = accId } - if accountId == nil { - if setting.Anonymous { - return setting.AnonymousAccountId, nil + // check api token + header := c.Req.Header.Get("Authorization") + parts := strings.SplitN(header, " ", 2) + if len(parts) == 2 || parts[0] == "Bearer" { + token := parts[1] + userQuery := m.GetAccountByTokenQuery{Token: token} + if err := bus.Dispatch(&userQuery); err != nil { + return -1, err } + return userQuery.Result.Id, nil + } - return -1, errors.New("Auth: session account id not found") + // anonymous gues user + if setting.Anonymous { + return setting.AnonymousAccountId, nil } - return accountId.(int64), nil + return -1, errors.New("Auth: session account id not found") } func authDenied(c *Context) { @@ -43,57 +60,17 @@ func authDenied(c *Context) { c.Redirect(setting.AppSubUrl + "/login") } -func authByToken(c *Context) { - header := c.Req.Header.Get("Authorization") - parts := strings.SplitN(header, " ", 2) - if len(parts) != 2 || parts[0] != "Bearer" { - return - } - token := parts[1] - userQuery := m.GetAccountByTokenQuery{Token: token} - - if err := bus.Dispatch(&userQuery); err != nil { - return - } - - usingQuery := m.GetAccountByIdQuery{Id: userQuery.Result.UsingAccountId} - if err := bus.Dispatch(&usingQuery); err != nil { - return - } - - c.UserAccount = userQuery.Result - c.Account = usingQuery.Result -} - -func authBySession(c *Context) { - accountId, err := authGetRequestAccountId(c) - - if err != nil && c.Req.URL.Path != "/login" { - authDenied(c) - return - } - - userQuery := m.GetAccountByIdQuery{Id: accountId} - if err := bus.Dispatch(&userQuery); err != nil { - authDenied(c) - return - } - - usingQuery := m.GetAccountByIdQuery{Id: userQuery.Result.UsingAccountId} - if err := bus.Dispatch(&usingQuery); err != nil { - authDenied(c) - return - } +func Auth(options *AuthOptions) macaron.Handler { + return func(c *Context) { - c.UserAccount = userQuery.Result - c.Account = usingQuery.Result -} + if !c.IsSignedIn && options.ReqSignedIn { + authDenied(c) + return + } -func Auth() macaron.Handler { - return func(c *Context) { - authByToken(c) - if c.UserAccount == nil { - authBySession(c) + if !c.IsAdmin && options.ReqAdmin { + authDenied(c) + return } } } diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 4e86df3eb35..b5f0b8da237 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -8,8 +8,9 @@ import ( "github.com/Unknwon/macaron" "github.com/macaron-contrib/session" + "github.com/torkelo/grafana-pro/pkg/bus" "github.com/torkelo/grafana-pro/pkg/log" - "github.com/torkelo/grafana-pro/pkg/models" + m "github.com/torkelo/grafana-pro/pkg/models" "github.com/torkelo/grafana-pro/pkg/setting" ) @@ -17,8 +18,11 @@ type Context struct { *macaron.Context Session session.Store - Account *models.Account - UserAccount *models.Account + IsSignedIn bool + IsAdmin bool + + Account *m.Account + UserAccount *m.Account } func (c *Context) GetAccountId() int64 { @@ -32,6 +36,29 @@ func GetContextHandler() macaron.Handler { Session: sess, } + // try get account id from request + if accountId, err := getRequestAccountId(ctx); err == nil { + // fetch user + userQuery := m.GetAccountByIdQuery{Id: accountId} + if err := bus.Dispatch(&userQuery); err != nil { + log.Error(3, "Failed to get user by id, %v, %v", accountId, err) + } else { + // fetch using account + ctx.UserAccount = userQuery.Result + usingQuery := m.GetAccountByIdQuery{Id: ctx.UserAccount.UsingAccountId} + if err := bus.Dispatch(&usingQuery); err != nil { + log.Error(3, "Faild to get account's using account, account: %v, usingAccountId: %v, err:%v", accountId, ctx.UserAccount.Id, err) + } else { + ctx.Account = usingQuery.Result + } + } + } + + if ctx.Account != nil { + ctx.IsSignedIn = true + ctx.IsAdmin = ctx.Account.IsAdmin + } + c.Map(ctx) } } diff --git a/pkg/models/account.go b/pkg/models/account.go index 1172d2740c5..8e4a897a58b 100644 --- a/pkg/models/account.go +++ b/pkg/models/account.go @@ -68,6 +68,14 @@ type GetAccountByLoginQuery struct { Result *Account } +type SearchAccountsQuery struct { + Query string + Page int + Limit int + + Result []*AccountSearchHitDTO +} + // ------------------------ // DTO & Projections @@ -84,6 +92,12 @@ type CollaboratorDTO struct { Role string `json:"role"` } +type AccountSearchHitDTO struct { + Id int64 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` +} + type AccountDTO struct { Email string `json:"email"` Name string `json:"name"` diff --git a/pkg/stores/sqlstore/accounts.go b/pkg/stores/sqlstore/accounts.go index 9072f0cc2db..76fbb288d81 100644 --- a/pkg/stores/sqlstore/accounts.go +++ b/pkg/stores/sqlstore/accounts.go @@ -19,6 +19,7 @@ func init() { bus.AddHandler("sql", GetAccountByToken) bus.AddHandler("sql", AddCollaborator) bus.AddHandler("sql", RemoveCollaborator) + bus.AddHandler("sql", SearchAccounts) } func CreateAccount(cmd *m.CreateAccountCommand) error { @@ -173,3 +174,14 @@ func GetOtherAccounts(query *m.GetOtherAccountsQuery) error { err := sess.Find(&query.Result) return err } + +func SearchAccounts(query *m.SearchAccountsQuery) error { + query.Result = make([]*m.AccountSearchHitDTO, 0) + sess := x.Table("account") + sess.Where("email LIKE ?", query.Query+"%") + sess.Limit(query.Limit, query.Limit*query.Page) + sess.Cols("id", "email", "name") + err := sess.Find(&query.Result) + return err + +}