API token -> API key rename

This commit is contained in:
Torkel Ödegaard
2015-01-27 08:26:11 +01:00
parent db371d2a5d
commit 951ce0a102
10 changed files with 201 additions and 195 deletions

Submodule grafana updated: d2f21bc93e...11b74baf79

View File

@ -58,13 +58,13 @@ func Register(r *macaron.Macaron) {
r.Delete("/users/:id", RemoveAccountUser) r.Delete("/users/:id", RemoveAccountUser)
}, reqAccountAdmin) }, reqAccountAdmin)
// Token // auth api keys
r.Group("/tokens", func() { r.Group("/auth/keys", func() {
r.Combo("/"). r.Combo("/").
Get(GetTokens). Get(GetApiKeys).
Post(bind(m.AddTokenCommand{}), AddToken). Post(bind(m.AddApiKeyCommand{}), AddApiKey).
Put(bind(m.UpdateTokenCommand{}), UpdateToken) Put(bind(m.UpdateApiKeyCommand{}), UpdateApiKey)
r.Delete("/:id", DeleteToken) r.Delete("/:id", DeleteApiKey)
}, reqAccountAdmin) }, reqAccountAdmin)
// Data sources // Data sources

83
pkg/api/apikey.go Normal file
View 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")
}

View File

@ -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")
}

View File

@ -31,12 +31,12 @@ func getRequestUserId(c *Context) int64 {
return 0 return 0
} }
func getApiToken(c *Context) string { func getApiKey(c *Context) string {
header := c.Req.Header.Get("Authorization") header := c.Req.Header.Get("Authorization")
parts := strings.SplitN(header, " ", 2) parts := strings.SplitN(header, " ", 2)
if len(parts) == 2 || parts[0] == "Bearer" { if len(parts) == 2 || parts[0] == "Bearer" {
token := parts[1] key := parts[1]
return token return key
} }
return "" return ""

View File

@ -39,22 +39,22 @@ func GetContextHandler() macaron.Handler {
ctx.IsSignedIn = true ctx.IsSignedIn = true
ctx.SignedInUser = query.Result ctx.SignedInUser = query.Result
} }
} else if token := getApiToken(ctx); token != "" { } else if key := getApiKey(ctx); key != "" {
// Try API Key auth // Try API Key auth
tokenQuery := m.GetTokenByTokenQuery{Token: token} keyQuery := m.GetApiKeyByKeyQuery{Key: key}
if err := bus.Dispatch(&tokenQuery); err != nil { if err := bus.Dispatch(&keyQuery); err != nil {
ctx.JsonApiErr(401, "Invalid token", err) ctx.JsonApiErr(401, "Invalid API key", err)
return return
} else { } else {
tokenInfo := tokenQuery.Result keyInfo := keyQuery.Result
ctx.IsSignedIn = true ctx.IsSignedIn = true
ctx.SignedInUser = &m.SignedInUser{} ctx.SignedInUser = &m.SignedInUser{}
// TODO: fix this // TODO: fix this
ctx.AccountRole = tokenInfo.Role ctx.AccountRole = keyInfo.Role
ctx.ApiKeyId = tokenInfo.Id ctx.ApiKeyId = keyInfo.Id
ctx.AccountId = tokenInfo.AccountId ctx.AccountId = keyInfo.AccountId
} }
} }

65
pkg/models/apikey.go Normal file
View 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"`
}

View File

@ -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"`
}

View File

@ -9,35 +9,35 @@ import (
) )
func init() { func init() {
bus.AddHandler("sql", GetTokens) bus.AddHandler("sql", GetApiKeys)
bus.AddHandler("sql", GetTokenByToken) bus.AddHandler("sql", GetApiKeyByKey)
bus.AddHandler("sql", UpdateToken) bus.AddHandler("sql", UpdateApiKey)
bus.AddHandler("sql", DeleteToken) bus.AddHandler("sql", DeleteApiKey)
bus.AddHandler("sql", AddToken) 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") 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) return sess.Find(&query.Result)
} }
func DeleteToken(cmd *m.DeleteTokenCommand) error { func DeleteApiKey(cmd *m.DeleteApiKeyCommand) error {
return inTransaction(func(sess *xorm.Session) 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) _, err := sess.Exec(rawSql, cmd.Id, cmd.AccountId)
return err return err
}) })
} }
func AddToken(cmd *m.AddTokenCommand) error { func AddApiKey(cmd *m.AddApiKeyCommand) error {
return inTransaction(func(sess *xorm.Session) error { return inTransaction(func(sess *xorm.Session) error {
t := m.Token{ t := m.ApiKey{
AccountId: cmd.AccountId, AccountId: cmd.AccountId,
Name: cmd.Name, Name: cmd.Name,
Role: cmd.Role, Role: cmd.Role,
Token: cmd.Token, Key: cmd.Key,
Created: time.Now(), Created: time.Now(),
Updated: 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 { return inTransaction(func(sess *xorm.Session) error {
t := m.Token{ t := m.ApiKey{
Id: cmd.Id, Id: cmd.Id,
AccountId: cmd.AccountId, AccountId: cmd.AccountId,
Name: cmd.Name, Name: cmd.Name,
Role: cmd.Role, Role: cmd.Role,
Updated: time.Now(), Updated: time.Now(),
} }
_, err := sess.Where("id=? and account_id=?", t.Id, t.AccountId).Update(&t) _, err := sess.Where("id=? and account_id=?", t.Id, t.AccountId).Update(&t)
return err return err
}) })
} }
func GetTokenByToken(query *m.GetTokenByTokenQuery) error { func GetApiKeyByKey(query *m.GetApiKeyByKeyQuery) error {
var token m.Token var apikey m.ApiKey
has, err := x.Where("token=?", query.Token).Get(&token) has, err := x.Where("key=?", query.Key).Get(&apikey)
if err != nil { if err != nil {
return err return err
} else if has == false { } else if has == false {
return m.ErrInvalidToken return m.ErrInvalidApiKey
} }
query.Result = &token query.Result = &apikey
return nil return nil
} }

View File

@ -2,13 +2,19 @@ package sqlstore
import . "github.com/torkelo/grafana-pro/pkg/services/sqlstore/migrator" 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) { func addMigrations(mg *Migrator) {
addMigrationLogMigrations(mg) addMigrationLogMigrations(mg)
addUserMigrations(mg) addUserMigrations(mg)
addAccountMigrations(mg) addAccountMigrations(mg)
addDashboardMigration(mg) addDashboardMigration(mg)
addDataSourceMigration(mg) addDataSourceMigration(mg)
addTokenMigrations(mg) addApiKeyMigrations(mg)
} }
func addMigrationLogMigrations(mg *Migrator) { func addMigrationLogMigrations(mg *Migrator) {
@ -131,19 +137,22 @@ func addDataSourceMigration(mg *Migrator) {
Table("data_source").Columns("account_id", "name").Unique()) Table("data_source").Columns("account_id", "name").Unique())
} }
func addTokenMigrations(mg *Migrator) { func addApiKeyMigrations(mg *Migrator) {
mg.AddMigration("create token table", new(AddTableMigration). mg.AddMigration("create api_key table", new(AddTableMigration).
Name("token").WithColumns( Name("api_key").WithColumns(
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, &Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
&Column{Name: "account_id", Type: DB_BigInt, Nullable: false}, &Column{Name: "account_id", Type: DB_BigInt, Nullable: false},
&Column{Name: "name", Type: DB_NVarchar, Length: 255, 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: "role", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "created", Type: DB_DateTime, Nullable: false}, &Column{Name: "created", Type: DB_DateTime, Nullable: false},
&Column{Name: "updated", Type: DB_DateTime, Nullable: false}, &Column{Name: "updated", Type: DB_DateTime, Nullable: false},
)) ))
//------- indexes ------------------ //------- indexes ------------------
mg.AddMigration("add index token.account_id", new(AddIndexMigration). mg.AddMigration("add index api_key.account_id", new(AddIndexMigration).
Table("token").Columns("account_id")) Table("api_key").Columns("account_id"))
mg.AddMigration("add index api_key.key", new(AddIndexMigration).
Table("api_key").Columns("key").Unique())
} }