Auth Method API Handler for CRUDL (not updating password specific fields)(#239)

This commit is contained in:
Todd Knight authored and GitHub committed 2020-08-06 12:50:20 -07:00
1 parent 7fefd5e2fe
commit b7bf76a9ba
15 files changed
+3676 -21

No files matched your search

@@ -208,15 +208,14 @@ func (r *Repository) UpdateAuthMethod(ctx context.Context, authMethod *AuthMetho
dbOpts...,
)
if err == nil && rowsUpdated > 1 {
// return err, which will result in a rollback of the update
return errors.New("error more than 1 resource would have been updated ")
return db.ErrMultipleRecords
}
return err
},
)
if err != nil {
if db.IsUniqueError(err) {
return nil, db.NoRowsAffected, fmt.Errorf("update: password auth method: authMethod %s already exists in scope %s", authMethod.Name, authMethod.ScopeId)
return nil, db.NoRowsAffected, fmt.Errorf("update: password auth method: authMethod %s already exists in scope %s: %w", authMethod.Name, authMethod.ScopeId, db.ErrNotUnique)
}
return nil, db.NoRowsAffected, fmt.Errorf("update: password auth method: %w for %s", err, authMethod.PublicId)
}
@@ -496,6 +496,15 @@ func TestRepository_UpdateAuthMethod(t *testing.T) {
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "null name ignored description",
args: args{
updates: &store.AuthMethod{Description: "ignored"},
fieldMaskPaths: []string{"name"},
},
wantErr: false,
wantRowsUpdate: 1,
},
{
name: "change min pw",
args: args{
+22
View File
@@ -23,6 +23,28 @@ import (
"google.golang.org/protobuf/proto"
)
func TestDb_UpdateUnsetField(t *testing.T) {
db, _ := TestSetup(t, "postgres")
rw := &Db{
underlying: db,
}
tu := &db_test.TestUser{
StoreTestUser: &db_test.StoreTestUser{
PublicId: testId(t),
Name: "default",
}}
require.NoError(t, rw.Create(context.Background(), tu))
updatedTu := tu.Clone().(*db_test.TestUser)
updatedTu.Name = "updated"
updatedTu.Email = "ignore"
cnt, err := rw.Update(context.Background(), updatedTu, []string{"Name"}, nil)
require.NoError(t, err)
assert.Equal(t, 1, cnt)
assert.Equal(t, "ignore", updatedTu.Email)
assert.Equal(t, "updated", updatedTu.Name)
}
func TestDb_Update(t *testing.T) {
db, _ := TestSetup(t, "postgres")
now := &timestamp.Timestamp{Timestamp: ptypes.TimestampNow()}
+226
View File
@@ -72,6 +72,56 @@
]
}
},
"/v1/scopes/*/auth-methods": {
"get": {
"summary": "Lists all AuthMethods",
"operationId": "AuthMethodService_ListAuthMethods",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/controller.api.services.v1.ListAuthMethodsResponse"
}
}
},
"parameters": [
{
"name": "view",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
"controller.api.services.v1.AuthMethodService"
]
},
"post": {
"summary": "Creates a single AuthMethod",
"operationId": "AuthMethodService_CreateAuthMethod",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
],
"tags": [
"controller.api.services.v1.AuthMethodService"
]
}
},
"/v1/scopes/*/auth-methods/{auth_method_id}/accounts": {
"get": {
"summary": "Lists all accounts in a specific auth method.",
@@ -271,6 +321,91 @@
]
}
},
"/v1/scopes/*/auth-methods/{id}": {
"get": {
"summary": "Gets a single AuthMethod",
"operationId": "AuthMethodService_GetAuthMethod",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "view",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
"controller.api.services.v1.AuthMethodService"
]
},
"delete": {
"summary": "Deletes an AuthMethod",
"operationId": "AuthMethodService_DeleteAuthMethod",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/controller.api.services.v1.DeleteAuthMethodResponse"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"controller.api.services.v1.AuthMethodService"
]
},
"patch": {
"summary": "Updates an AuthMethod",
"operationId": "AuthMethodService_UpdateAuthMethod",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
],
"tags": [
"controller.api.services.v1.AuthMethodService"
]
}
},
"/v1/scopes/*/auth-tokens": {
"get": {
"summary": "Lists all AuthTokens",
@@ -1725,6 +1860,50 @@
},
"title": "Account contains all fields related to an auth Account resource"
},
"controller.api.resources.auth.v1.AuthMethod": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The ID of the AuthMethod\nOutput only.",
"readOnly": true
},
"scope": {
"$ref": "#/definitions/controller.api.resources.scopes.v1.ScopeInfo",
"description": "Scope information for this resource\nOutput only.",
"readOnly": true
},
"name": {
"type": "string",
"title": "Optional name for identification purposes"
},
"description": {
"type": "string",
"title": "Optional user-set descripton for identification purposes"
},
"created_time": {
"type": "string",
"format": "date-time",
"description": "The time this resource was created\nOutput only.",
"readOnly": true
},
"updated_time": {
"type": "string",
"format": "date-time",
"description": "The time this resource was last updated.\nOutput only.",
"readOnly": true
},
"type": {
"type": "string",
"description": "The auth method type. This can be \"password\" or \"oidc\"."
},
"attributes": {
"type": "object",
"description": "The attributes that are applied for the specific Auth Method type."
}
},
"title": "AuthMethod contains all fields related to a AuthMethod resource"
},
"controller.api.resources.authtokens.v1.AuthToken": {
"type": "object",
"properties": {
@@ -2398,6 +2577,17 @@
}
}
},
"controller.api.services.v1.CreateAuthMethodResponse": {
"type": "object",
"properties": {
"uri": {
"type": "string"
},
"item": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
},
"controller.api.services.v1.CreateGroupResponse": {
"type": "object",
"properties": {
@@ -2484,6 +2674,15 @@
}
}
},
"controller.api.services.v1.DeleteAuthMethodResponse": {
"type": "object",
"properties": {
"existed": {
"type": "boolean",
"format": "boolean"
}
}
},
"controller.api.services.v1.DeleteAuthTokenResponse": {
"type": "object",
"properties": {
@@ -2564,6 +2763,14 @@
}
}
},
"controller.api.services.v1.GetAuthMethodResponse": {
"type": "object",
"properties": {
"item": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
},
"controller.api.services.v1.GetAuthTokenResponse": {
"type": "object",
"properties": {
@@ -2639,6 +2846,17 @@
}
}
},
"controller.api.services.v1.ListAuthMethodsResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
}
},
"controller.api.services.v1.ListAuthTokensResponse": {
"type": "object",
"properties": {
@@ -2900,6 +3118,14 @@
}
}
},
"controller.api.services.v1.UpdateAuthMethodResponse": {
"type": "object",
"properties": {
"item": {
"$ref": "#/definitions/controller.api.resources.auth.v1.AuthMethod"
}
}
},
"controller.api.services.v1.UpdateGroupResponse": {
"type": "object",
"properties": {
@@ -0,0 +1,355 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: controller/api/resources/auth/v1/auth_method.proto
package auth
import (
proto "github.com/golang/protobuf/proto"
_struct "github.com/golang/protobuf/ptypes/struct"
timestamp "github.com/golang/protobuf/ptypes/timestamp"
wrappers "github.com/golang/protobuf/ptypes/wrappers"
scopes "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/scopes"
_ "github.com/hashicorp/watchtower/internal/gen/controller/protooptions"
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
// AuthMethod contains all fields related to a AuthMethod resource
type AuthMethod struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The ID of the AuthMethod
// Output only.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// Scope information for this resource
// Output only.
Scope *scopes.ScopeInfo `protobuf:"bytes,2,opt,name=scope,proto3" json:"scope,omitempty"`
// Optional name for identification purposes
Name *wrappers.StringValue `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
// Optional user-set descripton for identification purposes
Description *wrappers.StringValue `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
// The time this resource was created
// Output only.
CreatedTime *timestamp.Timestamp `protobuf:"bytes,5,opt,name=created_time,proto3" json:"created_time,omitempty"`
// The time this resource was last updated.
// Output only.
UpdatedTime *timestamp.Timestamp `protobuf:"bytes,6,opt,name=updated_time,proto3" json:"updated_time,omitempty"`
// The auth method type. This can be "password" or "oidc".
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
// The attributes that are applied for the specific Auth Method type.
Attributes *_struct.Struct `protobuf:"bytes,8,opt,name=attributes,proto3" json:"attributes,omitempty"`
}
func (x *AuthMethod) Reset() {
*x = AuthMethod{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_resources_auth_v1_auth_method_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AuthMethod) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AuthMethod) ProtoMessage() {}
func (x *AuthMethod) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_resources_auth_v1_auth_method_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 AuthMethod.ProtoReflect.Descriptor instead.
func (*AuthMethod) Descriptor() ([]byte, []int) {
return file_controller_api_resources_auth_v1_auth_method_proto_rawDescGZIP(), []int{0}
}
func (x *AuthMethod) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *AuthMethod) GetScope() *scopes.ScopeInfo {
if x != nil {
return x.Scope
}
return nil
}
func (x *AuthMethod) GetName() *wrappers.StringValue {
if x != nil {
return x.Name
}
return nil
}
func (x *AuthMethod) GetDescription() *wrappers.StringValue {
if x != nil {
return x.Description
}
return nil
}
func (x *AuthMethod) GetCreatedTime() *timestamp.Timestamp {
if x != nil {
return x.CreatedTime
}
return nil
}
func (x *AuthMethod) GetUpdatedTime() *timestamp.Timestamp {
if x != nil {
return x.UpdatedTime
}
return nil
}
func (x *AuthMethod) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *AuthMethod) GetAttributes() *_struct.Struct {
if x != nil {
return x.Attributes
}
return nil
}
type PasswordAuthMethodAttributes struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The minimum length allowed for user names for accounts in this auth method.
MinUserNameLength uint32 `protobuf:"varint,1,opt,name=min_user_name_length,json=minUserNameLength,proto3" json:"min_user_name_length,omitempty"`
// The minimum length allowed for passwords for accounts in this auth method.
MinPasswordLength uint32 `protobuf:"varint,2,opt,name=min_password_length,json=minPasswordLength,proto3" json:"min_password_length,omitempty"`
}
func (x *PasswordAuthMethodAttributes) Reset() {
*x = PasswordAuthMethodAttributes{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_resources_auth_v1_auth_method_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PasswordAuthMethodAttributes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PasswordAuthMethodAttributes) ProtoMessage() {}
func (x *PasswordAuthMethodAttributes) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_resources_auth_v1_auth_method_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 PasswordAuthMethodAttributes.ProtoReflect.Descriptor instead.
func (*PasswordAuthMethodAttributes) Descriptor() ([]byte, []int) {
return file_controller_api_resources_auth_v1_auth_method_proto_rawDescGZIP(), []int{1}
}
func (x *PasswordAuthMethodAttributes) GetMinUserNameLength() uint32 {
if x != nil {
return x.MinUserNameLength
}
return 0
}
func (x *PasswordAuthMethodAttributes) GetMinPasswordLength() uint32 {
if x != nil {
return x.MinPasswordLength
}
return 0
}
var File_controller_api_resources_auth_v1_auth_method_proto protoreflect.FileDescriptor
var file_controller_api_resources_auth_v1_auth_method_proto_rawDesc = []byte{
0x0a, 0x32, 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, 0x2f,
0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x20, 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, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72,
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 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,
0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
0xd2, 0x03, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x43,
0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63,
0x6f, 0x70, 0x65, 0x12, 0x42, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42,
0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x5e, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a,
0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x61,
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
0x75, 0x74, 0x65, 0x73, 0x22, 0x7f, 0x0a, 0x1c, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x6d, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x11, 0x6d, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x4c,
0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x11, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c,
0x65, 0x6e, 0x67, 0x74, 0x68, 0x42, 0x51, 0x5a, 0x4f, 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, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x61,
0x75, 0x74, 0x68, 0x3b, 0x61, 0x75, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_controller_api_resources_auth_v1_auth_method_proto_rawDescOnce sync.Once
file_controller_api_resources_auth_v1_auth_method_proto_rawDescData = file_controller_api_resources_auth_v1_auth_method_proto_rawDesc
)
func file_controller_api_resources_auth_v1_auth_method_proto_rawDescGZIP() []byte {
file_controller_api_resources_auth_v1_auth_method_proto_rawDescOnce.Do(func() {
file_controller_api_resources_auth_v1_auth_method_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_resources_auth_v1_auth_method_proto_rawDescData)
})
return file_controller_api_resources_auth_v1_auth_method_proto_rawDescData
}
var file_controller_api_resources_auth_v1_auth_method_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_controller_api_resources_auth_v1_auth_method_proto_goTypes = []interface{}{
(*AuthMethod)(nil), // 0: controller.api.resources.auth.v1.AuthMethod
(*PasswordAuthMethodAttributes)(nil), // 1: controller.api.resources.auth.v1.PasswordAuthMethodAttributes
(*scopes.ScopeInfo)(nil), // 2: controller.api.resources.scopes.v1.ScopeInfo
(*wrappers.StringValue)(nil), // 3: google.protobuf.StringValue
(*timestamp.Timestamp)(nil), // 4: google.protobuf.Timestamp
(*_struct.Struct)(nil), // 5: google.protobuf.Struct
}
var file_controller_api_resources_auth_v1_auth_method_proto_depIdxs = []int32{
2, // 0: controller.api.resources.auth.v1.AuthMethod.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
3, // 1: controller.api.resources.auth.v1.AuthMethod.name:type_name -> google.protobuf.StringValue
3, // 2: controller.api.resources.auth.v1.AuthMethod.description:type_name -> google.protobuf.StringValue
4, // 3: controller.api.resources.auth.v1.AuthMethod.created_time:type_name -> google.protobuf.Timestamp
4, // 4: controller.api.resources.auth.v1.AuthMethod.updated_time:type_name -> google.protobuf.Timestamp
5, // 5: controller.api.resources.auth.v1.AuthMethod.attributes:type_name -> google.protobuf.Struct
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_controller_api_resources_auth_v1_auth_method_proto_init() }
func file_controller_api_resources_auth_v1_auth_method_proto_init() {
if File_controller_api_resources_auth_v1_auth_method_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_controller_api_resources_auth_v1_auth_method_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AuthMethod); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_api_resources_auth_v1_auth_method_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PasswordAuthMethodAttributes); 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_resources_auth_v1_auth_method_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_controller_api_resources_auth_v1_auth_method_proto_goTypes,
DependencyIndexes: file_controller_api_resources_auth_v1_auth_method_proto_depIdxs,
MessageInfos: file_controller_api_resources_auth_v1_auth_method_proto_msgTypes,
}.Build()
File_controller_api_resources_auth_v1_auth_method_proto = out.File
file_controller_api_resources_auth_v1_auth_method_proto_rawDesc = nil
file_controller_api_resources_auth_v1_auth_method_proto_goTypes = nil
file_controller_api_resources_auth_v1_auth_method_proto_depIdxs = nil
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,628 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: controller/api/services/v1/auth_method_service.proto
/*
Package services is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package services
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var (
filter_AuthMethodService_GetAuthMethod_0 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_AuthMethodService_GetAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, client AuthMethodServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetAuthMethodRequest
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_AuthMethodService_GetAuthMethod_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetAuthMethod(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthMethodService_GetAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, server AuthMethodServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetAuthMethodRequest
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_AuthMethodService_GetAuthMethod_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetAuthMethod(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_AuthMethodService_ListAuthMethods_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_AuthMethodService_ListAuthMethods_0(ctx context.Context, marshaler runtime.Marshaler, client AuthMethodServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAuthMethodsRequest
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_AuthMethodService_ListAuthMethods_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListAuthMethods(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthMethodService_ListAuthMethods_0(ctx context.Context, marshaler runtime.Marshaler, server AuthMethodServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListAuthMethodsRequest
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_AuthMethodService_ListAuthMethods_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListAuthMethods(ctx, &protoReq)
return msg, metadata, err
}
func request_AuthMethodService_CreateAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, client AuthMethodServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CreateAuthMethodRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.CreateAuthMethod(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthMethodService_CreateAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, server AuthMethodServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CreateAuthMethodRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.CreateAuthMethod(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_AuthMethodService_UpdateAuthMethod_0 = &utilities.DoubleArray{Encoding: map[string]int{"item": 0, "id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
func request_AuthMethodService_UpdateAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, client AuthMethodServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UpdateAuthMethodRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Item); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
} else {
protoReq.UpdateMask = fieldMask
}
}
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_AuthMethodService_UpdateAuthMethod_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.UpdateAuthMethod(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthMethodService_UpdateAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, server AuthMethodServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UpdateAuthMethodRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Item); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
} else {
protoReq.UpdateMask = fieldMask
}
}
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_AuthMethodService_UpdateAuthMethod_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.UpdateAuthMethod(ctx, &protoReq)
return msg, metadata, err
}
func request_AuthMethodService_DeleteAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, client AuthMethodServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteAuthMethodRequest
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.DeleteAuthMethod(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthMethodService_DeleteAuthMethod_0(ctx context.Context, marshaler runtime.Marshaler, server AuthMethodServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteAuthMethodRequest
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.DeleteAuthMethod(ctx, &protoReq)
return msg, metadata, err
}
// RegisterAuthMethodServiceHandlerServer registers the http handlers for service AuthMethodService to "mux".
// UnaryRPC :call AuthMethodServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
func RegisterAuthMethodServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthMethodServiceServer) error {
mux.Handle("GET", pattern_AuthMethodService_GetAuthMethod_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, "/controller.api.services.v1.AuthMethodService/GetAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthMethodService_GetAuthMethod_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_GetAuthMethod_0(ctx, mux, outboundMarshaler, w, req, response_AuthMethodService_GetAuthMethod_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AuthMethodService_ListAuthMethods_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, "/controller.api.services.v1.AuthMethodService/ListAuthMethods")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthMethodService_ListAuthMethods_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_ListAuthMethods_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_AuthMethodService_CreateAuthMethod_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, "/controller.api.services.v1.AuthMethodService/CreateAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthMethodService_CreateAuthMethod_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_CreateAuthMethod_0(ctx, mux, outboundMarshaler, w, req, response_AuthMethodService_CreateAuthMethod_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_AuthMethodService_UpdateAuthMethod_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, "/controller.api.services.v1.AuthMethodService/UpdateAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthMethodService_UpdateAuthMethod_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_UpdateAuthMethod_0(ctx, mux, outboundMarshaler, w, req, response_AuthMethodService_UpdateAuthMethod_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_AuthMethodService_DeleteAuthMethod_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, "/controller.api.services.v1.AuthMethodService/DeleteAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthMethodService_DeleteAuthMethod_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_DeleteAuthMethod_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterAuthMethodServiceHandlerFromEndpoint is same as RegisterAuthMethodServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterAuthMethodServiceHandlerFromEndpoint(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 RegisterAuthMethodServiceHandler(ctx, mux, conn)
}
// RegisterAuthMethodServiceHandler registers the http handlers for service AuthMethodService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterAuthMethodServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterAuthMethodServiceHandlerClient(ctx, mux, NewAuthMethodServiceClient(conn))
}
// RegisterAuthMethodServiceHandlerClient registers the http handlers for service AuthMethodService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AuthMethodServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AuthMethodServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "AuthMethodServiceClient" to call the correct interceptors.
func RegisterAuthMethodServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AuthMethodServiceClient) error {
mux.Handle("GET", pattern_AuthMethodService_GetAuthMethod_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, "/controller.api.services.v1.AuthMethodService/GetAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthMethodService_GetAuthMethod_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_GetAuthMethod_0(ctx, mux, outboundMarshaler, w, req, response_AuthMethodService_GetAuthMethod_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_AuthMethodService_ListAuthMethods_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, "/controller.api.services.v1.AuthMethodService/ListAuthMethods")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthMethodService_ListAuthMethods_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_ListAuthMethods_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_AuthMethodService_CreateAuthMethod_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, "/controller.api.services.v1.AuthMethodService/CreateAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthMethodService_CreateAuthMethod_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_CreateAuthMethod_0(ctx, mux, outboundMarshaler, w, req, response_AuthMethodService_CreateAuthMethod_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_AuthMethodService_UpdateAuthMethod_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, "/controller.api.services.v1.AuthMethodService/UpdateAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthMethodService_UpdateAuthMethod_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_UpdateAuthMethod_0(ctx, mux, outboundMarshaler, w, req, response_AuthMethodService_UpdateAuthMethod_0{resp}, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_AuthMethodService_DeleteAuthMethod_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, "/controller.api.services.v1.AuthMethodService/DeleteAuthMethod")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthMethodService_DeleteAuthMethod_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthMethodService_DeleteAuthMethod_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
type response_AuthMethodService_GetAuthMethod_0 struct {
proto.Message
}
func (m response_AuthMethodService_GetAuthMethod_0) XXX_ResponseBody() interface{} {
response := m.Message.(*GetAuthMethodResponse)
return response.Item
}
type response_AuthMethodService_CreateAuthMethod_0 struct {
proto.Message
}
func (m response_AuthMethodService_CreateAuthMethod_0) XXX_ResponseBody() interface{} {
response := m.Message.(*CreateAuthMethodResponse)
return response.Item
}
type response_AuthMethodService_UpdateAuthMethod_0 struct {
proto.Message
}
func (m response_AuthMethodService_UpdateAuthMethod_0) XXX_ResponseBody() interface{} {
response := m.Message.(*UpdateAuthMethodResponse)
return response.Item
}
var (
pattern_AuthMethodService_GetAuthMethod_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-methods", "id"}, ""))
pattern_AuthMethodService_ListAuthMethods_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2}, []string{"v1", "scopes", "auth-methods"}, ""))
pattern_AuthMethodService_CreateAuthMethod_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2}, []string{"v1", "scopes", "auth-methods"}, ""))
pattern_AuthMethodService_UpdateAuthMethod_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-methods", "id"}, ""))
pattern_AuthMethodService_DeleteAuthMethod_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-methods", "id"}, ""))
)
var (
forward_AuthMethodService_GetAuthMethod_0 = runtime.ForwardResponseMessage
forward_AuthMethodService_ListAuthMethods_0 = runtime.ForwardResponseMessage
forward_AuthMethodService_CreateAuthMethod_0 = runtime.ForwardResponseMessage
forward_AuthMethodService_UpdateAuthMethod_0 = runtime.ForwardResponseMessage
forward_AuthMethodService_DeleteAuthMethod_0 = runtime.ForwardResponseMessage
)
@@ -0,0 +1,50 @@
syntax = "proto3";
package controller.api.resources.auth.v1;
option go_package = "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/auth;auth";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/struct.proto";
import "controller/api/resources/scopes/v1/scope.proto";
import "controller/custom_options/v1/masks.proto";
// AuthMethod contains all fields related to a AuthMethod resource
message AuthMethod {
// The ID of the AuthMethod
// Output only.
string id = 1;
// Scope information for this resource
// Output only.
resources.scopes.v1.ScopeInfo scope = 2;
// Optional name for identification purposes
google.protobuf.StringValue name = 3 [(custom_options.v1.mask_mapping) = {this:"name" that: "name"}];
// Optional user-set descripton for identification purposes
google.protobuf.StringValue description = 4 [(custom_options.v1.mask_mapping) = {this:"description" that: "description"}];
// The time this resource was created
// Output only.
google.protobuf.Timestamp created_time = 5 [json_name="created_time"];
// The time this resource was last updated.
// Output only.
google.protobuf.Timestamp updated_time = 6 [json_name="updated_time"];
// The auth method type. This can be "password" or "oidc".
string type = 7;
// The attributes that are applied for the specific Auth Method type.
google.protobuf.Struct attributes = 8;
}
message PasswordAuthMethodAttributes {
// The minimum length allowed for user names for accounts in this auth method.
uint32 min_user_name_length = 1;
// The minimum length allowed for passwords for accounts in this auth method.
uint32 min_password_length = 2;
}
@@ -0,0 +1,132 @@
syntax = "proto3";
package controller.api.services.v1;
option go_package = "github.com/hashicorp/watchtower/internal/gen/controller/api/services;services";
import "protoc-gen-openapiv2/options/annotations.proto";
import "google/api/annotations.proto";
import "google/protobuf/field_mask.proto";
import "controller/api/resources/auth/v1/auth_method.proto";
service AuthMethodService {
// GetAuthMethod returns a stored AuthMethod if present. The provided request
// must include the org and auth method id for the auth method being retrieved. If
// any of those ids are missing, malformed or reference a non existing
// resource an error is returned.
rpc GetAuthMethod(GetAuthMethodRequest) returns (GetAuthMethodResponse) {
option (google.api.http) = {
get: "/v1/scopes/*/auth-methods/{id}"
response_body: "item"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Gets a single AuthMethod"
};
}
// ListAuthMethods returns a list of stored auth methods which exist inside the org
// referenced inside the request. The request must include the org id for
// the auth methods being retrieved. If the org id is missing, malformed, or
// reference a non existing organization, an error is returned.
rpc ListAuthMethods(ListAuthMethodsRequest) returns (ListAuthMethodsResponse) {
option (google.api.http) = {
get: "/v1/scopes/*/auth-methods"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Lists all AuthMethods"
};
}
// CreateAuthMethod creates and stores a user in watchtower. The provided
// request must include the org id in which the user will be created.
// If the org id is missing, malformed or references a non existing
// org, an error is returned. If a name is provided that is in
// use in another user in the same org, an error is returned.
rpc CreateAuthMethod(CreateAuthMethodRequest) returns (CreateAuthMethodResponse) {
option (google.api.http) = {
post: "/v1/scopes/*/auth-methods"
body: "item"
response_body: "item"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Creates a single AuthMethod"
};
}
// UpdateAuthMethod updates an existing user in watchtower. The provided
// user must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided user. An error is returned if either the org
// or user ids are missing or reference a non existing resource. An error
// is also returned if the request attempts to update the name to one that is
// already in use in this org.
rpc UpdateAuthMethod(UpdateAuthMethodRequest) returns (UpdateAuthMethodResponse) {
option (google.api.http) = {
patch: "/v1/scopes/*/auth-methods/{id}"
body: "item"
response_body: "item"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Updates an AuthMethod"
};
}
// DeleteAuthMethod removes a user from Watchtower. If the provided org or user 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 DeleteAuthMethod request was
// received.
rpc DeleteAuthMethod(DeleteAuthMethodRequest) returns (DeleteAuthMethodResponse) {
option (google.api.http) = {
delete: "/v1/scopes/*/auth-methods/{id}"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Deletes an AuthMethod"
};
}
}
message GetAuthMethodRequest {
string id = 1;
string view = 2;
}
message GetAuthMethodResponse {
resources.auth.v1.AuthMethod item = 1;
}
message ListAuthMethodsRequest {
string view = 1;
}
message ListAuthMethodsResponse {
repeated resources.auth.v1.AuthMethod items = 1;
}
message CreateAuthMethodRequest {
resources.auth.v1.AuthMethod item = 1;
}
message CreateAuthMethodResponse {
string uri = 1;
resources.auth.v1.AuthMethod item = 2;
}
message UpdateAuthMethodRequest {
string id = 1;
resources.auth.v1.AuthMethod item = 2;
google.protobuf.FieldMask update_mask = 3;
}
message UpdateAuthMethodResponse {
resources.auth.v1.AuthMethod item = 1;
}
message DeleteAuthMethodRequest {
string id = 1;
}
message DeleteAuthMethodResponse {
bool existed = 1;
}
+1 -1
View File
@@ -81,7 +81,7 @@ func handleGrpcGateway(c *Controller) (http.Handler, error) {
if err := services.RegisterHostCatalogServiceHandlerServer(ctx, mux, hcs); err != nil {
return nil, fmt.Errorf("failed to register host catalog service handler: %w", err)
}
accts, err := accounts.NewService(c.logger, c.PasswordAuthRepoFn)
accts, err := accounts.NewService(c.PasswordAuthRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create account handler service: %w", err)
}
@@ -7,7 +7,6 @@ import (
"regexp"
"strings"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/watchtower/internal/auth"
"github.com/hashicorp/watchtower/internal/auth/password"
"github.com/hashicorp/watchtower/internal/auth/password/store"
@@ -35,15 +34,14 @@ func init() {
// Service handles request as described by the pbs.AccountServiceServer interface.
type Service struct {
repoFn func() (*password.Repository, error)
log hclog.Logger
}
// NewService returns a user service which handles user related requests to watchtower.
func NewService(log hclog.Logger, repo func() (*password.Repository, error)) (Service, error) {
func NewService(repo func() (*password.Repository, error)) (Service, error) {
if repo == nil {
return Service{}, fmt.Errorf("nil password repository provided")
}
return Service{log: log, repoFn: repo}, nil
return Service{repoFn: repo}, nil
}
var _ pbs.AccountServiceServer = Service{}
@@ -139,7 +137,7 @@ func (s Service) getFromRepo(ctx context.Context, id string) (*pb.Account, error
if u == nil {
return nil, handlers.NotFoundErrorf("Account %q doesn't exist.", id)
}
return s.toProto(u), nil
return toProto(u)
}
func (s Service) createInRepo(ctx context.Context, authMethodId string, item *pb.Account) (*pb.Account, error) {
@@ -169,7 +167,7 @@ func (s Service) createInRepo(ctx context.Context, authMethodId string, item *pb
if out == nil {
return nil, status.Error(codes.Internal, "Unable to create user but no error returned from repository.")
}
return s.toProto(out), nil
return toProto(out)
}
func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
@@ -198,12 +196,16 @@ func (s Service) listFromRepo(ctx context.Context, authMethodId string) ([]*pb.A
}
var outUl []*pb.Account
for _, u := range ul {
outUl = append(outUl, s.toProto(u))
ou, err := toProto(u)
if err != nil {
return nil, err
}
outUl = append(outUl, ou)
}
return outUl, nil
}
func (s Service) toProto(in *password.Account) *pb.Account {
func toProto(in *password.Account) (*pb.Account, error) {
out := pb.Account{
Id: in.GetPublicId(),
CreatedTime: in.GetCreateTime().GetTimestamp(),
@@ -220,9 +222,9 @@ func (s Service) toProto(in *password.Account) *pb.Account {
if st, err := handlers.ProtoToStruct(&pb.PasswordAccountAttributes{Username: in.GetUserName()}); err == nil {
out.Attributes = st
} else {
s.log.Error("failed converting account attribute to struct", "error", err)
return nil, status.Errorf(codes.Internal, "failed building password attribute struct: %v", err)
}
return &out
return &out, nil
}
// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce
@@ -7,7 +7,6 @@ import (
"github.com/golang/protobuf/ptypes"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/watchtower/internal/auth"
"github.com/hashicorp/watchtower/internal/auth/password"
"github.com/hashicorp/watchtower/internal/authtoken"
@@ -36,7 +35,7 @@ func TestGet(t *testing.T) {
return password.NewRepository(rw, rw, wrap)
}
s, err := accounts.NewService(hclog.L(), repoFn)
s, err := accounts.NewService(repoFn)
require.NoError(t, err, "Couldn't create new auth token service.")
org, _ := iam.TestScopes(t, conn)
@@ -166,7 +165,7 @@ func TestList(t *testing.T) {
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
s, err := accounts.NewService(hclog.L(), repoFn)
s, err := accounts.NewService(repoFn)
require.NoError(t, err, "Couldn't create new user service.")
got, gErr := s.ListAccounts(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), &pbs.ListAccountsRequest{AuthMethodId: tc.authMethod})
@@ -191,7 +190,7 @@ func TestDelete(t *testing.T) {
ac := password.TestAccounts(t, conn, am1.GetPublicId(), 1)[0]
wrongAc := password.TestAccounts(t, conn, wrongAm.GetPublicId(), 1)[0]
s, err := accounts.NewService(hclog.L(), repoFn)
s, err := accounts.NewService(repoFn)
require.NoError(t, err, "Error when getting new user service.")
cases := []struct {
@@ -269,7 +268,7 @@ func TestDelete_twice(t *testing.T) {
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
ac := password.TestAccounts(t, conn, am.GetPublicId(), 1)[0]
s, err := accounts.NewService(hclog.L(), repoFn)
s, err := accounts.NewService(repoFn)
require.NoError(t, err, "Error when getting new user service")
req := &pbs.DeleteAccountRequest{
AuthMethodId: am.GetPublicId(),
@@ -291,7 +290,7 @@ func TestCreate(t *testing.T) {
return password.NewRepository(rw, rw, wrap)
}
s, err := accounts.NewService(hclog.L(), repoFn)
s, err := accounts.NewService(repoFn)
require.NoError(t, err, "Error when getting new account service.")
o, _ := iam.TestScopes(t, conn)
@@ -0,0 +1,370 @@
package authmethods
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"github.com/hashicorp/watchtower/internal/auth"
"github.com/hashicorp/watchtower/internal/auth/password"
"github.com/hashicorp/watchtower/internal/auth/password/store"
"github.com/hashicorp/watchtower/internal/db"
pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/auth"
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"
"google.golang.org/protobuf/types/known/wrapperspb"
)
var (
maskManager handlers.MaskManager
reInvalidID = regexp.MustCompile("[^A-Za-z0-9]")
)
func init() {
var err error
if maskManager, err = handlers.NewMaskManager(&pb.AuthMethod{}, &store.AuthMethod{}); err != nil {
panic(err)
}
}
// Service handles request as described by the pbs.AuthMethodServiceServer interface.
type Service struct {
repoFn func() (*password.Repository, error)
}
// NewService returns a auth method service which handles auth method related requests to watchtower.
func NewService(repo func() (*password.Repository, error)) (Service, error) {
if repo == nil {
return Service{}, fmt.Errorf("nil iam repository provided")
}
return Service{repoFn: repo}, nil
}
var _ pbs.AuthMethodServiceServer = Service{}
// ListAuthMethods implements the interface pbs.AuthMethodServiceServer.
func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRequest) (*pbs.ListAuthMethodsResponse, 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.ListAuthMethodsResponse{Items: ul}, nil
}
// GetAuthMethods implements the interface pbs.AuthMethodServiceServer.
func (s Service) GetAuthMethod(ctx context.Context, req *pbs.GetAuthMethodRequest) (*pbs.GetAuthMethodResponse, 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.GetAuthMethodResponse{Item: u}, nil
}
// CreateAuthMethod implements the interface pbs.AuthMethodServiceServer.
func (s Service) CreateAuthMethod(ctx context.Context, req *pbs.CreateAuthMethodRequest) (*pbs.CreateAuthMethodResponse, error) {
authResults := auth.Verify(ctx)
if !authResults.Valid {
return nil, handlers.ForbiddenError()
}
if err := validateCreateRequest(req); err != nil {
return nil, err
}
u, err := s.createInRepo(ctx, authResults.Scope.GetId(), req.GetItem())
if err != nil {
return nil, err
}
u.Scope = authResults.Scope
return &pbs.CreateAuthMethodResponse{Item: u, Uri: fmt.Sprintf("scopes/%s/auth-methods/%s", authResults.Scope.GetId(), u.GetId())}, nil
}
// UpdateAuthMethod implements the interface pbs.AuthMethodServiceServer.
func (s Service) UpdateAuthMethod(ctx context.Context, req *pbs.UpdateAuthMethodRequest) (*pbs.UpdateAuthMethodResponse, error) {
authResults := auth.Verify(ctx)
if !authResults.Valid {
return nil, handlers.ForbiddenError()
}
if err := validateUpdateRequest(req); err != nil {
return nil, err
}
u, err := s.updateInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem())
if err != nil {
return nil, err
}
return &pbs.UpdateAuthMethodResponse{Item: u}, nil
}
// DeleteAuthMethod implements the interface pbs.AuthMethodServiceServer.
func (s Service) DeleteAuthMethod(ctx context.Context, req *pbs.DeleteAuthMethodRequest) (*pbs.DeleteAuthMethodResponse, 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.DeleteAuthMethodResponse{Existed: existed}, nil
}
func (s Service) getFromRepo(ctx context.Context, id string) (*pb.AuthMethod, error) {
repo, err := s.repoFn()
if err != nil {
return nil, err
}
u, err := repo.LookupAuthMethod(ctx, id)
if err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return nil, handlers.NotFoundErrorf("AuthMethod %q doesn't exist.", id)
}
return nil, err
}
if u == nil {
return nil, handlers.NotFoundErrorf("AuthMethod %q doesn't exist.", id)
}
return toProto(u)
}
func (s Service) listFromRepo(ctx context.Context, scopeId string) ([]*pb.AuthMethod, error) {
repo, err := s.repoFn()
if err != nil {
return nil, err
}
ul, err := repo.ListAuthMethods(ctx, scopeId)
if err != nil {
return nil, err
}
var outUl []*pb.AuthMethod
for _, u := range ul {
ou, err := toProto(u)
if err != nil {
return nil, err
}
outUl = append(outUl, ou)
}
return outUl, nil
}
func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.AuthMethod) (*pb.AuthMethod, error) {
var opts []password.Option
if item.GetName() != nil {
opts = append(opts, password.WithName(item.GetName().GetValue()))
}
if item.GetDescription() != nil {
opts = append(opts, password.WithDescription(item.GetDescription().GetValue()))
}
u, err := password.NewAuthMethod(scopeId, opts...)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to build auth method for creation: %v.", err)
}
repo, err := s.repoFn()
if err != nil {
return nil, err
}
out, err := repo.CreateAuthMethod(ctx, u)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to create auth method: %v.", err)
}
if out == nil {
return nil, status.Error(codes.Internal, "Unable to create auth method but no error returned from repository.")
}
return toProto(out)
}
func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.AuthMethod) (*pb.AuthMethod, error) {
var opts []password.Option
if desc := item.GetDescription(); desc != nil {
opts = append(opts, password.WithDescription(desc.GetValue()))
}
if name := item.GetName(); name != nil {
opts = append(opts, password.WithName(name.GetValue()))
}
u, err := password.NewAuthMethod(scopeId, opts...)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to build auth method for update: %v.", err)
}
u.PublicId = id
dbMask := maskManager.Translate(mask)
if len(dbMask) == 0 {
return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid paths provided in the update mask."})
}
repo, err := s.repoFn()
if err != nil {
return nil, err
}
out, rowsUpdated, err := repo.UpdateAuthMethod(ctx, u, dbMask)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to update auth method: %v.", err)
}
if rowsUpdated == 0 {
return nil, handlers.NotFoundErrorf("AuthMethod %q doesn't exist.", id)
}
return toProto(out)
}
func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
repo, err := s.repoFn()
if err != nil {
return false, err
}
rows, err := repo.DeleteAuthMethod(ctx, id)
if err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return false, nil
}
return false, status.Errorf(codes.Internal, "Unable to delete auth method: %v.", err)
}
return rows > 0, nil
}
func toProto(in *password.AuthMethod) (*pb.AuthMethod, error) {
out := pb.AuthMethod{
Id: in.GetPublicId(),
CreatedTime: in.GetCreateTime().GetTimestamp(),
UpdatedTime: in.GetUpdateTime().GetTimestamp(),
Type: "password",
}
if in.GetDescription() != "" {
out.Description = &wrapperspb.StringValue{Value: in.GetDescription()}
}
if in.GetName() != "" {
out.Name = &wrapperspb.StringValue{Value: in.GetName()}
}
st, err := handlers.ProtoToStruct(&pb.PasswordAuthMethodAttributes{
MinUserNameLength: in.GetMinUserNameLength(),
MinPasswordLength: in.GetMinPasswordLength(),
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed building password attribute struct: %v", err)
}
out.Attributes = st
return &out, nil
}
// 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.GetAuthMethodRequest) error {
badFields := map[string]string{}
if !validId(req.GetId(), password.AuthMethodPrefix+"_") {
badFields["id"] = "Invalid formatted id."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
}
return nil
}
func validateListRequest(req *pbs.ListAuthMethodsRequest) error {
badFields := map[string]string{}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
}
return nil
}
func validateCreateRequest(req *pbs.CreateAuthMethodRequest) error {
badFields := map[string]string{}
item := req.GetItem()
if item.GetId() != "" {
badFields["id"] = "This is a read only field."
}
if item.GetCreatedTime() != nil {
badFields["created_time"] = "This is a read only field."
}
if item.GetUpdatedTime() != nil {
badFields["updated_time"] = "This is a read only field."
}
switch item.GetType() {
case "password":
pwAttrs := &pb.PasswordAuthMethodAttributes{}
if err := handlers.StructToProto(item.GetAttributes(), pwAttrs); err != nil {
badFields["attributes"] = "Attribute fields do not match the expected format."
}
default:
badFields["type"] = "This is a required field and must be \"password\"."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Argument errors found in the request.", badFields)
}
return nil
}
func validateUpdateRequest(req *pbs.UpdateAuthMethodRequest) error {
badFields := map[string]string{}
if !validId(req.GetId(), password.AuthMethodPrefix+"_") {
badFields["id"] = "Improperly formatted identifier."
}
if req.GetUpdateMask() == nil {
badFields["update_mask"] = "UpdateMask not provided but is required to update this resource."
}
item := req.GetItem()
if item == nil {
// It is legitimate for no item to be specified in an update request as it indicates all fields provided in
// the mask will be marked as unset.
return nil
}
if item.GetId() != "" {
badFields["id"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetCreatedTime() != nil {
badFields["created_time"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetUpdatedTime() != nil {
badFields["updated_time"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetType() != "" {
badFields["type"] = "This is a read only field and cannot be specified in an update request."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
}
return nil
}
func validateDeleteRequest(req *pbs.DeleteAuthMethodRequest) error {
badFields := map[string]string{}
if !validId(req.GetId(), password.AuthMethodPrefix+"_") {
badFields["id"] = "Incorrectly formatted identifier."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Errors in provided fields.", 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,709 @@
package authmethods_test
import (
"fmt"
"strings"
"testing"
"github.com/golang/protobuf/ptypes"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/watchtower/internal/auth"
"github.com/hashicorp/watchtower/internal/auth/password"
"github.com/hashicorp/watchtower/internal/db"
pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/auth"
"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/authmethods"
"github.com/hashicorp/watchtower/internal/types/scope"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/wrapperspb"
"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() (*password.Repository, error) {
return password.NewRepository(rw, rw, wrap)
}
o, _ := iam.TestScopes(t, conn)
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
wantU := &pb.AuthMethod{
Id: am.GetPublicId(),
CreatedTime: am.CreateTime.GetTimestamp(),
UpdatedTime: am.UpdateTime.GetTimestamp(),
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
Scope: &scopes.ScopeInfo{
Id: o.GetPublicId(),
Type: o.GetType(),
},
}
cases := []struct {
name string
scopeId string
req *pbs.GetAuthMethodRequest
res *pbs.GetAuthMethodResponse
errCode codes.Code
}{
{
name: "Get an Existing AuthMethod",
scopeId: o.GetPublicId(),
req: &pbs.GetAuthMethodRequest{Id: am.GetPublicId()},
res: &pbs.GetAuthMethodResponse{Item: wantU},
errCode: codes.OK,
},
{
name: "Get a non existant AuthMethod",
scopeId: o.GetPublicId(),
req: &pbs.GetAuthMethodRequest{Id: password.AuthMethodPrefix + "_DoesntExis"},
res: nil,
errCode: codes.NotFound,
},
{
name: "Wrong id prefix",
scopeId: o.GetPublicId(),
req: &pbs.GetAuthMethodRequest{Id: "j_1234567890"},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "space in id",
scopeId: o.GetPublicId(),
req: &pbs.GetAuthMethodRequest{Id: password.AuthMethodPrefix + "_1 23456789"},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
s, err := authmethods.NewService(repoFn)
require.NoError(err, "Couldn't create new auth_method service.")
got, gErr := s.GetAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "GetAuthMethod(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "GetAuthMethod(%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() (*password.Repository, error) {
return password.NewRepository(rw, rw, wrap)
}
oNoAuthMethods, _ := iam.TestScopes(t, conn)
oWithAuthMethods, _ := iam.TestScopes(t, conn)
oWithOtherAuthMethods, _ := iam.TestScopes(t, conn)
var wantSomeAuthMethods []*pb.AuthMethod
for _, am := range password.TestAuthMethods(t, conn, oWithAuthMethods.GetPublicId(), 3) {
wantSomeAuthMethods = append(wantSomeAuthMethods, &pb.AuthMethod{
Id: am.GetPublicId(),
CreatedTime: am.GetCreateTime().GetTimestamp(),
UpdatedTime: am.GetUpdateTime().GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: oWithAuthMethods.GetPublicId(), Type: scope.Org.String()},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
})
}
var wantOtherAuthMethods []*pb.AuthMethod
for _, aa := range password.TestAuthMethods(t, conn, oWithOtherAuthMethods.GetPublicId(), 3) {
wantOtherAuthMethods = append(wantOtherAuthMethods, &pb.AuthMethod{
Id: aa.GetPublicId(),
CreatedTime: aa.GetCreateTime().GetTimestamp(),
UpdatedTime: aa.GetUpdateTime().GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: oWithOtherAuthMethods.GetPublicId(), Type: scope.Org.String()},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
})
}
cases := []struct {
name string
scopeId string
res *pbs.ListAuthMethodsResponse
errCode codes.Code
}{
{
name: "List Some Auth Methods",
scopeId: oWithAuthMethods.GetPublicId(),
res: &pbs.ListAuthMethodsResponse{Items: wantSomeAuthMethods},
errCode: codes.OK,
},
{
name: "List Other Auth Methods",
scopeId: oWithOtherAuthMethods.GetPublicId(),
res: &pbs.ListAuthMethodsResponse{Items: wantOtherAuthMethods},
errCode: codes.OK,
},
{
name: "List No Auth Methods",
scopeId: oNoAuthMethods.GetPublicId(),
res: &pbs.ListAuthMethodsResponse{},
errCode: codes.OK,
},
// TODO: When an auth method doesn't exist, we should return a 404 instead of an empty list.
{
name: "Unfound Auth Method",
scopeId: password.AuthMethodPrefix + "_DoesntExis",
res: &pbs.ListAuthMethodsResponse{},
errCode: codes.OK,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
s, err := authmethods.NewService(repoFn)
require.NoError(err, "Couldn't create new auth_method service.")
got, gErr := s.ListAuthMethods(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), &pbs.ListAuthMethodsRequest{})
assert.Equal(tc.errCode, status.Code(gErr), "ListAuthMethods() for scope %q got error %v, wanted %v", tc.scopeId, gErr, tc.errCode)
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListAuthMethods() for scope %q got response %q, wanted %q", tc.scopeId, got, tc.res)
})
}
}
func TestDelete(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*password.Repository, error) {
return password.NewRepository(rw, rw, wrap)
}
o, _ := iam.TestScopes(t, conn)
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
s, err := authmethods.NewService(repoFn)
require.NoError(t, err, "Error when getting new auth_method service.")
cases := []struct {
name string
req *pbs.DeleteAuthMethodRequest
res *pbs.DeleteAuthMethodResponse
errCode codes.Code
}{
{
name: "Delete an Existing AuthMethod",
req: &pbs.DeleteAuthMethodRequest{
Id: am.GetPublicId(),
},
res: &pbs.DeleteAuthMethodResponse{
Existed: true,
},
errCode: codes.OK,
},
{
name: "Delete bad auth_method id",
req: &pbs.DeleteAuthMethodRequest{
Id: password.AuthMethodPrefix + "_doesntexis",
},
res: &pbs.DeleteAuthMethodResponse{
Existed: false,
},
errCode: codes.OK,
},
{
name: "Bad AuthMethod Id formatting",
req: &pbs.DeleteAuthMethodRequest{
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.DeleteAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "DeleteAuthMethod(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
assert.EqualValuesf(tc.res, got, "DeleteAuthMethod(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
func TestDelete_twice(t *testing.T) {
assert, require := assert.New(t), require.New(t)
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*password.Repository, error) {
return password.NewRepository(rw, rw, wrap)
}
o, _ := iam.TestScopes(t, conn)
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
s, err := authmethods.NewService(repoFn)
require.NoError(err, "Error when getting new auth_method service.")
req := &pbs.DeleteAuthMethodRequest{
Id: am.GetPublicId(),
}
got, gErr := s.DeleteAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), req)
assert.NoError(gErr, "First attempt")
assert.True(got.GetExisted(), "Expected existed to be true for the first delete.")
got, gErr = s.DeleteAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), req)
assert.NoError(gErr, "Second attempt")
assert.False(got.GetExisted(), "Expected existed to be false for the second delete.")
}
func TestCreate(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*password.Repository, error) {
return password.NewRepository(rw, rw, wrap)
}
o, _ := iam.TestScopes(t, conn)
defaultAm := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
defaultCreated, err := ptypes.Timestamp(defaultAm.GetCreateTime().GetTimestamp())
require.NoError(t, err, "Error converting proto to timestamp.")
cases := []struct {
name string
req *pbs.CreateAuthMethodRequest
res *pbs.CreateAuthMethodResponse
errCode codes.Code
}{
{
name: "Create a valid AuthMethod",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
}},
res: &pbs.CreateAuthMethodResponse{
Uri: fmt.Sprintf("scopes/%s/auth-methods/%s_", o.GetPublicId(), password.AuthMethodPrefix),
Item: &pb.AuthMethod{
Id: defaultAm.GetPublicId(),
CreatedTime: defaultAm.GetCreateTime().GetTimestamp(),
UpdatedTime: defaultAm.GetUpdateTime().GetTimestamp(),
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "desc"},
Scope: &scopes.ScopeInfo{Id: o.GetPublicId(), Type: scope.Org.String()},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
},
},
errCode: codes.OK,
},
{
name: "Can't specify Id",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
Id: password.AuthMethodPrefix + "_notallowed",
Type: "password",
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Can't specify Created Time",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
CreatedTime: ptypes.TimestampNow(),
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Can't specify Update Time",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
UpdatedTime: ptypes.TimestampNow(),
Type: "password",
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Can't specify Update Time",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
UpdatedTime: ptypes.TimestampNow(),
Type: "password",
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Must specify type",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "must specify type"},
Description: &wrapperspb.StringValue{Value: "must specify type"},
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Attributes must be valid for type",
req: &pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "Attributes must be valid for type"},
Description: &wrapperspb.StringValue{Value: "Attributes must be valid for type"},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"invalid_field": structpb.NewStringValue("invalid_value"),
"min_user_name_length": structpb.NewNumberValue(5),
}},
}},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
s, err := authmethods.NewService(repoFn)
require.NoError(err, "Error when getting new auth_method service.")
got, gErr := s.CreateAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "CreateAuthMethod(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
if tc.res == nil {
require.Nil(got)
}
if got != nil {
assert.Contains(got.GetUri(), tc.res.Uri)
assert.True(strings.HasPrefix(got.GetItem().GetId(), password.AuthMethodPrefix+"_"))
gotCreateTime, err := ptypes.Timestamp(got.GetItem().GetCreatedTime())
require.NoError(err, "Error converting proto to timestamp.")
gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime())
require.NoError(err, "Error converting proto to timestamp.")
// Verify it is a auth_method created after the test setup's default auth_method
assert.True(gotCreateTime.After(defaultCreated), "New auth_method should have been created after default auth_method. Was created %v, which is after %v", gotCreateTime, defaultCreated)
assert.True(gotUpdateTime.After(defaultCreated), "New auth_method should have been updated after default auth_method. Was updated %v, which is after %v", gotUpdateTime, defaultCreated)
// Clear all values which are hard to compare against.
got.Uri, tc.res.Uri = "", ""
got.Item.Id, tc.res.Item.Id = "", ""
got.Item.CreatedTime, got.Item.UpdatedTime, tc.res.Item.CreatedTime, tc.res.Item.UpdatedTime = nil, nil, nil, nil
}
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "CreateAuthMethod(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
func TestUpdate(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrap := db.TestWrapper(t)
repoFn := func() (*password.Repository, error) {
return password.NewRepository(rw, rw, wrap)
}
o, _ := iam.TestScopes(t, conn)
tested, err := authmethods.NewService(repoFn)
require.NoError(t, err, "Error when getting new auth_method service.")
freshAuthMethod := func() (*pb.AuthMethod, func()) {
am, err := tested.CreateAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())),
&pbs.CreateAuthMethodRequest{Item: &pb.AuthMethod{
Name: wrapperspb.String("default"),
Description: wrapperspb.String("default"),
Type: "password",
}})
require.NoError(t, err)
clean := func() {
_, err := tested.DeleteAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())),
&pbs.DeleteAuthMethodRequest{Id: am.GetItem().GetId()})
require.NoError(t, err)
}
return am.GetItem(), clean
}
cases := []struct {
name string
req *pbs.UpdateAuthMethodRequest
res *pbs.UpdateAuthMethodResponse
errCode codes.Code
}{
{
name: "Update an Existing AuthMethod",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name", "description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
},
},
errCode: codes.OK,
},
{
name: "Multiple Paths in single string",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name,description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
},
},
errCode: codes.OK,
},
{
name: "No Update Mask",
req: &pbs.UpdateAuthMethodRequest{
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Description: &wrapperspb.StringValue{Value: "updated desc"},
},
},
errCode: codes.InvalidArgument,
},
{
name: "No Paths in Mask",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{}},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Description: &wrapperspb.StringValue{Value: "updated desc"},
},
},
errCode: codes.InvalidArgument,
},
{
name: "Only non-existant paths in Mask",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{"nonexistant_field"}},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated name"},
Description: &wrapperspb.StringValue{Value: "updated desc"},
},
},
errCode: codes.InvalidArgument,
},
{
name: "Unset Name",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.AuthMethod{
Description: &wrapperspb.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
Description: &wrapperspb.StringValue{Value: "default"},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
},
},
errCode: codes.OK,
},
{
name: "Update Only Name",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated"},
Description: &wrapperspb.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "updated"},
Description: &wrapperspb.StringValue{Value: "default"},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
},
},
errCode: codes.OK,
},
{
name: "Update Only Description",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "ignored"},
Description: &wrapperspb.StringValue{Value: "notignored"},
},
},
res: &pbs.UpdateAuthMethodResponse{
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "default"},
Description: &wrapperspb.StringValue{Value: "notignored"},
Type: "password",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"min_password_length": structpb.NewNumberValue(8),
"min_user_name_length": structpb.NewNumberValue(5),
}},
},
},
errCode: codes.OK,
},
// TODO: Updating a non existant auth_method should result in a NotFound exception but currently results in
// the repoFn returning an internal error.
{
name: "Update a Non Existing AuthMethod",
req: &pbs.UpdateAuthMethodRequest{
Id: password.AuthMethodPrefix + "_DoesntExis",
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.AuthMethod{
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "desc"},
},
},
errCode: codes.Internal,
},
{
name: "Cant change Id",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"id"},
},
Item: &pb.AuthMethod{
Id: password.AuthMethodPrefix + "_somethinge",
Name: &wrapperspb.StringValue{Value: "new"},
Description: &wrapperspb.StringValue{Value: "new desc"},
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Cant specify Created Time",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"created_time"},
},
Item: &pb.AuthMethod{
CreatedTime: ptypes.TimestampNow(),
},
},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Cant specify Updated Time",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"updated_time"},
},
Item: &pb.AuthMethod{
UpdatedTime: ptypes.TimestampNow(),
},
},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Cant specify Type",
req: &pbs.UpdateAuthMethodRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"type"},
},
Item: &pb.AuthMethod{
Type: "oidc",
},
},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
am, cleanup := freshAuthMethod()
defer cleanup()
if tc.req.GetId() == "" {
tc.req.Id = am.GetId()
}
if tc.res != nil && tc.res.Item != nil {
tc.res.Item.Id = am.GetId()
tc.res.Item.CreatedTime = am.GetCreatedTime()
}
got, gErr := tested.UpdateAuthMethod(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "UpdateAuthMethod(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
if tc.res == nil {
require.Nil(got)
}
if got != nil {
assert.NotNilf(tc.res, "Expected UpdateAuthMethod response to be nil, but was %v", got)
gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime())
require.NoError(err, "Error converting proto to timestamp")
created, err := ptypes.Timestamp(am.GetCreatedTime())
require.NoError(err, "Error converting proto to timestamp")
// Verify it is a auth_method updated after it was created
assert.True(gotUpdateTime.After(created), "Updated auth_method should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, created)
// Clear all values which are hard to compare against.
got.Item.UpdatedTime, tc.res.Item.UpdatedTime = nil, nil
}
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "UpdateAuthMethod(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
@@ -18,7 +18,7 @@ func StructToProto(fields *structpb.Struct, p proto.Message) error {
}
func ProtoToStruct(p proto.Message) (*structpb.Struct, error) {
js, err := protojson.Marshal(p)
js, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(p)
if err != nil {
return nil, err
}