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

NOISSUE - Implement errors package in Authentication service (#1105)

* Implement errors package in Authn service

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* remove imported and not used fmt package

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* wrapped errors when issued new key

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* remove blank line

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* Change error message in tests
Remove nil case in encode error

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* return back nil value error handling

Signed-off-by: Ivan Milošević <iva@blokovi.com>
This commit is contained in:
Ivan Milošević 2020-04-10 17:43:42 +02:00 committed by GitHub
parent 57f7ee2595
commit e438be4250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 96 additions and 51 deletions

View File

@ -58,42 +58,50 @@ func TestIssue(t *testing.T) {
id string id string
kind uint32 kind uint32
err error err error
code codes.Code
}{ }{
{ {
desc: "issue for user with valid token", desc: "issue for user with valid token",
id: email, id: email,
kind: authn.UserKey, kind: authn.UserKey,
err: nil, err: nil,
code: codes.OK,
}, },
{ {
desc: "issue recovery key", desc: "issue recovery key",
id: email, id: email,
kind: authn.RecoveryKey, kind: authn.RecoveryKey,
err: nil, err: nil,
code: codes.OK,
}, },
{ {
desc: "issue API key", desc: "issue API key",
id: userKey.Secret, id: userKey.Secret,
kind: authn.APIKey, kind: authn.APIKey,
err: nil, err: nil,
code: codes.OK,
}, },
{ {
desc: "issue for invalid key type", desc: "issue for invalid key type",
id: email, id: email,
kind: 32, kind: 32,
err: status.Error(codes.InvalidArgument, "received invalid token request"), err: status.Error(codes.InvalidArgument, "received invalid token request"),
code: codes.InvalidArgument,
}, },
{ {
desc: "issue for user that exist", desc: "issue for user that exist",
id: "", id: "",
kind: authn.APIKey, kind: authn.APIKey,
err: status.Error(codes.Unauthenticated, "unauthorized access"), err: status.Error(codes.Unauthenticated, "unauthorized access"),
code: codes.Unauthenticated,
}, },
} }
for _, tc := range cases { for _, tc := range cases {
_, err := client.Issue(context.Background(), &mainflux.IssueReq{Issuer: tc.id, Type: tc.kind}) _, err := client.Issue(context.Background(), &mainflux.IssueReq{Issuer: tc.id, Type: tc.kind})
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err)) e, ok := status.FromError(err)
assert.True(t, ok, "gRPC status can't be extracted from the error")
assert.Equal(t, tc.code, e.Code(), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.code, e.Code()))
} }
} }
@ -116,36 +124,43 @@ func TestIdentify(t *testing.T) {
token string token string
id string id string
err error err error
code codes.Code
}{ }{
{ {
desc: "identify user with recovery token", desc: "identify user with recovery token",
token: recoveryKey.Secret, token: recoveryKey.Secret,
id: email, id: email,
err: nil, err: nil,
code: codes.OK,
}, },
{ {
desc: "identify user with API token", desc: "identify user with API token",
token: apiKey.Secret, token: apiKey.Secret,
id: email, id: email,
err: nil, err: nil,
code: codes.OK,
}, },
{ {
desc: "identify user with invalid user token", desc: "identify user with invalid user token",
token: "invalid", token: "invalid",
id: "", id: "",
err: status.Error(codes.Unauthenticated, "unauthorized access"), err: status.Error(codes.Unauthenticated, "unauthorized access"),
code: codes.Unauthenticated,
}, },
{ {
desc: "identify user that doesn't exist", desc: "identify user that doesn't exist",
token: "", token: "",
id: "", id: "",
err: status.Error(codes.InvalidArgument, "received invalid token request"), err: status.Error(codes.InvalidArgument, "received invalid token request"),
code: codes.InvalidArgument,
}, },
} }
for _, tc := range cases { for _, tc := range cases {
id, err := client.Identify(context.Background(), &mainflux.Token{Value: tc.token}) id, err := client.Identify(context.Background(), &mainflux.Token{Value: tc.token})
assert.Equal(t, tc.id, id.GetValue(), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.id, id.GetValue())) assert.Equal(t, tc.id, id.GetValue(), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.id, id.GetValue()))
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err)) e, ok := status.FromError(err)
assert.True(t, ok, "gRPC status can't be extracted from the error")
assert.Equal(t, tc.code, e.Code(), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.code, e.Code()))
} }
} }

View File

@ -8,6 +8,7 @@ import (
kitgrpc "github.com/go-kit/kit/transport/grpc" kitgrpc "github.com/go-kit/kit/transport/grpc"
mainflux "github.com/mainflux/mainflux" mainflux "github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/errors"
opentracing "github.com/opentracing/opentracing-go" opentracing "github.com/opentracing/opentracing-go"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
@ -74,12 +75,14 @@ func encodeIdentifyResponse(_ context.Context, grpcRes interface{}) (interface{}
} }
func encodeError(err error) error { func encodeError(err error) error {
switch err { switch {
case nil: case errors.Contains(err, nil):
return nil return nil
case authn.ErrMalformedEntity: case errors.Contains(err, authn.ErrMalformedEntity):
return status.Error(codes.InvalidArgument, "received invalid token request") return status.Error(codes.InvalidArgument, "received invalid token request")
case authn.ErrUnauthorizedAccess, authn.ErrKeyExpired: case errors.Contains(err, authn.ErrUnauthorizedAccess):
return status.Error(codes.Unauthenticated, err.Error())
case errors.Contains(err, authn.ErrKeyExpired):
return status.Error(codes.Unauthenticated, err.Error()) return status.Error(codes.Unauthenticated, err.Error())
default: default:
return status.Error(codes.Internal, "internal server error") return status.Error(codes.Internal, "internal server error")

View File

@ -48,3 +48,7 @@ func (res revokeKeyRes) Headers() map[string]string {
func (res revokeKeyRes) Empty() bool { func (res revokeKeyRes) Empty() bool {
return true return true
} }
type errorRes struct {
Err string `json:"error"`
}

View File

@ -6,7 +6,6 @@ package http
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"io" "io"
"net/http" "net/http"
"strings" "strings"
@ -16,6 +15,7 @@ import (
"github.com/go-zoo/bone" "github.com/go-zoo/bone"
"github.com/mainflux/mainflux" "github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/errors"
"github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
) )
@ -67,7 +67,7 @@ func decodeIssue(_ context.Context, r *http.Request) (interface{}, error) {
issuer: r.Header.Get("Authorization"), issuer: r.Header.Get("Authorization"),
} }
if err := json.NewDecoder(r.Body).Decode(&req); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err return nil, errors.Wrap(authn.ErrMalformedEntity, err)
} }
return req, nil return req, nil
@ -100,28 +100,28 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
} }
func encodeError(_ context.Context, err error, w http.ResponseWriter) { func encodeError(_ context.Context, err error, w http.ResponseWriter) {
w.Header().Set("Content-Type", contentType) switch {
case errors.Contains(err, authn.ErrMalformedEntity):
switch err {
case authn.ErrMalformedEntity:
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
case authn.ErrUnauthorizedAccess: case errors.Contains(err, authn.ErrUnauthorizedAccess):
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
case authn.ErrNotFound: case errors.Contains(err, authn.ErrNotFound):
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
case authn.ErrConflict: case errors.Contains(err, authn.ErrConflict):
w.WriteHeader(http.StatusConflict) w.WriteHeader(http.StatusConflict)
case io.EOF, io.ErrUnexpectedEOF: case errors.Contains(err, io.EOF):
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
case errUnsupportedContentType: case errors.Contains(err, io.ErrUnexpectedEOF):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType) w.WriteHeader(http.StatusUnsupportedMediaType)
default: default:
switch err.(type) { w.WriteHeader(http.StatusInternalServerError)
case *json.SyntaxError: }
w.WriteHeader(http.StatusBadRequest) errorVal, ok := err.(errors.Error)
case *json.UnmarshalTypeError: if ok {
w.WriteHeader(http.StatusBadRequest) if err := json.NewEncoder(w).Encode(errorRes{Err: errorVal.Msg()}); err != nil {
default: w.Header().Set("Content-Type", contentType)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
} }
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/authn/jwt" "github.com/mainflux/mainflux/authn/jwt"
"github.com/mainflux/mainflux/errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -48,7 +49,7 @@ func TestIssue(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
_, err := tokenizer.Issue(tc.key) _, err := tokenizer.Issue(tc.key)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err))
} }
} }
@ -104,7 +105,7 @@ func TestParse(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
key, err := tokenizer.Parse(tc.token) key, err := tokenizer.Parse(tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.key, key, fmt.Sprintf("%s expected %v, got %v", tc.desc, tc.key, key)) assert.Equal(t, tc.key, key, fmt.Sprintf("%s expected %v, got %v", tc.desc, tc.key, key))
} }
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/errors"
) )
type claims struct { type claims struct {
@ -68,9 +69,9 @@ func (svc tokenizer) Parse(token string) (authn.Key, error) {
if c.Type != nil && *c.Type == authn.APIKey { if c.Type != nil && *c.Type == authn.APIKey {
return c.toKey(), nil return c.toKey(), nil
} }
return authn.Key{}, authn.ErrKeyExpired return authn.Key{}, errors.Wrap(authn.ErrKeyExpired, err)
} }
return authn.Key{}, authn.ErrUnauthorizedAccess return authn.Key{}, errors.Wrap(authn.ErrUnauthorizedAccess, err)
} }
return c.toKey(), nil return c.toKey(), nil

View File

@ -7,8 +7,14 @@ import (
"github.com/lib/pq" "github.com/lib/pq"
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/errors"
) )
var (
errSave = errors.New("failed to save key in database")
errRetrieve = errors.New("failed to retrieve key from database")
errDelete = errors.New("failed to delete key from database")
)
var _ authn.KeyRepository = (*repo)(nil) var _ authn.KeyRepository = (*repo)(nil)
const ( const (
@ -37,11 +43,11 @@ func (kr repo) Save(ctx context.Context, key authn.Key) (string, error) {
pqErr, ok := err.(*pq.Error) pqErr, ok := err.(*pq.Error)
if ok { if ok {
if pqErr.Code.Name() == errDuplicate { if pqErr.Code.Name() == errDuplicate {
return "", authn.ErrConflict return "", errors.Wrap(authn.ErrConflict, pqErr)
} }
} }
return "", err return "", errors.Wrap(errSave, err)
} }
return dbKey.ID, nil return dbKey.ID, nil
@ -53,10 +59,10 @@ func (kr repo) Retrieve(ctx context.Context, issuer, id string) (authn.Key, erro
if err := kr.db.QueryRowxContext(ctx, q, issuer, id).StructScan(&key); err != nil { if err := kr.db.QueryRowxContext(ctx, q, issuer, id).StructScan(&key); err != nil {
pqErr, ok := err.(*pq.Error) pqErr, ok := err.(*pq.Error)
if err == sql.ErrNoRows || ok && errInvalid == pqErr.Code.Name() { if err == sql.ErrNoRows || ok && errInvalid == pqErr.Code.Name() {
return authn.Key{}, authn.ErrNotFound return authn.Key{}, errors.Wrap(authn.ErrNotFound, err)
} }
return authn.Key{}, err return authn.Key{}, errors.Wrap(errRetrieve, err)
} }
return toKey(key), nil return toKey(key), nil
@ -69,7 +75,7 @@ func (kr repo) Remove(ctx context.Context, issuer, id string) error {
Issuer: issuer, Issuer: issuer,
} }
if _, err := kr.db.NamedExecContext(ctx, q, key); err != nil { if _, err := kr.db.NamedExecContext(ctx, q, key); err != nil {
return err return errors.Wrap(errDelete, err)
} }
return nil return nil

View File

@ -12,6 +12,7 @@ import (
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/authn/postgres" "github.com/mainflux/mainflux/authn/postgres"
"github.com/mainflux/mainflux/authn/uuid" "github.com/mainflux/mainflux/authn/uuid"
"github.com/mainflux/mainflux/errors"
"github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -53,7 +54,7 @@ func TestKeySave(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
_, err := repo.Save(context.Background(), tc.key) _, err := repo.Save(context.Background(), tc.key)
assert.Equal(t, err, tc.err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
} }
} }
@ -101,7 +102,7 @@ func TestKeyRetrieve(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
_, err := repo.Retrieve(context.Background(), tc.issuer, tc.id) _, err := repo.Retrieve(context.Background(), tc.issuer, tc.id)
assert.Equal(t, err, tc.err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
} }
} }
@ -143,6 +144,6 @@ func TestKeyRemove(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
err := repo.Remove(context.Background(), tc.issuer, tc.id) err := repo.Remove(context.Background(), tc.issuer, tc.id)
assert.Equal(t, err, tc.err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
} }
} }

View File

@ -5,8 +5,9 @@ package authn
import ( import (
"context" "context"
"errors"
"time" "time"
"github.com/mainflux/mainflux/errors"
) )
const ( const (
@ -28,6 +29,12 @@ var (
// ErrConflict indicates that entity already exists. // ErrConflict indicates that entity already exists.
ErrConflict = errors.New("entity already exists") ErrConflict = errors.New("entity already exists")
errIssueUser = errors.New("failed to issue new user key")
errIssueTmp = errors.New("failed to issue new temporary key")
errRevoke = errors.New("failed to remove key")
errRetrieve = errors.New("failed to retrieve key data")
errIdentify = errors.New("failed to validate token")
) )
// Service specifies an API that must be fullfiled by the domain service // Service specifies an API that must be fullfiled by the domain service
@ -84,16 +91,18 @@ func (svc service) Issue(ctx context.Context, issuer string, key Key) (Key, erro
func (svc service) Revoke(ctx context.Context, issuer, id string) error { func (svc service) Revoke(ctx context.Context, issuer, id string) error {
email, err := svc.login(issuer) email, err := svc.login(issuer)
if err != nil { if err != nil {
return err return errors.Wrap(errRevoke, err)
} }
if err := svc.keys.Remove(ctx, email, id); err != nil {
return svc.keys.Remove(ctx, email, id) return errors.Wrap(errRevoke, err)
}
return nil
} }
func (svc service) Retrieve(ctx context.Context, issuer, id string) (Key, error) { func (svc service) Retrieve(ctx context.Context, issuer, id string) (Key, error) {
email, err := svc.login(issuer) email, err := svc.login(issuer)
if err != nil { if err != nil {
return Key{}, err return Key{}, errors.Wrap(errRetrieve, err)
} }
return svc.keys.Retrieve(ctx, email, id) return svc.keys.Retrieve(ctx, email, id)
@ -102,7 +111,7 @@ func (svc service) Retrieve(ctx context.Context, issuer, id string) (Key, error)
func (svc service) Identify(ctx context.Context, token string) (string, error) { func (svc service) Identify(ctx context.Context, token string) (string, error) {
c, err := svc.tokenizer.Parse(token) c, err := svc.tokenizer.Parse(token)
if err != nil { if err != nil {
return "", err return "", errors.Wrap(errIdentify, err)
} }
switch c.Type { switch c.Type {
@ -133,7 +142,7 @@ func (svc service) tmpKey(issuer string, duration time.Duration, key Key) (Key,
key.ExpiresAt = key.IssuedAt.Add(duration) key.ExpiresAt = key.IssuedAt.Add(duration)
val, err := svc.tokenizer.Issue(key) val, err := svc.tokenizer.Issue(key)
if err != nil { if err != nil {
return Key{}, err return Key{}, errors.Wrap(errIssueTmp, err)
} }
key.Secret = val key.Secret = val
@ -143,24 +152,24 @@ func (svc service) tmpKey(issuer string, duration time.Duration, key Key) (Key,
func (svc service) userKey(ctx context.Context, issuer string, key Key) (Key, error) { func (svc service) userKey(ctx context.Context, issuer string, key Key) (Key, error) {
email, err := svc.login(issuer) email, err := svc.login(issuer)
if err != nil { if err != nil {
return Key{}, err return Key{}, errors.Wrap(errIssueUser, err)
} }
key.Issuer = email key.Issuer = email
id, err := svc.idp.ID() id, err := svc.idp.ID()
if err != nil { if err != nil {
return Key{}, err return Key{}, errors.Wrap(errIssueUser, err)
} }
key.ID = id key.ID = id
value, err := svc.tokenizer.Issue(key) value, err := svc.tokenizer.Issue(key)
if err != nil { if err != nil {
return Key{}, err return Key{}, errors.Wrap(errIssueUser, err)
} }
key.Secret = value key.Secret = value
if _, err := svc.keys.Save(ctx, key); err != nil { if _, err := svc.keys.Save(ctx, key); err != nil {
return Key{}, err return Key{}, errors.Wrap(errIssueUser, err)
} }
return key, nil return key, nil

View File

@ -12,6 +12,7 @@ import (
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/authn/jwt" "github.com/mainflux/mainflux/authn/jwt"
"github.com/mainflux/mainflux/authn/mocks" "github.com/mainflux/mainflux/authn/mocks"
"github.com/mainflux/mainflux/errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -102,7 +103,7 @@ func TestIssue(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
_, err := svc.Issue(context.Background(), tc.issuer, tc.key) _, err := svc.Issue(context.Background(), tc.issuer, tc.key)
assert.Equal(t, err, tc.err, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err))
} }
} }
func TestRevoke(t *testing.T) { func TestRevoke(t *testing.T) {
@ -144,7 +145,7 @@ func TestRevoke(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
err := svc.Revoke(context.Background(), tc.issuer, tc.id) err := svc.Revoke(context.Background(), tc.issuer, tc.id)
assert.Equal(t, err, tc.err, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err))
} }
} }
func TestRetrieve(t *testing.T) { func TestRetrieve(t *testing.T) {
@ -205,7 +206,7 @@ func TestRetrieve(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
_, err := svc.Retrieve(context.Background(), tc.issuer, tc.id) _, err := svc.Retrieve(context.Background(), tc.issuer, tc.id)
assert.Equal(t, err, tc.err, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err))
} }
} }
func TestIdentify(t *testing.T) { func TestIdentify(t *testing.T) {
@ -272,7 +273,7 @@ func TestIdentify(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
id, err := svc.Identify(context.Background(), tc.key) id, err := svc.Identify(context.Background(), tc.key)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err)) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.id, id, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.id, id)) assert.Equal(t, tc.id, id, fmt.Sprintf("%s expected %s got %s\n", tc.desc, tc.id, id))
} }
} }

View File

@ -7,8 +7,12 @@ package uuid
import ( import (
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
"github.com/mainflux/mainflux/authn" "github.com/mainflux/mainflux/authn"
"github.com/mainflux/mainflux/errors"
) )
// errGeneratingID indicates error in generating UUID
var errGeneratingID = errors.New("failed to generate uuid")
var _ authn.IdentityProvider = (*uuidIdentityProvider)(nil) var _ authn.IdentityProvider = (*uuidIdentityProvider)(nil)
type uuidIdentityProvider struct{} type uuidIdentityProvider struct{}
@ -21,7 +25,7 @@ func New() authn.IdentityProvider {
func (idp *uuidIdentityProvider) ID() (string, error) { func (idp *uuidIdentityProvider) ID() (string, error) {
id, err := uuid.NewV4() id, err := uuid.NewV4()
if err != nil { if err != nil {
return "", err return "", errors.Wrap(errGeneratingID, err)
} }
return id.String(), nil return id.String(), nil