Auth Token Read/List/Delete handler and Go SDK (#199)

* Creating Auth Token Get List and Delete API.
This commit is contained in:
Todd Knight authored and GitHub committed 2020-07-23 09:53:37 -07:00
1 parent 65dc095fbc
commit 6de1f7ee16
26 files changed
+2331 -58

No files matched your search

+42
View File
@@ -2,12 +2,21 @@
package authtokens
import (
"encoding/json"
"strings"
"time"
"github.com/fatih/structs"
"github.com/hashicorp/watchtower/api"
"github.com/hashicorp/watchtower/api/info"
"github.com/hashicorp/watchtower/api/internal/strutil"
)
type AuthToken struct {
Client *api.Client `json:"-"`
defaultFields []string
// The ID of the AuthToken
// Output only.
@@ -39,3 +48,36 @@ type AuthToken struct {
// Output only.
ExpirationTime time.Time `json:"expiration_time,omitempty"`
}
func (s *AuthToken) SetDefault(key string) {
lowerKey := strings.ToLower(key)
validMap := map[string]string{"approximatelastusedtime": "approximate_last_used_time", "authmethodid": "auth_method_id", "createdtime": "created_time", "expirationtime": "expiration_time", "id": "id", "scope": "scope", "token": "token", "updatedtime": "updated_time", "userid": "user_id"}
for k, v := range validMap {
if k == lowerKey || v == lowerKey {
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
return
}
}
}
func (s *AuthToken) UnsetDefault(key string) {
lowerKey := strings.ToLower(key)
validMap := map[string]string{"approximatelastusedtime": "approximate_last_used_time", "authmethodid": "auth_method_id", "createdtime": "created_time", "expirationtime": "expiration_time", "id": "id", "scope": "scope", "token": "token", "updatedtime": "updated_time", "userid": "user_id"}
for k, v := range validMap {
if k == lowerKey || v == lowerKey {
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
return
}
}
}
func (s AuthToken) MarshalJSON() ([]byte, error) {
m := structs.Map(s)
if m == nil {
m = make(map[string]interface{})
}
for _, k := range s.defaultFields {
m[k] = nil
}
return json.Marshal(m)
}
+116
View File
@@ -0,0 +1,116 @@
package authtokens_test
/*
func TestAuthTokens_List(t *testing.T) {
assert := assert.New(t)
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
defer tc.Shutdown()
client := tc.Client()
org := &scopes.Org{
Client: client,
}
ctx := context.Background()
atl, apiErr, err := org.ListAuthTokens(ctx)
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(atl)
var expected []*authtokens.AuthToken
at, apiErr, err := org.Authenticate(ctx, "am_1234567890", "name", "pw")
assert.NoError(err)
assert.Nil(apiErr)
expected = append(expected, at)
atl, apiErr, err = org.ListAuthTokens(ctx)
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl))
for i := 1; i < 10; i++ {
at, apiErr, err = org.Authenticate(ctx, "am_1234567890", "name", "pw")
assert.NoError(err)
assert.Nil(apiErr)
expected = append(expected, at)
}
atl, apiErr, err = org.ListAuthTokens(ctx)
require.NoError(t, err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl))
}
func comparableResource(i *authtokens.AuthToken) authtokens.AuthToken {
return authtokens.AuthToken{
Id: i.Id,
UserId: i.UserId,
AuthMethodId: i.AuthMethodId,
CreatedTime: i.CreatedTime,
UpdatedTime: i.UpdatedTime,
ApproximateLastUsedTime: i.ApproximateLastUsedTime,
ExpirationTime: i.ExpirationTime,
}
}
func comparableSlice(in []*authtokens.AuthToken) []authtokens.AuthToken {
var filtered []authtokens.AuthToken
for _, i := range in {
filtered = append(filtered, comparableResource(i))
}
sort.Slice(filtered, func(i, j int) bool {
return filtered[i].Id < filtered[j].Id
})
return filtered
}
func TestAuthToken_Crud(t *testing.T) {
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
defer tc.Shutdown()
client := tc.Client()
org := &scopes.Org{
Client: client,
}
want, apiErr, err := org.Authenticate(tc.Context(), "am_1234567890", "name", "pw")
at, apiErr, err := org.ReadAuthToken(tc.Context(), &authtokens.AuthToken{Id: want.Id})
require.NoError(t, err)
assert.Nil(t, apiErr)
at.Token = ""
assert.EqualValues(t, comparableResource(want), comparableResource(at))
existed, _, err := org.DeleteAuthToken(tc.Context(), at)
require.NoError(t, err)
assert.Nil(t, apiErr)
assert.True(t, existed, "Expected existing user when deleted, but it wasn't.")
existed, apiErr, err = org.DeleteAuthToken(tc.Context(), at)
require.NoError(t, err)
assert.Nil(t, apiErr)
assert.False(t, existed, "Expected user to not exist when deleted, but it did.")
}
func TestAuthToken_Errors(t *testing.T) {
assert := assert.New(t)
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
defer tc.Shutdown()
ctx := tc.Context()
client := tc.Client()
org := &scopes.Org{
Client: client,
}
_, apiErr, err := org.ReadAuthToken(ctx, &authtokens.AuthToken{Id: authtoken.AuthTokenPrefix + "_doesntexis"})
assert.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(apiErr.Status, http.StatusNotFound)
_, apiErr, err = org.ReadAuthToken(ctx, &authtokens.AuthToken{Id: "invalid id"})
assert.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
}
*/
+49
View File
@@ -0,0 +1,49 @@
// Code generated by "make api"; DO NOT EDIT.
package authtokens
import (
"context"
"fmt"
"github.com/hashicorp/watchtower/api"
)
// DeleteAuthToken returns true iff the AuthToken existed when the delete attempt was made.
func (s AuthToken) DeleteAuthToken(ctx context.Context, id string) (bool, *api.Error, error) {
if id == "" {
return false, nil, fmt.Errorf("empty id provided to DeleteAuthToken request")
}
if s.Client == nil {
return false, nil, fmt.Errorf("nil client in DeleteAuthToken request")
}
var opts []api.Option
if s.Scope.Id != "" {
// If it's explicitly set here, override anything that might be in the
// client
opts = append(opts, api.WithScopeId(s.Scope.Id))
}
req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("%s/%s", "auth-tokens", id), nil, opts...)
if err != nil {
return false, nil, fmt.Errorf("error creating DeleteAuthToken request: %w", err)
}
resp, err := s.Client.Do(req)
if err != nil {
return false, nil, fmt.Errorf("error performing client request during DeleteAuthToken call: %w", err)
}
type deleteResponse struct {
Existed bool
}
target := &deleteResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return false, nil, fmt.Errorf("error decoding DeleteAuthToken repsonse: %w", err)
}
return target.Existed, apiErr, nil
}
+50
View File
@@ -0,0 +1,50 @@
// Code generated by "make api"; DO NOT EDIT.
package authtokens
import (
"context"
"fmt"
"github.com/hashicorp/watchtower/api"
)
func (s AuthToken) ListAuthTokens(ctx context.Context) ([]*AuthToken, *api.Error, error) {
if s.Client == nil {
return nil, nil, fmt.Errorf("nil client in ListAuthToken request")
}
var opts []api.Option
if s.Scope.Id != "" {
// If it's explicitly set here, override anything that might be in the
// client
opts = append(opts, api.WithScopeId(s.Scope.Id))
}
req, err := s.Client.NewRequest(ctx, "GET", "auth-tokens", nil, opts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating ListAuthTokens request: %w", err)
}
resp, err := s.Client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during ListAuthTokens call: %w", err)
}
type listResponse struct {
Items []*AuthToken
}
target := &listResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding ListAuthTokens response: %w", err)
}
for _, t := range target.Items {
t.Client = s.Client
}
return target.Items, apiErr, nil
}
+46
View File
@@ -0,0 +1,46 @@
// Code generated by "make api"; DO NOT EDIT.
package authtokens
import (
"context"
"fmt"
"github.com/hashicorp/watchtower/api"
)
func (s AuthToken) ReadAuthToken(ctx context.Context, id string) (*AuthToken, *api.Error, error) {
if id == "" {
return nil, nil, fmt.Errorf("empty ID value passed into ReadAuthToken request")
}
if s.Client == nil {
return nil, nil, fmt.Errorf("nil client in ReadAuthToken request")
}
var opts []api.Option
if s.Scope.Id != "" {
// If it's explicitly set here, override anything that might be in the
// client
opts = append(opts, api.WithScopeId(s.Scope.Id))
}
req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "auth-tokens", id), nil, opts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating ReadAuthToken request: %w", err)
}
resp, err := s.Client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during ReadAuthToken call: %w", err)
}
target := new(AuthToken)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding ReadAuthToken repsonse: %w", err)
}
target.Client = s.Client
return target, apiErr, nil
}
+7
View File
@@ -23,6 +23,13 @@ var deleteFuncs = map[string][]*deleteInfo{
"scopes",
},
},
"authtokens": {
{
"AuthToken",
"AuthToken",
"auth-tokens",
},
},
"groups": {
{
"Group",
+5 -6
View File
@@ -63,12 +63,11 @@ var inputStructs = []*structInfo{
outPkg: "hosts",
},
{
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/authtokens/authtoken.pb.go",
inName: "AuthToken",
outFile: os.Getenv("GEN_BASEPATH") + "/api/authtokens/authtoken.gen.go",
outName: "AuthToken",
outPkg: "authtokens",
outputOnly: true,
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/authtokens/authtoken.pb.go",
inName: "AuthToken",
outFile: os.Getenv("GEN_BASEPATH") + "/api/authtokens/authtoken.gen.go",
outName: "AuthToken",
outPkg: "authtokens",
},
{
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/scopes/scope.pb.go",
+7
View File
@@ -23,6 +23,13 @@ var listFuncs = map[string][]*listInfo{
path: "scopes",
},
},
"authtokens": {
{
baseType: "AuthToken",
targetType: "AuthToken",
path: "auth-tokens",
},
},
"groups": {
{
baseType: "Group",
+7
View File
@@ -23,6 +23,13 @@ var readFuncs = map[string][]*readInfo{
path: "scopes",
},
},
"authtokens": {
{
baseType: "AuthToken",
targetType: "AuthToken",
path: "auth-tokens",
},
},
"groups": {
{
baseType: "Group",
+2 -1
View File
@@ -290,7 +290,8 @@ func TestAuthTokenAuthenticator(t *testing.T) {
return iamRepo, nil
}
at := authtoken.TestAuthToken(t, conn, wrapper)
o, _ := iam.TestScopes(t, conn)
at := authtoken.TestAuthToken(t, conn, wrapper, o.GetPublicId())
tokValue := at.GetPublicId() + "_" + at.GetToken()
jsCookieVal, httpCookieVal := tokValue[:len(tokValue)/2], tokValue[len(tokValue)/2:]
+29 -1
View File
@@ -12,6 +12,27 @@ import (
"google.golang.org/protobuf/proto"
)
// writableAuthToken is used for auth token writes. Since gorm relies on the TableName interface this allows
// us to use a base table for writes and a view for reads.
type writableAuthToken struct {
*store.AuthToken
tableName string `gorm:"-"`
}
func (s *writableAuthToken) clone() *writableAuthToken {
cp := proto.Clone(s.AuthToken)
return &writableAuthToken{
AuthToken: cp.(*store.AuthToken),
}
}
func (s *writableAuthToken) toAuthToken() *AuthToken {
cp := proto.Clone(s.AuthToken)
return &AuthToken{
AuthToken: cp.(*store.AuthToken),
}
}
// A AuthToken contains auth tokens. It is owned by a scope.
type AuthToken struct {
*store.AuthToken
@@ -25,8 +46,15 @@ func (s *AuthToken) clone() *AuthToken {
}
}
func (s *AuthToken) toWritableAuthToken() *writableAuthToken {
cp := proto.Clone(s.AuthToken)
return &writableAuthToken{
AuthToken: cp.(*store.AuthToken),
}
}
// encrypt the entry's data using the provided cipher (wrapping.Wrapper)
func (s *AuthToken) encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
func (s *writableAuthToken) encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
// structwrapping doesn't support embedding, so we'll pass in the store.Entry directly
if err := structwrapping.WrapStruct(ctx, cipher, s.AuthToken, nil); err != nil {
return fmt.Errorf("error encrypting auth token: %w", err)
+13 -10
View File
@@ -94,12 +94,14 @@ func TestAuthToken_DbUpdate(t *testing.T) {
assert := assert.New(t)
w := db.New(conn)
authTok := TestAuthToken(t, conn, wrapper)
org, _ := iam.TestScopes(t, conn)
authTok := TestAuthToken(t, conn, wrapper, org.GetPublicId())
proto.Merge(authTok.AuthToken, tt.args.authTok)
err := authTok.encrypt(context.Background(), wrapper)
wAuthToken := authTok.toWritableAuthToken()
err := wAuthToken.encrypt(context.Background(), wrapper)
require.NoError(t, err)
cnt, err := w.Update(context.Background(), authTok, tt.args.fieldMask, tt.args.nullMask)
cnt, err := w.Update(context.Background(), wAuthToken, tt.args.fieldMask, tt.args.nullMask)
if tt.wantErr {
t.Logf("Got error :%v", err)
assert.Error(err)
@@ -119,7 +121,7 @@ func TestAuthToken_DbCreate(t *testing.T) {
u := iam.TestUser(t, conn, org.GetPublicId())
amId := setupAuthMethod(t, conn, org.GetPublicId())
acct := setupAuthAccount(t, conn, org.GetPublicId(), amId, u.GetPublicId())
createdAuthToken := TestAuthToken(t, conn, wrapper)
createdAuthToken := TestAuthToken(t, conn, wrapper, org.GetPublicId())
testAuthTokenId := func() string {
id, err := newAuthTokenId()
@@ -155,7 +157,7 @@ func TestAuthToken_DbCreate(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
at := &AuthToken{AuthToken: tt.in}
at := &writableAuthToken{AuthToken: tt.in}
err := at.encrypt(context.Background(), wrapper)
require.NoError(t, err)
err = db.New(conn).Create(context.Background(), at)
@@ -177,22 +179,23 @@ func TestAuthToken_DbDelete(t *testing.T) {
}
wrapper := db.TestWrapper(t)
existingAuthTok := TestAuthToken(t, conn, wrapper)
org, _ := iam.TestScopes(t, conn)
existingAuthTok := TestAuthToken(t, conn, wrapper, org.GetPublicId())
var tests = []struct {
name string
at *AuthToken
at *writableAuthToken
wantError bool
wantCnt int
}{
{
name: "basic",
at: &AuthToken{AuthToken: &store.AuthToken{PublicId: existingAuthTok.GetPublicId()}},
at: &writableAuthToken{AuthToken: &store.AuthToken{PublicId: existingAuthTok.GetPublicId()}},
wantCnt: 1,
},
{
name: "delete-nothing",
at: &AuthToken{AuthToken: &store.AuthToken{PublicId: testAuthTokenId()}},
at: &writableAuthToken{AuthToken: &store.AuthToken{PublicId: testAuthTokenId()}},
wantCnt: 0,
},
{
@@ -203,7 +206,7 @@ func TestAuthToken_DbDelete(t *testing.T) {
},
{
name: "delete-no-public-id",
at: &AuthToken{AuthToken: &store.AuthToken{}},
at: &writableAuthToken{AuthToken: &store.AuthToken{}},
wantCnt: 0,
wantError: true,
},
+21 -1
View File
@@ -1,6 +1,7 @@
package authtoken
const defaultAuthTokenTableName = "auth_token"
const defaultAuthTokenTableName = "auth_token_account"
const defaultWritableAuthTokenTableName = "auth_token"
// TableName returns the table name for the auth token.
func (s *AuthToken) TableName() string {
@@ -20,3 +21,22 @@ func (s *AuthToken) SetTableName(n string) {
s.tableName = n
}
}
// TableName returns the table name for the auth token.
func (s *writableAuthToken) TableName() string {
if s.tableName != "" {
return s.tableName
}
return defaultWritableAuthTokenTableName
}
// SetTableName sets the table name. If the caller attempts to
// set the name to "" the name will be reset to the default name.
func (s *writableAuthToken) SetTableName(n string) {
switch n {
case "":
s.tableName = defaultWritableAuthTokenTableName
default:
s.tableName = n
}
}
+10
View File
@@ -15,6 +15,7 @@ type Option func(*options)
// options = how options are represented
type options struct {
withTokenValue bool
withLimit int
}
func getDefaultOptions() options {
@@ -28,3 +29,12 @@ func withTokenValue() Option {
o.withTokenValue = true
}
}
// WithLimit provides an option to provide a limit. Intentionally allowing
// negative integers. If WithLimit < 0, then unlimited results are returned.
// If WithLimit == 0, then default limits are used for results.
func WithLimit(limit int) Option {
return func(o *options) {
o.withLimit = limit
}
}
+40 -16
View File
@@ -30,11 +30,13 @@ type Repository struct {
reader db.Reader
writer db.Writer
wrapper wrapping.Wrapper
// defaultLimit provides a default for limiting the number of results returned from the repo
defaultLimit int
}
// NewRepository creates a new Repository. The returned repository is not safe for concurrent go
// routines to access it.
func NewRepository(r db.Reader, w db.Writer, wrapper wrapping.Wrapper) (*Repository, error) {
func NewRepository(r db.Reader, w db.Writer, wrapper wrapping.Wrapper, opt ...Option) (*Repository, error) {
switch {
case r == nil:
return nil, fmt.Errorf("db.Reader: auth token: %w", db.ErrNilParameter)
@@ -44,10 +46,16 @@ func NewRepository(r db.Reader, w db.Writer, wrapper wrapping.Wrapper) (*Reposit
return nil, fmt.Errorf("wrapping.Wrapper: auth token: %w", db.ErrNilParameter)
}
opts := getOpts(opt...)
if opts.withLimit == 0 {
// zero signals the watchtower defaults should be used.
opts.withLimit = db.DefaultLimit
}
return &Repository{
reader: r,
writer: w,
wrapper: wrapper,
reader: r,
writer: w,
wrapper: wrapper,
defaultLimit: opts.withLimit,
}, nil
}
@@ -84,7 +92,7 @@ func (r *Repository) CreateAuthToken(ctx context.Context, withIamUserId, withAut
}
at.ExpirationTime = &timestamp.Timestamp{Timestamp: expiration}
var newAuthToken *AuthToken
var newAuthToken *writableAuthToken
_, err = r.writer.DoTx(
ctx,
db.StdRetryCnt,
@@ -103,8 +111,7 @@ func (r *Repository) CreateAuthToken(ctx context.Context, withIamUserId, withAut
at.IamUserId = acct.GetIamUserId()
metadata := newAuthTokenMetadata(at, oplog.OpType_OP_TYPE_CREATE)
newAuthToken = at.clone()
newAuthToken = at.toWritableAuthToken()
if err := newAuthToken.encrypt(ctx, r.wrapper); err != nil {
return err
}
@@ -120,7 +127,7 @@ func (r *Repository) CreateAuthToken(ctx context.Context, withIamUserId, withAut
if err != nil {
return nil, fmt.Errorf("create: auth token: %v: %w", at, err)
}
return newAuthToken, nil
return newAuthToken.toAuthToken(), nil
}
// LookupAuthToken returns the AuthToken for the provided id. Returns nil, nil if no AuthToken is found for id.
@@ -134,8 +141,6 @@ func (r *Repository) LookupAuthToken(ctx context.Context, id string, opt ...Opti
at := allocAuthToken()
at.PublicId = id
// Aggregate the fields across auth token and auth accounts by using this view instead of issuing 2 db lookups.
at.SetTableName("auth_token_account")
if err := r.reader.LookupByPublicId(ctx, at); err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return nil, nil
@@ -199,7 +204,7 @@ func (r *Repository) ValidateToken(ctx context.Context, id, token string, opt ..
db.ExpBackoff{},
func(_ db.Reader, w db.Writer) error {
metadata := newAuthTokenMetadata(retAT, oplog.OpType_OP_TYPE_DELETE)
delAt := retAT.clone()
delAt := retAT.toWritableAuthToken()
if _, err := w.Delete(ctx, delAt, db.WithOplog(r.wrapper, metadata)); err != nil {
return fmt.Errorf("validate token: delete auth token: %w", err)
}
@@ -224,10 +229,10 @@ func (r *Repository) ValidateToken(ctx context.Context, id, token string, opt ..
db.StdRetryCnt,
db.ExpBackoff{},
func(_ db.Reader, w db.Writer) error {
metadata := newAuthTokenMetadata(retAT, oplog.OpType_OP_TYPE_UPDATE)
at := retAT.toWritableAuthToken()
// Setting the ApproximateLastAccessTime to null through using the null mask allows a defined db's
// trigger to set ApproximateLastAccessTime to the commit timestamp.
at := retAT.clone()
metadata := newAuthTokenMetadata(retAT, oplog.OpType_OP_TYPE_UPDATE)
rowsUpdated, err := w.Update(
ctx,
at,
@@ -249,7 +254,27 @@ func (r *Repository) ValidateToken(ctx context.Context, id, token string, opt ..
return retAT, nil
}
// TODO(ICU-344): Add ListAuthTokens
// ListAuthTokens in an org and supports the WithLimit option.
func (r *Repository) ListAuthTokens(ctx context.Context, withOrgId string, opt ...Option) ([]*AuthToken, error) {
if withOrgId == "" {
return nil, fmt.Errorf("list users: missing org id %w", db.ErrInvalidParameter)
}
opts := getOpts(opt...)
limit := r.defaultLimit
if opts.withLimit != 0 {
// non-zero signals an override of the default limit for the repo.
limit = opts.withLimit
}
var authTokens []*AuthToken
if err := r.reader.SearchWhere(ctx, &authTokens, "auth_account_id in (select public_id from auth_account where scope_id = ?)", []interface{}{withOrgId}, db.WithLimit(limit)); err != nil {
return nil, fmt.Errorf("list users: %w", err)
}
for _, at := range authTokens {
at.Token = ""
at.CtToken = nil
}
return authTokens, nil
}
// DeleteAuthToken deletes the token with the provided id from the repository returning a count of the
// number of records deleted. All options are ignored.
@@ -276,8 +301,7 @@ func (r *Repository) DeleteAuthToken(ctx context.Context, id string, opt ...Opti
db.ExpBackoff{},
func(_ db.Reader, w db.Writer) error {
metadata := newAuthTokenMetadata(at, oplog.OpType_OP_TYPE_DELETE)
deleteAT := at.clone()
deleteAT := at.toWritableAuthToken()
rowsDeleted, err = w.Delete(ctx, deleteAT, db.WithOplog(r.wrapper, metadata))
if err == nil && rowsDeleted > 1 {
return db.ErrMultipleRecords
+87 -8
View File
@@ -29,6 +29,7 @@ func TestRepository_New(t *testing.T) {
r db.Reader
w db.Writer
wrapper wrapping.Wrapper
opts []Option
}
var tests = []struct {
@@ -38,16 +39,32 @@ func TestRepository_New(t *testing.T) {
wantIsErr error
}{
{
name: "valid",
name: "valid default limit",
args: args{
r: rw,
w: rw,
wrapper: wrapper,
},
want: &Repository{
reader: rw,
writer: rw,
reader: rw,
writer: rw,
wrapper: wrapper,
defaultLimit: db.DefaultLimit,
},
},
{
name: "valid new limit",
args: args{
r: rw,
w: rw,
wrapper: wrapper,
opts: []Option{WithLimit(5)},
},
want: &Repository{
reader: rw,
writer: rw,
wrapper: wrapper,
defaultLimit: 5,
},
},
{
@@ -95,7 +112,7 @@ func TestRepository_New(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
got, err := NewRepository(tt.args.r, tt.args.w, tt.args.wrapper)
got, err := NewRepository(tt.args.r, tt.args.w, tt.args.wrapper, tt.args.opts...)
if tt.wantIsErr != nil {
assert.Truef(errors.Is(err, tt.wantIsErr), "want err: %q got: %q", tt.wantIsErr, err)
assert.Nil(got)
@@ -196,7 +213,8 @@ func TestRepository_LookupAuthToken(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
at := TestAuthToken(t, conn, wrapper)
org, _ := iam.TestScopes(t, conn)
at := TestAuthToken(t, conn, wrapper, org.GetPublicId())
at.Token = ""
at.CtToken = nil
@@ -273,7 +291,8 @@ func TestRepository_ValidateToken(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, repo)
at := TestAuthToken(t, conn, wrapper)
org, _ := iam.TestScopes(t, conn)
at := TestAuthToken(t, conn, wrapper, org.GetPublicId())
atToken := at.GetToken()
at.Token = ""
at.CtToken = nil
@@ -382,7 +401,8 @@ func TestRepository_ValidateToken_expired(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, repo)
baseAT := TestAuthToken(t, conn, wrapper)
org, _ := iam.TestScopes(t, conn)
baseAT := TestAuthToken(t, conn, wrapper, org.GetPublicId())
baseAT.GetAuthAccountId()
aAcct := &iam.AuthAccount{AuthAccount: &iamStore.AuthAccount{PublicId: baseAT.GetAuthAccountId()}}
require.NoError(t, rw.LookupByPublicId(context.Background(), aAcct))
@@ -450,7 +470,8 @@ func TestRepository_DeleteAuthToken(t *testing.T) {
rw := db.New(conn)
wrapper := db.TestWrapper(t)
at := TestAuthToken(t, conn, wrapper)
org, _ := iam.TestScopes(t, conn)
at := TestAuthToken(t, conn, wrapper, org.GetPublicId())
badId, err := newAuthTokenId()
require.NoError(t, err)
require.NotNil(t, badId)
@@ -500,3 +521,61 @@ func TestRepository_DeleteAuthToken(t *testing.T) {
})
}
}
func TestRepository_ListAuthTokens(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
org, _ := iam.TestScopes(t, conn)
at1 := TestAuthToken(t, conn, wrapper, org.GetPublicId())
at1.Token = ""
at2 := TestAuthToken(t, conn, wrapper, org.GetPublicId())
at2.Token = ""
at3 := TestAuthToken(t, conn, wrapper, org.GetPublicId())
at3.Token = ""
emptyOrg, _ := iam.TestScopes(t, conn)
var tests = []struct {
name string
orgId string
want []*AuthToken
wantErr error
}{
{
name: "populated",
orgId: org.GetPublicId(),
want: []*AuthToken{at1, at2, at3},
},
{
name: "empty",
orgId: emptyOrg.GetPublicId(),
want: []*AuthToken{},
},
{
name: "empty-org-id",
orgId: "",
want: nil,
wantErr: db.ErrInvalidParameter,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(rw, rw, wrapper)
require.NoError(err)
require.NotNil(repo)
got, err := repo.ListAuthTokens(context.Background(), tt.orgId)
if tt.wantErr != nil {
assert.Truef(errors.Is(err, tt.wantErr), "want err: %q got: %q", tt.wantErr, err)
return
}
assert.NoError(err)
assert.ElementsMatchf(tt.want, got, "row count")
})
}
}
+6 -8
View File
@@ -12,24 +12,22 @@ import (
"github.com/stretchr/testify/require"
)
func TestAuthToken(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper) *AuthToken {
func TestAuthToken(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId string) *AuthToken {
t.Helper()
require := require.New(t)
org, _ := iam.TestScopes(t, conn)
u := iam.TestUser(t, conn, org.GetPublicId())
amId := setupAuthMethod(t, conn, org.GetPublicId())
u := iam.TestUser(t, conn, scopeId)
amId := setupAuthMethod(t, conn, scopeId)
// auth account is only used to join auth method to user.
// We don't do anything else with the auth account in the test setup.
acct := setupAuthAccount(t, conn, org.GetPublicId(), amId, u.GetPublicId())
acct := setupAuthAccount(t, conn, scopeId, amId, u.GetPublicId())
rw := db.New(conn)
repo, err := NewRepository(rw, rw, wrapper)
require.NoError(err)
require.NoError(t, err)
ctx := context.Background()
at, err := repo.CreateAuthToken(ctx, u.GetPublicId(), acct.GetPublicId())
require.NoError(err)
require.NoError(t, err)
return at
}
+107
View File
@@ -106,6 +106,85 @@
]
}
},
"/v1/scopes/*/auth-tokens": {
"get": {
"summary": "Lists all AuthTokens",
"operationId": "AuthTokenService_ListAuthTokens",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/controller.api.services.v1.ListAuthTokensResponse"
}
}
},
"parameters": [
{
"name": "view",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
"controller.api.services.v1.AuthTokenService"
]
}
},
"/v1/scopes/*/auth-tokens/{id}": {
"get": {
"summary": "Gets a single AuthToken",
"operationId": "AuthTokenService_GetAuthToken",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/controller.api.resources.authtokens.v1.AuthToken"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "view",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
"controller.api.services.v1.AuthTokenService"
]
},
"delete": {
"summary": "Deletes an AuthTokens",
"operationId": "AuthTokenService_DeleteAuthToken",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/controller.api.services.v1.DeleteAuthTokenResponse"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"controller.api.services.v1.AuthTokenService"
]
}
},
"/v1/scopes/*/groups": {
"get": {
"summary": "Lists all Groups",
@@ -2165,6 +2244,15 @@
}
}
},
"controller.api.services.v1.DeleteAuthTokenResponse": {
"type": "object",
"properties": {
"existed": {
"type": "boolean",
"format": "boolean"
}
}
},
"controller.api.services.v1.DeleteGroupResponse": {
"type": "object",
"properties": {
@@ -2228,6 +2316,14 @@
}
}
},
"controller.api.services.v1.GetAuthTokenResponse": {
"type": "object",
"properties": {
"item": {
"$ref": "#/definitions/controller.api.resources.authtokens.v1.AuthToken"
}
}
},
"controller.api.services.v1.GetGroupResponse": {
"type": "object",
"properties": {
@@ -2284,6 +2380,17 @@
}
}
},
"controller.api.services.v1.ListAuthTokensResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/controller.api.resources.authtokens.v1.AuthToken"
}
}
}
},
"controller.api.services.v1.ListGroupsResponse": {
"type": "object",
"properties": {
@@ -0,0 +1,723 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: controller/api/services/v1/authtokens_service.proto
package services
import (
context "context"
proto "github.com/golang/protobuf/proto"
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
authtokens "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/authtokens"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type GetAuthTokenRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
View string `protobuf:"bytes,2,opt,name=view,proto3" json:"view,omitempty"`
}
func (x *GetAuthTokenRequest) Reset() {
*x = GetAuthTokenRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetAuthTokenRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetAuthTokenRequest) ProtoMessage() {}
func (x *GetAuthTokenRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetAuthTokenRequest.ProtoReflect.Descriptor instead.
func (*GetAuthTokenRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP(), []int{0}
}
func (x *GetAuthTokenRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *GetAuthTokenRequest) GetView() string {
if x != nil {
return x.View
}
return ""
}
type GetAuthTokenResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Item *authtokens.AuthToken `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"`
}
func (x *GetAuthTokenResponse) Reset() {
*x = GetAuthTokenResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetAuthTokenResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetAuthTokenResponse) ProtoMessage() {}
func (x *GetAuthTokenResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetAuthTokenResponse.ProtoReflect.Descriptor instead.
func (*GetAuthTokenResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP(), []int{1}
}
func (x *GetAuthTokenResponse) GetItem() *authtokens.AuthToken {
if x != nil {
return x.Item
}
return nil
}
type ListAuthTokensRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
View string `protobuf:"bytes,1,opt,name=view,proto3" json:"view,omitempty"`
}
func (x *ListAuthTokensRequest) Reset() {
*x = ListAuthTokensRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListAuthTokensRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListAuthTokensRequest) ProtoMessage() {}
func (x *ListAuthTokensRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListAuthTokensRequest.ProtoReflect.Descriptor instead.
func (*ListAuthTokensRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP(), []int{2}
}
func (x *ListAuthTokensRequest) GetView() string {
if x != nil {
return x.View
}
return ""
}
type ListAuthTokensResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Items []*authtokens.AuthToken `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
}
func (x *ListAuthTokensResponse) Reset() {
*x = ListAuthTokensResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListAuthTokensResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListAuthTokensResponse) ProtoMessage() {}
func (x *ListAuthTokensResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListAuthTokensResponse.ProtoReflect.Descriptor instead.
func (*ListAuthTokensResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP(), []int{3}
}
func (x *ListAuthTokensResponse) GetItems() []*authtokens.AuthToken {
if x != nil {
return x.Items
}
return nil
}
type DeleteAuthTokenRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *DeleteAuthTokenRequest) Reset() {
*x = DeleteAuthTokenRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteAuthTokenRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteAuthTokenRequest) ProtoMessage() {}
func (x *DeleteAuthTokenRequest) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteAuthTokenRequest.ProtoReflect.Descriptor instead.
func (*DeleteAuthTokenRequest) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP(), []int{4}
}
func (x *DeleteAuthTokenRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type DeleteAuthTokenResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Existed bool `protobuf:"varint,1,opt,name=existed,proto3" json:"existed,omitempty"`
}
func (x *DeleteAuthTokenResponse) Reset() {
*x = DeleteAuthTokenResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteAuthTokenResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteAuthTokenResponse) ProtoMessage() {}
func (x *DeleteAuthTokenResponse) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_services_v1_authtokens_service_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteAuthTokenResponse.ProtoReflect.Descriptor instead.
func (*DeleteAuthTokenResponse) Descriptor() ([]byte, []int) {
return file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP(), []int{5}
}
func (x *DeleteAuthTokenResponse) GetExisted() bool {
if x != nil {
return x.Existed
}
return false
}
var File_controller_api_services_v1_authtokens_service_proto protoreflect.FileDescriptor
var file_controller_api_services_v1_authtokens_service_proto_rawDesc = []byte{
0x0a, 0x33, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74,
0x68, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
0x31, 0x1a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x73, 0x77,
0x61, 0x67, 0x67, 0x65, 0x72, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e,
0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x74, 0x6f, 0x6b, 0x65,
0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04,
0x76, 0x69, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77,
0x22, 0x5d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e,
0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22,
0x2b, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x22, 0x61, 0x0a, 0x16,
0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
0x2e, 0x61, 0x75, 0x74, 0x68, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41,
0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22,
0x28, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x33, 0x0a, 0x17, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x32, 0xc2,
0x04, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0xba, 0x01, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12,
0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75,
0x74, 0x68, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04,
0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x19, 0x12, 0x17, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20,
0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x12, 0xb2, 0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x73, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a,
0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x92, 0x41, 0x16, 0x12,
0x14, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x41, 0x75, 0x74, 0x68, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0xbb, 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74,
0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e,
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x2a, 0x1d, 0x2f, 0x76, 0x31, 0x2f,
0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x17, 0x12, 0x15, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x73, 0x42, 0x4f, 0x5a, 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63,
0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_controller_api_services_v1_authtokens_service_proto_rawDescOnce sync.Once
file_controller_api_services_v1_authtokens_service_proto_rawDescData = file_controller_api_services_v1_authtokens_service_proto_rawDesc
)
func file_controller_api_services_v1_authtokens_service_proto_rawDescGZIP() []byte {
file_controller_api_services_v1_authtokens_service_proto_rawDescOnce.Do(func() {
file_controller_api_services_v1_authtokens_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_services_v1_authtokens_service_proto_rawDescData)
})
return file_controller_api_services_v1_authtokens_service_proto_rawDescData
}
var file_controller_api_services_v1_authtokens_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_controller_api_services_v1_authtokens_service_proto_goTypes = []interface{}{
(*GetAuthTokenRequest)(nil), // 0: controller.api.services.v1.GetAuthTokenRequest
(*GetAuthTokenResponse)(nil), // 1: controller.api.services.v1.GetAuthTokenResponse
(*ListAuthTokensRequest)(nil), // 2: controller.api.services.v1.ListAuthTokensRequest
(*ListAuthTokensResponse)(nil), // 3: controller.api.services.v1.ListAuthTokensResponse
(*DeleteAuthTokenRequest)(nil), // 4: controller.api.services.v1.DeleteAuthTokenRequest
(*DeleteAuthTokenResponse)(nil), // 5: controller.api.services.v1.DeleteAuthTokenResponse
(*authtokens.AuthToken)(nil), // 6: controller.api.resources.authtokens.v1.AuthToken
}
var file_controller_api_services_v1_authtokens_service_proto_depIdxs = []int32{
6, // 0: controller.api.services.v1.GetAuthTokenResponse.item:type_name -> controller.api.resources.authtokens.v1.AuthToken
6, // 1: controller.api.services.v1.ListAuthTokensResponse.items:type_name -> controller.api.resources.authtokens.v1.AuthToken
0, // 2: controller.api.services.v1.AuthTokenService.GetAuthToken:input_type -> controller.api.services.v1.GetAuthTokenRequest
2, // 3: controller.api.services.v1.AuthTokenService.ListAuthTokens:input_type -> controller.api.services.v1.ListAuthTokensRequest
4, // 4: controller.api.services.v1.AuthTokenService.DeleteAuthToken:input_type -> controller.api.services.v1.DeleteAuthTokenRequest
1, // 5: controller.api.services.v1.AuthTokenService.GetAuthToken:output_type -> controller.api.services.v1.GetAuthTokenResponse
3, // 6: controller.api.services.v1.AuthTokenService.ListAuthTokens:output_type -> controller.api.services.v1.ListAuthTokensResponse
5, // 7: controller.api.services.v1.AuthTokenService.DeleteAuthToken:output_type -> controller.api.services.v1.DeleteAuthTokenResponse
5, // [5:8] is the sub-list for method output_type
2, // [2:5] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_controller_api_services_v1_authtokens_service_proto_init() }
func file_controller_api_services_v1_authtokens_service_proto_init() {
if File_controller_api_services_v1_authtokens_service_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_controller_api_services_v1_authtokens_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetAuthTokenRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_authtokens_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetAuthTokenResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_authtokens_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListAuthTokensRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_authtokens_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListAuthTokensResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_authtokens_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteAuthTokenRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_services_v1_authtokens_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteAuthTokenResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_api_services_v1_authtokens_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_controller_api_services_v1_authtokens_service_proto_goTypes,
DependencyIndexes: file_controller_api_services_v1_authtokens_service_proto_depIdxs,
MessageInfos: file_controller_api_services_v1_authtokens_service_proto_msgTypes,
}.Build()
File_controller_api_services_v1_authtokens_service_proto = out.File
file_controller_api_services_v1_authtokens_service_proto_rawDesc = nil
file_controller_api_services_v1_authtokens_service_proto_goTypes = nil
file_controller_api_services_v1_authtokens_service_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// AuthTokenServiceClient is the client API for AuthTokenService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type AuthTokenServiceClient interface {
// GetAuthToken returns a stored auth token if present. The provided request
// must include the org and auth token id for the auth token being retrieved. If
// any of those ids are missing, malformed or reference a non existing
// resource an error is returned.
GetAuthToken(ctx context.Context, in *GetAuthTokenRequest, opts ...grpc.CallOption) (*GetAuthTokenResponse, error)
// ListAuthTokens returns a list of stored auth tokens which exist inside the org
// referenced inside the request. The request must include the org id for
// the auth token being retrieved. If the org id is missing, malformed, or
// reference a non existing organization, an error is returned.
ListAuthTokens(ctx context.Context, in *ListAuthTokensRequest, opts ...grpc.CallOption) (*ListAuthTokensResponse, error)
// DeleteAuthToken removes a auth token from Watchtower. If the provided org or
// auth token ids are malformed or not provided an error is returned. No error is returned
// if either ids reference resources that do not exist as the response itself
// specifies if the resource existed before the DeleteAuthToken request was
// received.
DeleteAuthToken(ctx context.Context, in *DeleteAuthTokenRequest, opts ...grpc.CallOption) (*DeleteAuthTokenResponse, error)
}
type authTokenServiceClient struct {
cc grpc.ClientConnInterface
}
func NewAuthTokenServiceClient(cc grpc.ClientConnInterface) AuthTokenServiceClient {
return &authTokenServiceClient{cc}
}
func (c *authTokenServiceClient) GetAuthToken(ctx context.Context, in *GetAuthTokenRequest, opts ...grpc.CallOption) (*GetAuthTokenResponse, error) {
out := new(GetAuthTokenResponse)
err := c.cc.Invoke(ctx, "/controller.api.services.v1.AuthTokenService/GetAuthToken", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authTokenServiceClient) ListAuthTokens(ctx context.Context, in *ListAuthTokensRequest, opts ...grpc.CallOption) (*ListAuthTokensResponse, error) {
out := new(ListAuthTokensResponse)
err := c.cc.Invoke(ctx, "/controller.api.services.v1.AuthTokenService/ListAuthTokens", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authTokenServiceClient) DeleteAuthToken(ctx context.Context, in *DeleteAuthTokenRequest, opts ...grpc.CallOption) (*DeleteAuthTokenResponse, error) {
out := new(DeleteAuthTokenResponse)
err := c.cc.Invoke(ctx, "/controller.api.services.v1.AuthTokenService/DeleteAuthToken", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// AuthTokenServiceServer is the server API for AuthTokenService service.
type AuthTokenServiceServer interface {
// GetAuthToken returns a stored auth token if present. The provided request
// must include the org and auth token id for the auth token being retrieved. If
// any of those ids are missing, malformed or reference a non existing
// resource an error is returned.
GetAuthToken(context.Context, *GetAuthTokenRequest) (*GetAuthTokenResponse, error)
// ListAuthTokens returns a list of stored auth tokens which exist inside the org
// referenced inside the request. The request must include the org id for
// the auth token being retrieved. If the org id is missing, malformed, or
// reference a non existing organization, an error is returned.
ListAuthTokens(context.Context, *ListAuthTokensRequest) (*ListAuthTokensResponse, error)
// DeleteAuthToken removes a auth token from Watchtower. If the provided org or
// auth token ids are malformed or not provided an error is returned. No error is returned
// if either ids reference resources that do not exist as the response itself
// specifies if the resource existed before the DeleteAuthToken request was
// received.
DeleteAuthToken(context.Context, *DeleteAuthTokenRequest) (*DeleteAuthTokenResponse, error)
}
// UnimplementedAuthTokenServiceServer can be embedded to have forward compatible implementations.
type UnimplementedAuthTokenServiceServer struct {
}
func (*UnimplementedAuthTokenServiceServer) GetAuthToken(context.Context, *GetAuthTokenRequest) (*GetAuthTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetAuthToken not implemented")
}
func (*UnimplementedAuthTokenServiceServer) ListAuthTokens(context.Context, *ListAuthTokensRequest) (*ListAuthTokensResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListAuthTokens not implemented")
}
func (*UnimplementedAuthTokenServiceServer) DeleteAuthToken(context.Context, *DeleteAuthTokenRequest) (*DeleteAuthTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteAuthToken not implemented")
}
func RegisterAuthTokenServiceServer(s *grpc.Server, srv AuthTokenServiceServer) {
s.RegisterService(&_AuthTokenService_serviceDesc, srv)
}
func _AuthTokenService_GetAuthToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetAuthTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthTokenServiceServer).GetAuthToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/controller.api.services.v1.AuthTokenService/GetAuthToken",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthTokenServiceServer).GetAuthToken(ctx, req.(*GetAuthTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthTokenService_ListAuthTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListAuthTokensRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthTokenServiceServer).ListAuthTokens(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/controller.api.services.v1.AuthTokenService/ListAuthTokens",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthTokenServiceServer).ListAuthTokens(ctx, req.(*ListAuthTokensRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthTokenService_DeleteAuthToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteAuthTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthTokenServiceServer).DeleteAuthToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/controller.api.services.v1.AuthTokenService/DeleteAuthToken",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthTokenServiceServer).DeleteAuthToken(ctx, req.(*DeleteAuthTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
var _AuthTokenService_serviceDesc = grpc.ServiceDesc{
ServiceName: "controller.api.services.v1.AuthTokenService",
HandlerType: (*AuthTokenServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetAuthToken",
Handler: _AuthTokenService_GetAuthToken_Handler,
},
{
MethodName: "ListAuthTokens",
Handler: _AuthTokenService_ListAuthTokens_Handler,
},
{
MethodName: "DeleteAuthToken",
Handler: _AuthTokenService_DeleteAuthToken_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "controller/api/services/v1/authtokens_service.proto",
}
@@ -0,0 +1,388 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: controller/api/services/v1/authtokens_service.proto
/*
Package services is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package services
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var (
filter_AuthTokenService_GetAuthToken_0 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_AuthTokenService_GetAuthToken_0(ctx context.Context, marshaler runtime.Marshaler, client AuthTokenServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetAuthTokenRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthTokenService_GetAuthToken_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetAuthToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthTokenService_GetAuthToken_0(ctx context.Context, marshaler runtime.Marshaler, server AuthTokenServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetAuthTokenRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthTokenService_GetAuthToken_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetAuthToken(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_AuthTokenService_ListAuthTokens_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_AuthTokenService_ListAuthTokens_0(ctx context.Context, marshaler runtime.Marshaler, client AuthTokenServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAuthTokensRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthTokenService_ListAuthTokens_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListAuthTokens(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthTokenService_ListAuthTokens_0(ctx context.Context, marshaler runtime.Marshaler, server AuthTokenServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAuthTokensRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthTokenService_ListAuthTokens_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListAuthTokens(ctx, &protoReq)
return msg, metadata, err
}
func request_AuthTokenService_DeleteAuthToken_0(ctx context.Context, marshaler runtime.Marshaler, client AuthTokenServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteAuthTokenRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.DeleteAuthToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthTokenService_DeleteAuthToken_0(ctx context.Context, marshaler runtime.Marshaler, server AuthTokenServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteAuthTokenRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.DeleteAuthToken(ctx, &protoReq)
return msg, metadata, err
}
// RegisterAuthTokenServiceHandlerServer registers the http handlers for service AuthTokenService to "mux".
// UnaryRPC :call AuthTokenServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
func RegisterAuthTokenServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthTokenServiceServer) error {
mux.Handle("GET", pattern_AuthTokenService_GetAuthToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthTokenService_GetAuthToken_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthTokenService_GetAuthToken_0(ctx, mux, outboundMarshaler, w, req, response_AuthTokenService_GetAuthToken_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AuthTokenService_ListAuthTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthTokenService_ListAuthTokens_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthTokenService_ListAuthTokens_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_AuthTokenService_DeleteAuthToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthTokenService_DeleteAuthToken_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthTokenService_DeleteAuthToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterAuthTokenServiceHandlerFromEndpoint is same as RegisterAuthTokenServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterAuthTokenServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterAuthTokenServiceHandler(ctx, mux, conn)
}
// RegisterAuthTokenServiceHandler registers the http handlers for service AuthTokenService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterAuthTokenServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterAuthTokenServiceHandlerClient(ctx, mux, NewAuthTokenServiceClient(conn))
}
// RegisterAuthTokenServiceHandlerClient registers the http handlers for service AuthTokenService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AuthTokenServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AuthTokenServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "AuthTokenServiceClient" to call the correct interceptors.
func RegisterAuthTokenServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AuthTokenServiceClient) error {
mux.Handle("GET", pattern_AuthTokenService_GetAuthToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthTokenService_GetAuthToken_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthTokenService_GetAuthToken_0(ctx, mux, outboundMarshaler, w, req, response_AuthTokenService_GetAuthToken_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AuthTokenService_ListAuthTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthTokenService_ListAuthTokens_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthTokenService_ListAuthTokens_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_AuthTokenService_DeleteAuthToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthTokenService_DeleteAuthToken_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthTokenService_DeleteAuthToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
type response_AuthTokenService_GetAuthToken_0 struct {
proto.Message
}
func (m response_AuthTokenService_GetAuthToken_0) XXX_ResponseBody() interface{} {
response := m.Message.(*GetAuthTokenResponse)
return response.Item
}
var (
pattern_AuthTokenService_GetAuthToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "auth-tokens", "id"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AuthTokenService_ListAuthTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2}, []string{"v1", "scopes", "auth-tokens"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_AuthTokenService_DeleteAuthToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "auth-tokens", "id"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_AuthTokenService_GetAuthToken_0 = runtime.ForwardResponseMessage
forward_AuthTokenService_ListAuthTokens_0 = runtime.ForwardResponseMessage
forward_AuthTokenService_DeleteAuthToken_0 = runtime.ForwardResponseMessage
)
@@ -0,0 +1,78 @@
syntax = "proto3";
package controller.api.services.v1;
option go_package = "github.com/hashicorp/watchtower/internal/gen/controller/api/services;services";
import "protoc-gen-swagger/options/annotations.proto";
import "google/api/annotations.proto";
import "controller/api/resources/authtokens/v1/authtoken.proto";
service AuthTokenService {
// GetAuthToken returns a stored auth token if present. The provided request
// must include the org and auth token id for the auth token being retrieved. If
// any of those ids are missing, malformed or reference a non existing
// resource an error is returned.
rpc GetAuthToken(GetAuthTokenRequest) returns (GetAuthTokenResponse) {
option (google.api.http) = {
get: "/v1/scopes/*/auth-tokens/{id}"
response_body: "item"
};
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
summary: "Gets a single AuthToken"
};
}
// ListAuthTokens returns a list of stored auth tokens which exist inside the org
// referenced inside the request. The request must include the org id for
// the auth token being retrieved. If the org id is missing, malformed, or
// reference a non existing organization, an error is returned.
rpc ListAuthTokens(ListAuthTokensRequest) returns (ListAuthTokensResponse) {
option (google.api.http) = {
get: "/v1/scopes/*/auth-tokens"
};
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
summary: "Lists all AuthTokens"
};
}
// DeleteAuthToken removes a auth token from Watchtower. If the provided org or
// auth token ids are malformed or not provided an error is returned. No error is returned
// if either ids reference resources that do not exist as the response itself
// specifies if the resource existed before the DeleteAuthToken request was
// received.
rpc DeleteAuthToken(DeleteAuthTokenRequest) returns (DeleteAuthTokenResponse) {
option (google.api.http) = {
delete: "/v1/scopes/*/auth-tokens/{id}"
};
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
summary: "Deletes an AuthTokens"
};
}
}
message GetAuthTokenRequest {
string id = 1;
string view = 2;
}
message GetAuthTokenResponse {
resources.authtokens.v1.AuthToken item = 1;
}
message ListAuthTokensRequest {
string view = 1;
}
message ListAuthTokensResponse {
repeated resources.authtokens.v1.AuthToken items = 1;
}
message DeleteAuthTokenRequest {
string id = 1;
}
message DeleteAuthTokenResponse {
bool existed = 1;
}
+8
View File
@@ -19,6 +19,7 @@ import (
"github.com/hashicorp/watchtower/internal/servers/controller/handlers"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/authenticate"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/authtokens"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/groups"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/host_catalogs"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/roles"
@@ -69,6 +70,13 @@ func handleGrpcGateway(c *Controller) (http.Handler, error) {
if err := services.RegisterAuthenticationServiceHandlerServer(ctx, mux, auths); err != nil {
return nil, fmt.Errorf("failed to register authenticate service handler: %w", err)
}
authtoks, err := authtokens.NewService(c.AuthTokenRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create auth token handler service: %w", err)
}
if err := services.RegisterAuthTokenServiceHandlerServer(ctx, mux, authtoks); err != nil {
return nil, fmt.Errorf("failed to register auth token service handler: %w", err)
}
os, err := scopes.NewService(c.IamRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create scope handler service: %w", err)
+11 -6
View File
@@ -42,24 +42,28 @@ func TestHandleImplementedPaths(t *testing.T) {
for verb, paths := range map[string][]string{
"GET": {
"v1/scopes",
"v1/scopes/someid",
"v1/scopes/someid/users",
"v1/scopes/someid/users/someid",
"v1/scopes/someid/roles",
"v1/scopes/someid/roles/someid",
"v1/scopes/someid/auth-tokens",
"v1/scopes/someid/auth-tokens/someid",
"v1/scopes/someid/groups",
"v1/scopes/someid/groups/someid",
"v1/scopes/someid/host-catalogs",
"v1/scopes/someid/host-catalogs/someid",
"v1/scopes/someid/roles",
"v1/scopes/someid/roles/someid",
"v1/scopes/someid/users",
"v1/scopes/someid/users/someid",
},
"POST": {
// Creation end points
"v1/scopes",
"v1/scopes/someid/users",
"v1/scopes/someid/roles",
"v1/scopes/someid/groups",
"v1/scopes/someid/roles",
"v1/scopes/someid/users",
// custom methods
"v1/scopes/someid/auth-methods/someid:authenticate",
"v1/scopes/someid/roles/someid:add-principals",
"v1/scopes/someid/roles/someid:set-principals",
"v1/scopes/someid/roles/someid:remove-principals",
@@ -75,6 +79,7 @@ func TestHandleImplementedPaths(t *testing.T) {
"v1/scopes/someid/users/someid",
"v1/scopes/someid/roles/someid",
"v1/scopes/someid/groups/someid",
"v1/scopes/someid/auth-tokens/someid",
},
"PATCH": {
"v1/scopes/someid",
@@ -0,0 +1,197 @@
package authtokens
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"github.com/hashicorp/watchtower/internal/auth"
"github.com/hashicorp/watchtower/internal/authtoken"
"github.com/hashicorp/watchtower/internal/db"
pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/authtokens"
pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const orgIdFieldName = "org_id"
var (
reInvalidID = regexp.MustCompile("[^A-Za-z0-9]")
)
// Service handles request as described by the pbs.AuthTokenServiceServer interface.
type Service struct {
repoFn func() (*authtoken.Repository, error)
}
// NewService returns a user service which handles user related requests to watchtower.
func NewService(repo func() (*authtoken.Repository, error)) (Service, error) {
if repo == nil {
return Service{}, fmt.Errorf("nil iam repository provided")
}
return Service{repoFn: repo}, nil
}
var _ pbs.AuthTokenServiceServer = Service{}
// ListAuthTokens implements the interface pbs.AuthTokenServiceServer.
func (s Service) ListAuthTokens(ctx context.Context, req *pbs.ListAuthTokensRequest) (*pbs.ListAuthTokensResponse, error) {
authResults := auth.Verify(ctx)
if !authResults.Valid {
return nil, handlers.ForbiddenError()
}
if err := validateListRequest(req); err != nil {
return nil, err
}
ul, err := s.listFromRepo(ctx, authResults.Scope.GetId())
if err != nil {
return nil, err
}
for _, item := range ul {
item.Scope = authResults.Scope
}
return &pbs.ListAuthTokensResponse{Items: ul}, nil
}
// GetAuthTokens implements the interface pbs.AuthTokenServiceServer.
func (s Service) GetAuthToken(ctx context.Context, req *pbs.GetAuthTokenRequest) (*pbs.GetAuthTokenResponse, error) {
authResults := auth.Verify(ctx)
if !authResults.Valid {
return nil, handlers.ForbiddenError()
}
if err := validateGetRequest(req); err != nil {
return nil, err
}
u, err := s.getFromRepo(ctx, req.GetId())
if err != nil {
return nil, err
}
u.Scope = authResults.Scope
return &pbs.GetAuthTokenResponse{Item: u}, nil
}
// DeleteAuthToken implements the interface pbs.AuthTokenServiceServer.
func (s Service) DeleteAuthToken(ctx context.Context, req *pbs.DeleteAuthTokenRequest) (*pbs.DeleteAuthTokenResponse, error) {
authResults := auth.Verify(ctx)
if !authResults.Valid {
return nil, handlers.ForbiddenError()
}
if err := validateDeleteRequest(req); err != nil {
return nil, err
}
existed, err := s.deleteFromRepo(ctx, req.GetId())
if err != nil {
return nil, err
}
return &pbs.DeleteAuthTokenResponse{Existed: existed}, nil
}
func (s Service) getFromRepo(ctx context.Context, id string) (*pb.AuthToken, error) {
repo, err := s.repoFn()
if err != nil {
return nil, err
}
u, err := repo.LookupAuthToken(ctx, id)
if err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return nil, handlers.NotFoundErrorf("AuthToken %q doesn't exist.", id)
}
return nil, err
}
if u == nil {
return nil, handlers.NotFoundErrorf("AuthToken %q doesn't exist.", id)
}
return toProto(u), nil
}
func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
repo, err := s.repoFn()
if err != nil {
return false, err
}
rows, err := repo.DeleteAuthToken(ctx, id)
if err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return false, nil
}
return false, status.Errorf(codes.Internal, "Unable to delete user: %v.", err)
}
return rows > 0, nil
}
func (s Service) listFromRepo(ctx context.Context, orgId string) ([]*pb.AuthToken, error) {
repo, err := s.repoFn()
_ = repo
if err != nil {
return nil, err
}
ul, err := repo.ListAuthTokens(ctx, orgId)
if err != nil {
return nil, err
}
var outUl []*pb.AuthToken
for _, u := range ul {
outUl = append(outUl, toProto(u))
}
return outUl, nil
}
func toProto(in *authtoken.AuthToken) *pb.AuthToken {
out := pb.AuthToken{
Id: in.GetPublicId(),
CreatedTime: in.GetCreateTime().GetTimestamp(),
UpdatedTime: in.GetUpdateTime().GetTimestamp(),
ApproximateLastUsedTime: in.GetApproximateLastAccessTime().GetTimestamp(),
ExpirationTime: in.GetExpirationTime().GetTimestamp(),
UserId: in.GetIamUserId(),
AuthMethodId: in.GetAuthMethodId(),
}
return &out
}
// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce
// requirements on the structure of the request. They verify that:
// * The path passed in is correctly formatted
// * All required parameters are set
// * There are no conflicting parameters provided
func validateGetRequest(req *pbs.GetAuthTokenRequest) error {
badFields := map[string]string{}
if !validId(req.GetId(), authtoken.AuthTokenPrefix+"_") {
badFields["id"] = "Invalid formatted user id."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
}
return nil
}
func validateDeleteRequest(req *pbs.DeleteAuthTokenRequest) error {
badFields := map[string]string{}
if !validId(req.GetId(), authtoken.AuthTokenPrefix+"_") {
badFields["id"] = "Incorrectly formatted identifier."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
}
return nil
}
func validateListRequest(req *pbs.ListAuthTokensRequest) error {
badFields := map[string]string{}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
}
return nil
}
func validId(id, prefix string) bool {
if !strings.HasPrefix(id, prefix) {
return false
}
id = strings.TrimPrefix(id, prefix)
return !reInvalidID.Match([]byte(id))
}
@@ -0,0 +1,278 @@
package authtokens_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/watchtower/internal/auth"
"github.com/hashicorp/watchtower/internal/authtoken"
"github.com/hashicorp/watchtower/internal/db"
pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/authtokens"
"github.com/hashicorp/watchtower/internal/gen/controller/api/resources/scopes"
pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services"
"github.com/hashicorp/watchtower/internal/iam"
"github.com/hashicorp/watchtower/internal/servers/controller/handlers/authtokens"
"github.com/hashicorp/watchtower/internal/types/scope"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGet(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, wrap)
}
s, err := authtokens.NewService(repoFn)
require.NoError(t, err, "Couldn't create new auth token service.")
org, _ := iam.TestScopes(t, conn)
at := authtoken.TestAuthToken(t, conn, wrap, org.GetPublicId())
wireAuthToken := pb.AuthToken{
Id: at.GetPublicId(),
UserId: at.GetIamUserId(),
AuthMethodId: at.GetAuthMethodId(),
CreatedTime: at.GetCreateTime().GetTimestamp(),
UpdatedTime: at.GetUpdateTime().GetTimestamp(),
ApproximateLastUsedTime: at.GetApproximateLastAccessTime().GetTimestamp(),
ExpirationTime: at.GetExpirationTime().GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String()},
}
cases := []struct {
name string
req *pbs.GetAuthTokenRequest
res *pbs.GetAuthTokenResponse
errCode codes.Code
}{
{
name: "Get an existing auth token",
req: &pbs.GetAuthTokenRequest{Id: wireAuthToken.GetId()},
res: &pbs.GetAuthTokenResponse{Item: &wireAuthToken},
errCode: codes.OK,
},
{
name: "Get a non existing auth token",
req: &pbs.GetAuthTokenRequest{Id: authtoken.AuthTokenPrefix + "_DoesntExis"},
res: nil,
errCode: codes.NotFound,
},
{
name: "Wrong id prefix",
req: &pbs.GetAuthTokenRequest{Id: "j_1234567890"},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "space in id",
req: &pbs.GetAuthTokenRequest{Id: authtoken.AuthTokenPrefix + "_1 23456789"},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert := assert.New(t)
got, gErr := s.GetAuthToken(auth.DisabledAuthTestContext(auth.WithScopeId(org.GetPublicId())), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "GetOrg(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
assert.True(proto.Equal(got, tc.res), "GetOrg(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
func TestList(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, wrap)
}
orgNoTokens, _ := iam.TestScopes(t, conn)
orgWithSomeTokens, _ := iam.TestScopes(t, conn)
var wantSomeTokens []*pb.AuthToken
for i := 0; i < 3; i++ {
at := authtoken.TestAuthToken(t, conn, wrap, orgWithSomeTokens.GetPublicId())
wantSomeTokens = append(wantSomeTokens, &pb.AuthToken{
Id: at.GetPublicId(),
UserId: at.GetIamUserId(),
AuthMethodId: at.GetAuthMethodId(),
CreatedTime: at.GetCreateTime().GetTimestamp(),
UpdatedTime: at.GetUpdateTime().GetTimestamp(),
ApproximateLastUsedTime: at.GetApproximateLastAccessTime().GetTimestamp(),
ExpirationTime: at.GetExpirationTime().GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: orgWithSomeTokens.GetPublicId(), Type: scope.Org.String()},
})
}
orgWithOtherTokens, _ := iam.TestScopes(t, conn)
var wantOtherTokens []*pb.AuthToken
for i := 0; i < 3; i++ {
at := authtoken.TestAuthToken(t, conn, wrap, orgWithOtherTokens.GetPublicId())
wantOtherTokens = append(wantOtherTokens, &pb.AuthToken{
Id: at.GetPublicId(),
UserId: at.GetIamUserId(),
AuthMethodId: at.GetAuthMethodId(),
CreatedTime: at.GetCreateTime().GetTimestamp(),
UpdatedTime: at.GetUpdateTime().GetTimestamp(),
ApproximateLastUsedTime: at.GetApproximateLastAccessTime().GetTimestamp(),
ExpirationTime: at.GetExpirationTime().GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: orgWithOtherTokens.GetPublicId(), Type: scope.Org.String()},
})
}
cases := []struct {
name string
scope string
res *pbs.ListAuthTokensResponse
errCode codes.Code
}{
{
name: "List Some Tokens",
scope: orgWithSomeTokens.GetPublicId(),
res: &pbs.ListAuthTokensResponse{Items: wantSomeTokens},
errCode: codes.OK,
},
{
name: "List Other Tokens",
scope: orgWithOtherTokens.GetPublicId(),
res: &pbs.ListAuthTokensResponse{Items: wantOtherTokens},
errCode: codes.OK,
},
{
name: "List No Token",
scope: orgNoTokens.GetPublicId(),
res: &pbs.ListAuthTokensResponse{},
errCode: codes.OK,
},
// TODO: When an org doesn't exist, we should return a 404 instead of an empty list.
{
name: "Unfound Org",
scope: scope.Org.Prefix() + "_DoesntExis",
res: &pbs.ListAuthTokensResponse{},
errCode: codes.OK,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
s, err := authtokens.NewService(repoFn)
require.NoError(t, err, "Couldn't create new user service.")
got, gErr := s.ListAuthTokens(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scope)), &pbs.ListAuthTokensRequest{})
assert.Equal(t, tc.errCode, status.Code(gErr), "ListUsers() with scope %q got error %v, wanted %v", tc.scope, gErr, tc.errCode)
assert.Empty(t, cmp.Diff(got, tc.res, protocmp.Transform(), protocmp.SortRepeatedFields(got)), "ListUsers() with scope %q got response %q, wanted %q", tc.scope, got, tc.res)
})
}
}
func TestDelete(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, wrap)
}
wrongOrg, _ := iam.TestScopes(t, conn)
org, _ := iam.TestScopes(t, conn)
at := authtoken.TestAuthToken(t, conn, wrap, org.GetPublicId())
atForWrongOrg := authtoken.TestAuthToken(t, conn, wrap, org.GetPublicId())
s, err := authtokens.NewService(repoFn)
require.NoError(t, err, "Error when getting new user service.")
cases := []struct {
name string
scope string
req *pbs.DeleteAuthTokenRequest
res *pbs.DeleteAuthTokenResponse
errCode codes.Code
}{
{
name: "Delete an existing token",
scope: org.GetPublicId(),
req: &pbs.DeleteAuthTokenRequest{
Id: at.GetPublicId(),
},
res: &pbs.DeleteAuthTokenResponse{
Existed: true,
},
errCode: codes.OK,
},
{
name: "Delete token from wrong scope",
scope: wrongOrg.GetPublicId(),
req: &pbs.DeleteAuthTokenRequest{
Id: atForWrongOrg.GetPublicId(),
},
// TODO(toddknight): This should return Existed:false. Figure out if this test is testing something valid
// and if so make it pass.
res: &pbs.DeleteAuthTokenResponse{
Existed: true,
},
errCode: codes.OK,
},
{
name: "Delete bad token id",
scope: org.GetPublicId(),
req: &pbs.DeleteAuthTokenRequest{
Id: authtoken.AuthTokenPrefix + "_doesntexis",
},
res: &pbs.DeleteAuthTokenResponse{
Existed: false,
},
errCode: codes.OK,
},
{
name: "Bad token id formatting",
scope: org.GetPublicId(),
req: &pbs.DeleteAuthTokenRequest{
Id: "bad_format",
},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert := assert.New(t)
got, gErr := s.DeleteAuthToken(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scope)), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "DeleteUser(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
assert.EqualValuesf(tc.res, got, "DeleteUser(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
func TestDelete_twice(t *testing.T) {
assert := assert.New(t)
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, wrap)
}
org, _ := iam.TestScopes(t, conn)
at := authtoken.TestAuthToken(t, conn, wrap, org.GetPublicId())
s, err := authtokens.NewService(repoFn)
require.NoError(t, err, "Error when getting new user service")
req := &pbs.DeleteAuthTokenRequest{
Id: at.GetPublicId(),
}
got, gErr := s.DeleteAuthToken(auth.DisabledAuthTestContext(auth.WithScopeId(at.GetScopeId())), req)
assert.NoError(gErr, "First attempt")
assert.True(got.GetExisted(), "Expected existed to be true for the first delete.")
got, gErr = s.DeleteAuthToken(auth.DisabledAuthTestContext(auth.WithScopeId(at.GetScopeId())), req)
assert.NoError(gErr, "Second attempt")
assert.False(got.GetExisted(), "Expected existed to be false for the second delete.")
}
+4 -1
View File
@@ -26,7 +26,8 @@ const (
Global Type = 19
// TODO: remove this after demo
Group Type = 20
Group Type = 20
AuthToken Type = 21
)
func (r Type) String() string {
@@ -52,6 +53,7 @@ func (r Type) String() string {
"target",
"global",
"group",
"auth-token",
}[r]
}
@@ -76,4 +78,5 @@ var Map = map[string]Type{
Target.String(): Target,
Global.String(): Global,
Group.String(): Group,
AuthToken.String(): AuthToken,
}