1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-28 13:48:49 +08:00

114 lines
2.3 KiB
Go
Raw Normal View History

MF-932 - User API keys (#941) * Add inital Auth implementation Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Extract IssuedAt on transport layer Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add token type Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix Auth service URL in Things service Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add User Keys revocation check Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Update tests Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove unused tracing methods Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix Key retrival and parsing Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove unused code Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Increase test coverage Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix compose files Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix typos Simplify tests. Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix typos and remove useless comments Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Rename Auth to Authn Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Rename database.go to tracin.go A new name (`tracing.go`) describes better the purpose of the file. Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Increase test coverage Fix typo. Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Increase test coverage Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove token from Users service Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix identify login keys Rename token parsing method. Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Extract tokenizer to interface Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove pointer time Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Use pointer for expiration time in response Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Use uppercase N Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove unnecessary email check Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Cleanup unused code and env vars Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Rename tokenizer field Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Use slices and named fields in test cases Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Update AuthN keys naming Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove package-lock.json changes Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove Secret from issuing request Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2019-12-16 16:22:09 +01:00
package postgres
import (
"context"
"database/sql"
"time"
"github.com/lib/pq"
"github.com/mainflux/mainflux/authn"
)
var _ authn.KeyRepository = (*repo)(nil)
const (
errDuplicate = "unique_violation"
errInvalid = "invalid_text_representation"
)
type repo struct {
db Database
}
// New instantiates a PostgreSQL implementation of key repository.
func New(db Database) authn.KeyRepository {
return &repo{
db: db,
}
}
func (kr repo) Save(ctx context.Context, key authn.Key) (string, error) {
q := `INSERT INTO keys (id, type, issuer, issued_at, expires_at)
VALUES (:id, :type, :issuer, :issued_at, :expires_at)`
dbKey := toDBKey(key)
if _, err := kr.db.NamedExecContext(ctx, q, dbKey); err != nil {
pqErr, ok := err.(*pq.Error)
if ok {
if pqErr.Code.Name() == errDuplicate {
return "", authn.ErrConflict
}
}
return "", err
}
return dbKey.ID, nil
}
func (kr repo) Retrieve(ctx context.Context, issuer, id string) (authn.Key, error) {
q := `SELECT id, type, issuer, issued_at, expires_at FROM keys WHERE issuer = $1 AND id = $2`
key := dbKey{}
if err := kr.db.QueryRowxContext(ctx, q, issuer, id).StructScan(&key); err != nil {
pqErr, ok := err.(*pq.Error)
if err == sql.ErrNoRows || ok && errInvalid == pqErr.Code.Name() {
return authn.Key{}, authn.ErrNotFound
}
return authn.Key{}, err
}
return toKey(key), nil
}
func (kr repo) Remove(ctx context.Context, issuer, id string) error {
q := `DELETE FROM keys WHERE issuer = :issuer AND id = :id`
key := dbKey{
ID: id,
Issuer: issuer,
}
if _, err := kr.db.NamedExecContext(ctx, q, key); err != nil {
return err
}
return nil
}
type dbKey struct {
ID string `db:"id"`
Type uint32 `db:"type"`
Issuer string `db:"issuer"`
Revoked bool `db:"revoked"`
IssuedAt time.Time `db:"issued_at"`
ExpiresAt sql.NullTime `db:"expires_at"`
}
func toDBKey(key authn.Key) dbKey {
ret := dbKey{
ID: key.ID,
Type: key.Type,
Issuer: key.Issuer,
IssuedAt: key.IssuedAt,
}
if !key.ExpiresAt.IsZero() {
ret.ExpiresAt = sql.NullTime{Time: key.ExpiresAt, Valid: true}
}
return ret
}
func toKey(key dbKey) authn.Key {
ret := authn.Key{
ID: key.ID,
Type: key.Type,
Issuer: key.Issuer,
IssuedAt: key.IssuedAt,
}
if key.ExpiresAt.Valid {
ret.ExpiresAt = key.ExpiresAt.Time
}
return ret
}