mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
API token -> API key rename
This commit is contained in:
parent
db371d2a5d
commit
951ce0a102
2
grafana
2
grafana
@ -1 +1 @@
|
||||
Subproject commit d2f21bc93e96d9ac36b1925c0b0b137a7edc94d2
|
||||
Subproject commit 11b74baf7920bcd4e39b5e77bfb49e6b08752dc2
|
@ -58,13 +58,13 @@ func Register(r *macaron.Macaron) {
|
||||
r.Delete("/users/:id", RemoveAccountUser)
|
||||
}, reqAccountAdmin)
|
||||
|
||||
// Token
|
||||
r.Group("/tokens", func() {
|
||||
// auth api keys
|
||||
r.Group("/auth/keys", func() {
|
||||
r.Combo("/").
|
||||
Get(GetTokens).
|
||||
Post(bind(m.AddTokenCommand{}), AddToken).
|
||||
Put(bind(m.UpdateTokenCommand{}), UpdateToken)
|
||||
r.Delete("/:id", DeleteToken)
|
||||
Get(GetApiKeys).
|
||||
Post(bind(m.AddApiKeyCommand{}), AddApiKey).
|
||||
Put(bind(m.UpdateApiKeyCommand{}), UpdateApiKey)
|
||||
r.Delete("/:id", DeleteApiKey)
|
||||
}, reqAccountAdmin)
|
||||
|
||||
// Data sources
|
||||
|
83
pkg/api/apikey.go
Normal file
83
pkg/api/apikey.go
Normal file
@ -0,0 +1,83 @@
|
||||
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"
|
||||
"github.com/torkelo/grafana-pro/pkg/util"
|
||||
)
|
||||
|
||||
func GetApiKeys(c *middleware.Context) {
|
||||
query := m.GetApiKeysQuery{AccountId: c.AccountId}
|
||||
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
c.JsonApiErr(500, "Failed to list api keys", err)
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]*m.ApiKeyDTO, len(query.Result))
|
||||
for i, t := range query.Result {
|
||||
result[i] = &m.ApiKeyDTO{
|
||||
Id: t.Id,
|
||||
Name: t.Name,
|
||||
Role: t.Role,
|
||||
Key: t.Key,
|
||||
}
|
||||
}
|
||||
c.JSON(200, result)
|
||||
}
|
||||
|
||||
func DeleteApiKey(c *middleware.Context) {
|
||||
id := c.ParamsInt64(":id")
|
||||
|
||||
cmd := &m.DeleteApiKeyCommand{Id: id, AccountId: c.AccountId}
|
||||
|
||||
err := bus.Dispatch(cmd)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to delete API key", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JsonOK("API key deleted")
|
||||
}
|
||||
|
||||
func AddApiKey(c *middleware.Context, cmd m.AddApiKeyCommand) {
|
||||
if !cmd.Role.IsValid() {
|
||||
c.JsonApiErr(400, "Invalid role specified", nil)
|
||||
return
|
||||
}
|
||||
|
||||
cmd.AccountId = c.AccountId
|
||||
cmd.Key = util.GetRandomString(64)
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
c.JsonApiErr(500, "Failed to add API key", err)
|
||||
return
|
||||
}
|
||||
|
||||
result := &m.ApiKeyDTO{
|
||||
Id: cmd.Result.Id,
|
||||
Name: cmd.Result.Name,
|
||||
Role: cmd.Result.Role,
|
||||
Key: cmd.Result.Key,
|
||||
}
|
||||
|
||||
c.JSON(200, result)
|
||||
}
|
||||
|
||||
func UpdateApiKey(c *middleware.Context, cmd m.UpdateApiKeyCommand) {
|
||||
if !cmd.Role.IsValid() {
|
||||
c.JsonApiErr(400, "Invalid role specified", nil)
|
||||
return
|
||||
}
|
||||
|
||||
cmd.AccountId = c.AccountId
|
||||
|
||||
err := bus.Dispatch(&cmd)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to update api key", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JsonOK("API key updated")
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
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"
|
||||
"github.com/torkelo/grafana-pro/pkg/util"
|
||||
)
|
||||
|
||||
func GetTokens(c *middleware.Context) {
|
||||
query := m.GetTokensQuery{AccountId: c.AccountId}
|
||||
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
c.JsonApiErr(500, "Failed to list tokens", err)
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]*m.TokenDTO, len(query.Result))
|
||||
for i, t := range query.Result {
|
||||
result[i] = &m.TokenDTO{
|
||||
Id: t.Id,
|
||||
Name: t.Name,
|
||||
Role: t.Role,
|
||||
Token: t.Token,
|
||||
}
|
||||
}
|
||||
c.JSON(200, result)
|
||||
}
|
||||
|
||||
func DeleteToken(c *middleware.Context) {
|
||||
id := c.ParamsInt64(":id")
|
||||
|
||||
cmd := &m.DeleteTokenCommand{Id: id, AccountId: c.AccountId}
|
||||
|
||||
err := bus.Dispatch(cmd)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to delete token", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JsonOK("Token deleted")
|
||||
}
|
||||
|
||||
func AddToken(c *middleware.Context, cmd m.AddTokenCommand) {
|
||||
if !cmd.Role.IsValid() {
|
||||
c.JsonApiErr(400, "Invalid role specified", nil)
|
||||
return
|
||||
}
|
||||
|
||||
cmd.AccountId = c.AccountId
|
||||
cmd.Token = util.GetRandomString(64)
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
c.JsonApiErr(500, "Failed to add token", err)
|
||||
return
|
||||
}
|
||||
|
||||
result := &m.TokenDTO{
|
||||
Id: cmd.Result.Id,
|
||||
Name: cmd.Result.Name,
|
||||
Role: cmd.Result.Role,
|
||||
Token: cmd.Result.Token,
|
||||
}
|
||||
|
||||
c.JSON(200, result)
|
||||
}
|
||||
|
||||
func UpdateToken(c *middleware.Context, cmd m.UpdateTokenCommand) {
|
||||
if !cmd.Role.IsValid() {
|
||||
c.JsonApiErr(400, "Invalid role specified", nil)
|
||||
return
|
||||
}
|
||||
|
||||
cmd.AccountId = c.AccountId
|
||||
|
||||
err := bus.Dispatch(&cmd)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to update token", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JsonOK("Token updated")
|
||||
}
|
@ -31,12 +31,12 @@ func getRequestUserId(c *Context) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func getApiToken(c *Context) string {
|
||||
func getApiKey(c *Context) string {
|
||||
header := c.Req.Header.Get("Authorization")
|
||||
parts := strings.SplitN(header, " ", 2)
|
||||
if len(parts) == 2 || parts[0] == "Bearer" {
|
||||
token := parts[1]
|
||||
return token
|
||||
key := parts[1]
|
||||
return key
|
||||
}
|
||||
|
||||
return ""
|
||||
|
@ -39,22 +39,22 @@ func GetContextHandler() macaron.Handler {
|
||||
ctx.IsSignedIn = true
|
||||
ctx.SignedInUser = query.Result
|
||||
}
|
||||
} else if token := getApiToken(ctx); token != "" {
|
||||
} else if key := getApiKey(ctx); key != "" {
|
||||
// Try API Key auth
|
||||
tokenQuery := m.GetTokenByTokenQuery{Token: token}
|
||||
if err := bus.Dispatch(&tokenQuery); err != nil {
|
||||
ctx.JsonApiErr(401, "Invalid token", err)
|
||||
keyQuery := m.GetApiKeyByKeyQuery{Key: key}
|
||||
if err := bus.Dispatch(&keyQuery); err != nil {
|
||||
ctx.JsonApiErr(401, "Invalid API key", err)
|
||||
return
|
||||
} else {
|
||||
tokenInfo := tokenQuery.Result
|
||||
keyInfo := keyQuery.Result
|
||||
|
||||
ctx.IsSignedIn = true
|
||||
ctx.SignedInUser = &m.SignedInUser{}
|
||||
|
||||
// TODO: fix this
|
||||
ctx.AccountRole = tokenInfo.Role
|
||||
ctx.ApiKeyId = tokenInfo.Id
|
||||
ctx.AccountId = tokenInfo.AccountId
|
||||
ctx.AccountRole = keyInfo.Role
|
||||
ctx.ApiKeyId = keyInfo.Id
|
||||
ctx.AccountId = keyInfo.AccountId
|
||||
}
|
||||
}
|
||||
|
||||
|
65
pkg/models/apikey.go
Normal file
65
pkg/models/apikey.go
Normal file
@ -0,0 +1,65 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrInvalidApiKey = errors.New("Invalid API Key")
|
||||
|
||||
type ApiKey struct {
|
||||
Id int64
|
||||
AccountId int64
|
||||
Name string
|
||||
Key string
|
||||
Role RoleType
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// COMMANDS
|
||||
type AddApiKeyCommand struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Role RoleType `json:"role" binding:"required"`
|
||||
AccountId int64 `json:"-"`
|
||||
Key string `json:"-"`
|
||||
|
||||
Result *ApiKey `json:"-"`
|
||||
}
|
||||
|
||||
type UpdateApiKeyCommand struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Role RoleType `json:"role"`
|
||||
|
||||
AccountId int64 `json:"-"`
|
||||
}
|
||||
|
||||
type DeleteApiKeyCommand struct {
|
||||
Id int64 `json:"id"`
|
||||
AccountId int64 `json:"-"`
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// QUERIES
|
||||
|
||||
type GetApiKeysQuery struct {
|
||||
AccountId int64
|
||||
Result []*ApiKey
|
||||
}
|
||||
|
||||
type GetApiKeyByKeyQuery struct {
|
||||
Key string
|
||||
Result *ApiKey
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// DTO & Projections
|
||||
|
||||
type ApiKeyDTO struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Role RoleType `json:"role"`
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrInvalidToken = errors.New("Invalid token")
|
||||
|
||||
type Token struct {
|
||||
Id int64
|
||||
AccountId int64 `xorm:"not null unique(uix_account_id_name)"`
|
||||
Name string `xorm:"not null unique(uix_account_id_name)"`
|
||||
Token string `xorm:"UNIQUE NOT NULL"`
|
||||
Role RoleType `xorm:"not null"`
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// COMMANDS
|
||||
type AddTokenCommand struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Role RoleType `json:"role" binding:"required"`
|
||||
AccountId int64 `json:"-"`
|
||||
Token string `json:"-"`
|
||||
Result *Token `json:"-"`
|
||||
}
|
||||
|
||||
type UpdateTokenCommand struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Role RoleType `json:"role"`
|
||||
|
||||
AccountId int64 `json:"-"`
|
||||
Result *Token `json:"-"`
|
||||
}
|
||||
|
||||
type DeleteTokenCommand struct {
|
||||
Id int64 `json:"id"`
|
||||
AccountId int64 `json:"-"`
|
||||
Result *Token `json:"-"`
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// QUERIES
|
||||
|
||||
type GetTokensQuery struct {
|
||||
AccountId int64
|
||||
Result []*Token
|
||||
}
|
||||
|
||||
type GetTokenByTokenQuery struct {
|
||||
Token string
|
||||
Result *Token
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// DTO & Projections
|
||||
|
||||
type TokenDTO struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token"`
|
||||
Role RoleType `json:"role"`
|
||||
}
|
@ -9,35 +9,35 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", GetTokens)
|
||||
bus.AddHandler("sql", GetTokenByToken)
|
||||
bus.AddHandler("sql", UpdateToken)
|
||||
bus.AddHandler("sql", DeleteToken)
|
||||
bus.AddHandler("sql", AddToken)
|
||||
bus.AddHandler("sql", GetApiKeys)
|
||||
bus.AddHandler("sql", GetApiKeyByKey)
|
||||
bus.AddHandler("sql", UpdateApiKey)
|
||||
bus.AddHandler("sql", DeleteApiKey)
|
||||
bus.AddHandler("sql", AddApiKey)
|
||||
}
|
||||
|
||||
func GetTokens(query *m.GetTokensQuery) error {
|
||||
func GetApiKeys(query *m.GetApiKeysQuery) error {
|
||||
sess := x.Limit(100, 0).Where("account_id=?", query.AccountId).Asc("name")
|
||||
|
||||
query.Result = make([]*m.Token, 0)
|
||||
query.Result = make([]*m.ApiKey, 0)
|
||||
return sess.Find(&query.Result)
|
||||
}
|
||||
|
||||
func DeleteToken(cmd *m.DeleteTokenCommand) error {
|
||||
func DeleteApiKey(cmd *m.DeleteApiKeyCommand) error {
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
var rawSql = "DELETE FROM token WHERE id=? and account_id=?"
|
||||
var rawSql = "DELETE FROM api_key WHERE id=? and account_id=?"
|
||||
_, err := sess.Exec(rawSql, cmd.Id, cmd.AccountId)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func AddToken(cmd *m.AddTokenCommand) error {
|
||||
func AddApiKey(cmd *m.AddApiKeyCommand) error {
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
t := m.Token{
|
||||
t := m.ApiKey{
|
||||
AccountId: cmd.AccountId,
|
||||
Name: cmd.Name,
|
||||
Role: cmd.Role,
|
||||
Token: cmd.Token,
|
||||
Key: cmd.Key,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
}
|
||||
@ -50,32 +50,30 @@ func AddToken(cmd *m.AddTokenCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateToken(cmd *m.UpdateTokenCommand) error {
|
||||
|
||||
func UpdateApiKey(cmd *m.UpdateApiKeyCommand) error {
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
t := m.Token{
|
||||
t := m.ApiKey{
|
||||
Id: cmd.Id,
|
||||
AccountId: cmd.AccountId,
|
||||
Name: cmd.Name,
|
||||
Role: cmd.Role,
|
||||
Updated: time.Now(),
|
||||
}
|
||||
|
||||
_, err := sess.Where("id=? and account_id=?", t.Id, t.AccountId).Update(&t)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func GetTokenByToken(query *m.GetTokenByTokenQuery) error {
|
||||
var token m.Token
|
||||
has, err := x.Where("token=?", query.Token).Get(&token)
|
||||
func GetApiKeyByKey(query *m.GetApiKeyByKeyQuery) error {
|
||||
var apikey m.ApiKey
|
||||
has, err := x.Where("key=?", query.Key).Get(&apikey)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has == false {
|
||||
return m.ErrInvalidToken
|
||||
return m.ErrInvalidApiKey
|
||||
}
|
||||
|
||||
query.Result = &token
|
||||
query.Result = &apikey
|
||||
return nil
|
||||
}
|
@ -2,13 +2,19 @@ package sqlstore
|
||||
|
||||
import . "github.com/torkelo/grafana-pro/pkg/services/sqlstore/migrator"
|
||||
|
||||
// --- Migration Guide line ---
|
||||
// 1. Never change a migration that is committed and pushed to master
|
||||
// 2. Always add new migrations (to change or undo previous migrations)
|
||||
// 3. Some migraitons are not yet written (rename column, table, drop table, index etc)
|
||||
// 4
|
||||
|
||||
func addMigrations(mg *Migrator) {
|
||||
addMigrationLogMigrations(mg)
|
||||
addUserMigrations(mg)
|
||||
addAccountMigrations(mg)
|
||||
addDashboardMigration(mg)
|
||||
addDataSourceMigration(mg)
|
||||
addTokenMigrations(mg)
|
||||
addApiKeyMigrations(mg)
|
||||
}
|
||||
|
||||
func addMigrationLogMigrations(mg *Migrator) {
|
||||
@ -131,19 +137,22 @@ func addDataSourceMigration(mg *Migrator) {
|
||||
Table("data_source").Columns("account_id", "name").Unique())
|
||||
}
|
||||
|
||||
func addTokenMigrations(mg *Migrator) {
|
||||
mg.AddMigration("create token table", new(AddTableMigration).
|
||||
Name("token").WithColumns(
|
||||
func addApiKeyMigrations(mg *Migrator) {
|
||||
mg.AddMigration("create api_key table", new(AddTableMigration).
|
||||
Name("api_key").WithColumns(
|
||||
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
&Column{Name: "account_id", Type: DB_BigInt, Nullable: false},
|
||||
&Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
&Column{Name: "token", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
&Column{Name: "key", Type: DB_Varchar, Length: 64, Nullable: false},
|
||||
&Column{Name: "role", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
&Column{Name: "created", Type: DB_DateTime, Nullable: false},
|
||||
&Column{Name: "updated", Type: DB_DateTime, Nullable: false},
|
||||
))
|
||||
|
||||
//------- indexes ------------------
|
||||
mg.AddMigration("add index token.account_id", new(AddIndexMigration).
|
||||
Table("token").Columns("account_id"))
|
||||
mg.AddMigration("add index api_key.account_id", new(AddIndexMigration).
|
||||
Table("api_key").Columns("account_id"))
|
||||
|
||||
mg.AddMigration("add index api_key.key", new(AddIndexMigration).
|
||||
Table("api_key").Columns("key").Unique())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user