token management is ok with middleware .. OK

This commit is contained in:
Adrien Marquès 2018-07-08 15:29:25 +02:00
parent ba8d73aa8c
commit 0962196e00
7 changed files with 109 additions and 46 deletions

View File

@ -1,7 +1,7 @@
package main package main
import ( import (
"git.xdrm.io/example/aicra/controller/db" "git.xdrm.io/example/aicra/db"
e "git.xdrm.io/go/aicra/err" e "git.xdrm.io/go/aicra/err"
i "git.xdrm.io/go/aicra/implement" i "git.xdrm.io/go/aicra/implement"
) )
@ -26,7 +26,7 @@ func Get(d i.Arguments, r *i.Response) i.Response {
} }
/* (3) Check if match for this key */ /* (3) Check if match for this key */
val := cli.Get(key) val := cli.Get(db.DATA, key)
if val == nil { if val == nil {
r.Err = e.NoMatchFound r.Err = e.NoMatchFound
return *r return *r
@ -57,13 +57,13 @@ func Post(d i.Arguments, r *i.Response) i.Response {
} }
/* (3) Check if key already used */ /* (3) Check if key already used */
if cli.Get(url) != nil { if cli.Get(db.DATA, url) != nil {
r.Err = e.AlreadyExists r.Err = e.AlreadyExists
return *r return *r
} }
/* (4) Store */ /* (4) Store */
if !cli.Set(url, target) { if !cli.Set(db.DATA, url, target) {
r.Err = e.Failure r.Err = e.Failure
return *r return *r
} }
@ -92,13 +92,13 @@ func Put(d i.Arguments, r *i.Response) i.Response {
} }
/* (3) Check if key already used */ /* (3) Check if key already used */
if cli.Get(url) == nil { if cli.Get(db.DATA, url) == nil {
r.Err = e.NoMatchFound r.Err = e.NoMatchFound
return *r return *r
} }
/* (4) Update */ /* (4) Update */
if !cli.Set(url, target) { if !cli.Set(db.DATA, url, target) {
r.Err = e.Failure r.Err = e.Failure
return *r return *r
} }
@ -126,13 +126,13 @@ func Delete(d i.Arguments, r *i.Response) i.Response {
} }
/* (3) Check if key already used */ /* (3) Check if key already used */
if cli.Get(url) == nil { if cli.Get(db.DATA, url) == nil {
r.Err = e.NoMatchFound r.Err = e.NoMatchFound
return *r return *r
} }
/* (4) Delete */ /* (4) Delete */
if !cli.Del(url) { if !cli.Del(db.DATA, url) {
r.Err = e.Failure r.Err = e.Failure
return *r return *r
} }

View File

@ -1,18 +0,0 @@
package main
import (
"fmt"
e "git.xdrm.io/go/aicra/err"
i "git.xdrm.io/go/aicra/implement"
)
// Builds an access token from credentials
func Post(d i.Arguments, r *i.Response) i.Response {
if d.Has("_AUTHORIZATION_") {
fmt.Printf("authorization: '%s'\n", d["_AUTHORIZATION_"].(string))
}
r.Err = e.Success
return *r
}

46
controller/token/main.go Normal file
View File

@ -0,0 +1,46 @@
package main
import (
"crypto/sha512"
"encoding/hex"
"git.xdrm.io/example/aicra/db"
e "git.xdrm.io/go/aicra/err"
i "git.xdrm.io/go/aicra/implement"
"strconv"
"time"
)
// Builds an access token from credentials
func Post(d i.Arguments, r *i.Response) i.Response {
/* (1) Init redis connection */
cli := db.Connect()
if cli == nil {
r.Err = e.Failure
return *r
}
/* (2) Extract api input */
role, ok := d["role"].(string)
if !ok {
r.Err = e.InvalidParam
r.Err.BindArgument("url")
return *r
}
/* (3) Generate token */
hasher := sha512.New()
defer hasher.Reset()
hasher.Write([]byte(strconv.FormatInt(time.Now().Unix(), 5)))
token := hex.EncodeToString(hasher.Sum(nil))
/* (4) Store */
if !cli.Set(db.TOKEN, token, role, time.Minute) {
r.Err = e.Failure
return *r
}
r.Set("token", token)
r.Err = e.Success
return *r
}

View File

@ -3,16 +3,23 @@ package db
import ( import (
"fmt" "fmt"
"github.com/go-redis/redis" "github.com/go-redis/redis"
"time"
) )
const NONCE = "go-tiny-url" const NONCE = "go-tiny-url"
var domain = "data" type Domain string
const (
DATA Domain = "data"
TOKEN Domain = "token"
)
type db redis.Client type db redis.Client
// Returns a connected client to dataset // Returns a connected client to dataset
func Connect() *db { func Connect() *db {
cli := redis.NewClient(&redis.Options{ cli := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", Addr: "127.0.0.1:6379",
Password: "", Password: "",
@ -27,10 +34,10 @@ func Connect() *db {
} }
// returns value from key (nil if nothing) // returns value from key (nil if nothing)
func (c *db) Get(key string) []byte { func (c *db) Get(dom Domain, key string) []byte {
// 1. Try to get // 1. Try to get
if val, err := (*redis.Client)(c).Get(fmt.Sprintf("%s:%s:%s", NONCE, domain, key)).Result(); err != nil { if val, err := (*redis.Client)(c).Get(fmt.Sprintf("%s:%s:%s", NONCE, dom, key)).Result(); err != nil {
// 2. nil if nothing found // 2. nil if nothing found
return nil return nil
} else { } else {
@ -41,10 +48,15 @@ func (c *db) Get(key string) []byte {
} }
// stores a value for a key (success state in return) // stores a value for a key (success state in return)
func (c *db) Set(key string, value string) bool { func (c *db) Set(dom Domain, key string, value string, exp ...time.Duration) bool {
var expiration time.Duration = 0
if len(exp) > 0 {
expiration = exp[0]
}
// 1. Try to set // 1. Try to set
if (*redis.Client)(c).Set(fmt.Sprintf("%s:%s:%s", NONCE, domain, key), value, 0).Err() != nil { if (*redis.Client)(c).Set(fmt.Sprintf("%s:%s:%s", NONCE, dom, key), value, expiration).Err() != nil {
// 2. failure // 2. failure
return false return false
} }
@ -55,10 +67,10 @@ func (c *db) Set(key string, value string) bool {
} }
// deletes the value for a key (success state in return) // deletes the value for a key (success state in return)
func (c *db) Del(key string) bool { func (c *db) Del(dom Domain, key string) bool {
// 1. Try to set // 1. Try to set
if (*redis.Client)(c).Del(fmt.Sprintf("%s:%s:%s", NONCE, domain, key)).Err() != nil { if (*redis.Client)(c).Del(fmt.Sprintf("%s:%s:%s", NONCE, dom, key)).Err() != nil {
// 2. failure // 2. failure
return false return false
} }
@ -67,9 +79,3 @@ func (c *db) Del(key string) bool {
return true return true
} }
// Switch following operations to DATA dataset
func (c *db) SwitchData() { domain = "data" }
// Switch following operations to AUTH dataset
func (c *db) SwitchAuth() { domain = "auth" }

View File

@ -1,4 +1,4 @@
package aicraserver package main
import ( import (
"git.xdrm.io/go/aicra" "git.xdrm.io/go/aicra"

View File

@ -38,16 +38,15 @@
}, },
"/": { "/": {
"auth": { "token": {
"POST": { "POST": {
"info": "returns a 1-minute access token", "info": "creates a 1-minute access token",
"scope": [[]], "scope": [[]],
"in": { "in": {
"username": { "info": "user name", "type": "varchar(3,20)" }, "URL#0": { "info": "wanted role", "type": "varchar(3,10)", "name": "role" }
"password": { "info": "password", "type": "varchar(5,150)" }
}, },
"out": { "out": {
"token": { "info": "access token", "type": "varchar(256,256)" } "token": { "info": "access token", "type": "varchar(128,128)" }
} }
} }
} }

View File

@ -1,11 +1,41 @@
package main package main
import ( import (
"git.xdrm.io/example/aicra/db"
"git.xdrm.io/go/aicra/middleware" "git.xdrm.io/go/aicra/middleware"
"net/http" "net/http"
"strings"
) )
// Authentication middleware // Authentication middleware
func Inspect(req http.Request, scope *middleware.Scope) { func Inspect(req http.Request, scope *middleware.Scope) {
*scope = append(*scope, "admin")
// 1. get authorization header
token := req.Header.Get("Authorization")
// fail if no header
if len(token) < 1 {
return
}
// 2. fail on invalid token format
if len(token) != 128 || strings.ContainsAny(token, "$-_") {
return
}
// 3. get role for this token
cli := db.Connect()
if cli == nil {
return
}
defer cli.Close()
role := cli.Get(db.TOKEN, token)
if role == nil {
return
}
// add role to scope
*scope = append(*scope, string(role))
} }