Merge pull request #649 from rithujohn191/gRPC-endpoints

api: add gRPC endpoints for creating, updating and deleting passwords
This commit is contained in:
Eric Chiang 2016-11-01 14:20:31 -07:00 committed by GitHub
commit 90e613b328
5 changed files with 444 additions and 27 deletions

View File

@ -14,6 +14,13 @@ It has these top-level messages:
CreateClientResp CreateClientResp
DeleteClientReq DeleteClientReq
DeleteClientResp DeleteClientResp
Password
CreatePasswordReq
CreatePasswordResp
UpdatePasswordReq
UpdatePasswordResp
DeletePasswordReq
DeletePasswordResp
*/ */
package api package api
@ -109,12 +116,103 @@ func (m *DeleteClientResp) String() string { return proto.CompactText
func (*DeleteClientResp) ProtoMessage() {} func (*DeleteClientResp) ProtoMessage() {}
func (*DeleteClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (*DeleteClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
// Password is an email for password mapping managed by the storage.
type Password struct {
Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"`
// Currently we do not accept plain text passwords. Could be an option in the future.
Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"`
Username string `protobuf:"bytes,3,opt,name=username" json:"username,omitempty"`
UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId" json:"user_id,omitempty"`
}
func (m *Password) Reset() { *m = Password{} }
func (m *Password) String() string { return proto.CompactTextString(m) }
func (*Password) ProtoMessage() {}
func (*Password) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
// CreatePasswordReq is a request to make a password.
type CreatePasswordReq struct {
Password *Password `protobuf:"bytes,1,opt,name=password" json:"password,omitempty"`
}
func (m *CreatePasswordReq) Reset() { *m = CreatePasswordReq{} }
func (m *CreatePasswordReq) String() string { return proto.CompactTextString(m) }
func (*CreatePasswordReq) ProtoMessage() {}
func (*CreatePasswordReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *CreatePasswordReq) GetPassword() *Password {
if m != nil {
return m.Password
}
return nil
}
// CreatePasswordResp returns the response from creating a password.
type CreatePasswordResp struct {
AlreadyExists bool `protobuf:"varint,1,opt,name=already_exists,json=alreadyExists" json:"already_exists,omitempty"`
}
func (m *CreatePasswordResp) Reset() { *m = CreatePasswordResp{} }
func (m *CreatePasswordResp) String() string { return proto.CompactTextString(m) }
func (*CreatePasswordResp) ProtoMessage() {}
func (*CreatePasswordResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
// UpdatePasswordReq is a request to modify an existing password.
type UpdatePasswordReq struct {
// The email used to lookup the password. This field cannot be modified
Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"`
NewHash []byte `protobuf:"bytes,2,opt,name=new_hash,json=newHash,proto3" json:"new_hash,omitempty"`
NewUsername string `protobuf:"bytes,3,opt,name=new_username,json=newUsername" json:"new_username,omitempty"`
}
func (m *UpdatePasswordReq) Reset() { *m = UpdatePasswordReq{} }
func (m *UpdatePasswordReq) String() string { return proto.CompactTextString(m) }
func (*UpdatePasswordReq) ProtoMessage() {}
func (*UpdatePasswordReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
// UpdatePasswordResp returns the response from modifying an existing password.
type UpdatePasswordResp struct {
NotFound bool `protobuf:"varint,1,opt,name=not_found,json=notFound" json:"not_found,omitempty"`
}
func (m *UpdatePasswordResp) Reset() { *m = UpdatePasswordResp{} }
func (m *UpdatePasswordResp) String() string { return proto.CompactTextString(m) }
func (*UpdatePasswordResp) ProtoMessage() {}
func (*UpdatePasswordResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
// DeletePasswordReq is a request to delete a password.
type DeletePasswordReq struct {
Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"`
}
func (m *DeletePasswordReq) Reset() { *m = DeletePasswordReq{} }
func (m *DeletePasswordReq) String() string { return proto.CompactTextString(m) }
func (*DeletePasswordReq) ProtoMessage() {}
func (*DeletePasswordReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
// DeletePasswordResp returns the response from deleting a password.
type DeletePasswordResp struct {
NotFound bool `protobuf:"varint,1,opt,name=not_found,json=notFound" json:"not_found,omitempty"`
}
func (m *DeletePasswordResp) Reset() { *m = DeletePasswordResp{} }
func (m *DeletePasswordResp) String() string { return proto.CompactTextString(m) }
func (*DeletePasswordResp) ProtoMessage() {}
func (*DeletePasswordResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
func init() { func init() {
proto.RegisterType((*Client)(nil), "api.Client") proto.RegisterType((*Client)(nil), "api.Client")
proto.RegisterType((*CreateClientReq)(nil), "api.CreateClientReq") proto.RegisterType((*CreateClientReq)(nil), "api.CreateClientReq")
proto.RegisterType((*CreateClientResp)(nil), "api.CreateClientResp") proto.RegisterType((*CreateClientResp)(nil), "api.CreateClientResp")
proto.RegisterType((*DeleteClientReq)(nil), "api.DeleteClientReq") proto.RegisterType((*DeleteClientReq)(nil), "api.DeleteClientReq")
proto.RegisterType((*DeleteClientResp)(nil), "api.DeleteClientResp") proto.RegisterType((*DeleteClientResp)(nil), "api.DeleteClientResp")
proto.RegisterType((*Password)(nil), "api.Password")
proto.RegisterType((*CreatePasswordReq)(nil), "api.CreatePasswordReq")
proto.RegisterType((*CreatePasswordResp)(nil), "api.CreatePasswordResp")
proto.RegisterType((*UpdatePasswordReq)(nil), "api.UpdatePasswordReq")
proto.RegisterType((*UpdatePasswordResp)(nil), "api.UpdatePasswordResp")
proto.RegisterType((*DeletePasswordReq)(nil), "api.DeletePasswordReq")
proto.RegisterType((*DeletePasswordResp)(nil), "api.DeletePasswordResp")
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -132,6 +230,12 @@ type DexClient interface {
CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error) CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error)
// DeleteClient attempts to delete the provided client. // DeleteClient attempts to delete the provided client.
DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error) DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error)
// CreatePassword attempts to create the password.
CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error)
// UpdatePassword attempts to modify existing password.
UpdatePassword(ctx context.Context, in *UpdatePasswordReq, opts ...grpc.CallOption) (*UpdatePasswordResp, error)
// DeletePassword attempts to delete the password.
DeletePassword(ctx context.Context, in *DeletePasswordReq, opts ...grpc.CallOption) (*DeletePasswordResp, error)
} }
type dexClient struct { type dexClient struct {
@ -160,6 +264,33 @@ func (c *dexClient) DeleteClient(ctx context.Context, in *DeleteClientReq, opts
return out, nil return out, nil
} }
func (c *dexClient) CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error) {
out := new(CreatePasswordResp)
err := grpc.Invoke(ctx, "/api.Dex/CreatePassword", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) UpdatePassword(ctx context.Context, in *UpdatePasswordReq, opts ...grpc.CallOption) (*UpdatePasswordResp, error) {
out := new(UpdatePasswordResp)
err := grpc.Invoke(ctx, "/api.Dex/UpdatePassword", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) DeletePassword(ctx context.Context, in *DeletePasswordReq, opts ...grpc.CallOption) (*DeletePasswordResp, error) {
out := new(DeletePasswordResp)
err := grpc.Invoke(ctx, "/api.Dex/DeletePassword", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Dex service // Server API for Dex service
type DexServer interface { type DexServer interface {
@ -167,6 +298,12 @@ type DexServer interface {
CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error) CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error)
// DeleteClient attempts to delete the provided client. // DeleteClient attempts to delete the provided client.
DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error) DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error)
// CreatePassword attempts to create the password.
CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error)
// UpdatePassword attempts to modify existing password.
UpdatePassword(context.Context, *UpdatePasswordReq) (*UpdatePasswordResp, error)
// DeletePassword attempts to delete the password.
DeletePassword(context.Context, *DeletePasswordReq) (*DeletePasswordResp, error)
} }
func RegisterDexServer(s *grpc.Server, srv DexServer) { func RegisterDexServer(s *grpc.Server, srv DexServer) {
@ -209,6 +346,60 @@ func _Dex_DeleteClient_Handler(srv interface{}, ctx context.Context, dec func(in
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Dex_CreatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreatePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).CreatePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/CreatePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).CreatePassword(ctx, req.(*CreatePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_UpdatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdatePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).UpdatePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/UpdatePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).UpdatePassword(ctx, req.(*UpdatePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_DeletePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeletePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).DeletePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/DeletePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).DeletePassword(ctx, req.(*DeletePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
var _Dex_serviceDesc = grpc.ServiceDesc{ var _Dex_serviceDesc = grpc.ServiceDesc{
ServiceName: "api.Dex", ServiceName: "api.Dex",
HandlerType: (*DexServer)(nil), HandlerType: (*DexServer)(nil),
@ -221,6 +412,18 @@ var _Dex_serviceDesc = grpc.ServiceDesc{
MethodName: "DeleteClient", MethodName: "DeleteClient",
Handler: _Dex_DeleteClient_Handler, Handler: _Dex_DeleteClient_Handler,
}, },
{
MethodName: "CreatePassword",
Handler: _Dex_CreatePassword_Handler,
},
{
MethodName: "UpdatePassword",
Handler: _Dex_UpdatePassword_Handler,
},
{
MethodName: "DeletePassword",
Handler: _Dex_DeletePassword_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: fileDescriptor0, Metadata: fileDescriptor0,
@ -229,27 +432,38 @@ var _Dex_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("api/api.proto", fileDescriptor0) } func init() { proto.RegisterFile("api/api.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 337 bytes of a gzipped FileDescriptorProto // 527 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x92, 0x4f, 0x6b, 0xe3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x54, 0xcb, 0x6e, 0xdb, 0x30,
0x10, 0xc5, 0x63, 0x3b, 0xeb, 0x38, 0x93, 0xbf, 0x88, 0xdd, 0xc5, 0xbb, 0xbd, 0xa4, 0x0e, 0x85, 0x10, 0x8c, 0x1f, 0xb1, 0xe5, 0xf5, 0x23, 0x31, 0x91, 0x26, 0x8a, 0x7b, 0x71, 0x18, 0x14, 0x70,
0x9c, 0x12, 0x48, 0xa1, 0xb7, 0x9e, 0x92, 0xf6, 0x5c, 0x0c, 0xb9, 0xd6, 0x28, 0xf6, 0xb4, 0x08, 0x2e, 0x09, 0x9a, 0x02, 0xbd, 0x14, 0xed, 0xc5, 0x69, 0xd1, 0xde, 0x02, 0x01, 0xbe, 0x56, 0x60,
0x54, 0x4b, 0x95, 0x64, 0x48, 0xcf, 0xfd, 0x64, 0xfd, 0x66, 0x45, 0x8a, 0x0a, 0x4e, 0x68, 0x6f, 0xcc, 0x6d, 0x42, 0x40, 0x91, 0x58, 0x92, 0x82, 0xd3, 0xcf, 0xeb, 0x2f, 0xf4, 0x8b, 0x0a, 0x52,
0x7e, 0x3f, 0xcd, 0xcc, 0x7b, 0x33, 0x18, 0x46, 0x54, 0xb2, 0x15, 0x95, 0x6c, 0x29, 0x95, 0x30, 0xb4, 0x21, 0xc9, 0x2e, 0xdc, 0x9b, 0x66, 0xb8, 0x9c, 0xe5, 0xcc, 0x2e, 0x04, 0x43, 0x26, 0xc5,
0x82, 0x44, 0x54, 0xb2, 0xec, 0x23, 0x80, 0x78, 0xc3, 0x19, 0xd6, 0x86, 0x8c, 0x21, 0x64, 0x55, 0x0d, 0x93, 0xe2, 0x5a, 0xaa, 0xcc, 0x64, 0xa4, 0xc5, 0xa4, 0xa0, 0xbf, 0x1b, 0xd0, 0x99, 0x27,
0x1a, 0xcc, 0x82, 0x45, 0x3f, 0x0f, 0x59, 0x45, 0xfe, 0x42, 0xac, 0xb1, 0x54, 0x68, 0xd2, 0xd0, 0x02, 0x53, 0x43, 0x46, 0xd0, 0x14, 0x3c, 0x6c, 0x4c, 0x1b, 0xb3, 0x5e, 0xd4, 0x14, 0x9c, 0x9c,
0x31, 0xaf, 0xc8, 0x1c, 0x46, 0x0a, 0x2b, 0xa6, 0xb0, 0x34, 0x45, 0xa3, 0x98, 0x4e, 0xa3, 0x59, 0x42, 0x47, 0xe3, 0x52, 0xa1, 0x09, 0x9b, 0x8e, 0xf3, 0x88, 0x5c, 0xc2, 0x50, 0x21, 0x17, 0x0a,
0xb4, 0xe8, 0xe7, 0xc3, 0x2f, 0xb8, 0x53, 0x4c, 0xdb, 0x22, 0xa3, 0x1a, 0x6d, 0xb0, 0x2a, 0x24, 0x97, 0x26, 0xce, 0x95, 0xd0, 0x61, 0x6b, 0xda, 0x9a, 0xf5, 0xa2, 0xc1, 0x9a, 0x5c, 0x28, 0xa1,
0xa2, 0xd2, 0x69, 0xf7, 0x58, 0xe4, 0xe1, 0x83, 0x65, 0xd6, 0x41, 0x36, 0x7b, 0xce, 0xca, 0xf4, 0x6d, 0x91, 0x51, 0xb9, 0x36, 0xc8, 0x63, 0x89, 0xa8, 0x74, 0xd8, 0x2e, 0x8a, 0x3c, 0x79, 0x6f,
0xd7, 0x2c, 0x58, 0x24, 0xb9, 0x57, 0x84, 0x40, 0xb7, 0xa6, 0x2f, 0x98, 0xc6, 0xce, 0xd7, 0x7d, 0x39, 0xdb, 0x41, 0xe6, 0x0f, 0x89, 0x58, 0x86, 0x87, 0xd3, 0xc6, 0x2c, 0x88, 0x3c, 0x22, 0x04,
0x93, 0x7f, 0x90, 0x70, 0xf1, 0x2c, 0x8a, 0x46, 0xf1, 0xb4, 0xe7, 0x78, 0xcf, 0xea, 0x9d, 0xe2, 0xda, 0x29, 0x7b, 0xc6, 0xb0, 0xe3, 0xfa, 0xba, 0x6f, 0x72, 0x0e, 0x41, 0x92, 0x3d, 0x66, 0x71,
0xd9, 0x0d, 0x4c, 0x36, 0x0a, 0xa9, 0xc1, 0xe3, 0x22, 0x39, 0xbe, 0x92, 0x39, 0xc4, 0xa5, 0x13, 0xae, 0x92, 0xb0, 0xeb, 0xf8, 0xae, 0xc5, 0x0b, 0x95, 0xd0, 0xf7, 0x70, 0x34, 0x57, 0xc8, 0x0c,
0x6e, 0x9f, 0xc1, 0x7a, 0xb0, 0xb4, 0x7b, 0xfb, 0x77, 0xff, 0x94, 0x3d, 0xc2, 0xf4, 0xb4, 0x4f, 0x16, 0x46, 0x22, 0xfc, 0x49, 0x2e, 0xa1, 0xb3, 0x74, 0xc0, 0xf9, 0xe9, 0xdf, 0xf6, 0xaf, 0xad,
0x4b, 0x72, 0x05, 0x63, 0xca, 0x15, 0xd2, 0xea, 0xad, 0xc0, 0x03, 0xd3, 0x46, 0xbb, 0x01, 0x49, 0x6f, 0x7f, 0xee, 0x8f, 0xe8, 0x77, 0x38, 0xae, 0xde, 0xd3, 0x92, 0xbc, 0x81, 0x11, 0x4b, 0x14,
0x3e, 0xf2, 0xf4, 0xce, 0xc1, 0xd6, 0xfc, 0xf0, 0xe7, 0xf9, 0x97, 0x30, 0xd9, 0x22, 0xc7, 0x76, 0x32, 0xfe, 0x2b, 0xc6, 0x17, 0xa1, 0x8d, 0x76, 0x02, 0x41, 0x34, 0xf4, 0xec, 0x67, 0x47, 0x96,
0xae, 0xb3, 0x1b, 0x67, 0x2b, 0x98, 0x9e, 0x96, 0x68, 0x49, 0x2e, 0xa0, 0x5f, 0x0b, 0x53, 0x3c, 0xf4, 0x9b, 0xff, 0xd6, 0xbf, 0x80, 0xa3, 0x3b, 0x4c, 0xb0, 0xfc, 0xae, 0x5a, 0xc6, 0xf4, 0x06,
0x89, 0xa6, 0xae, 0xbc, 0x7b, 0x52, 0x0b, 0x73, 0x6f, 0xf5, 0xfa, 0x3d, 0x80, 0x68, 0x8b, 0x07, 0x8e, 0xab, 0x25, 0x5a, 0x92, 0xd7, 0xd0, 0x4b, 0x33, 0x13, 0xff, 0xc8, 0xf2, 0x94, 0xfb, 0xee,
0x72, 0x0b, 0xc3, 0x76, 0x76, 0xf2, 0xfb, 0x18, 0xe0, 0xf4, 0x0c, 0xff, 0xff, 0x7c, 0x43, 0xb5, 0x41, 0x9a, 0x99, 0x2f, 0x16, 0x53, 0x01, 0xc1, 0x3d, 0xd3, 0x7a, 0x95, 0x29, 0x4e, 0x4e, 0xe0,
0xcc, 0x3a, 0xb6, 0xbd, 0xed, 0xeb, 0xdb, 0xcf, 0xd2, 0xfa, 0xf6, 0xf3, 0x80, 0x59, 0x67, 0x1f, 0x10, 0x9f, 0x99, 0x48, 0xbc, 0x5e, 0x01, 0x6c, 0x78, 0x4f, 0x4c, 0x3f, 0xb9, 0x87, 0x0d, 0x22,
0xbb, 0x3f, 0xe8, 0xfa, 0x33, 0x00, 0x00, 0xff, 0xff, 0xd1, 0x13, 0xbd, 0x1b, 0x52, 0x02, 0x00, 0xf7, 0x4d, 0x26, 0x10, 0xe4, 0x1a, 0x95, 0x0b, 0xb5, 0xe5, 0x8a, 0x37, 0x98, 0x9c, 0x41, 0xd7,
0x00, 0x7e, 0xc7, 0x82, 0x87, 0xed, 0x62, 0xce, 0x16, 0x7e, 0xe3, 0xf4, 0x13, 0x8c, 0x8b, 0x78, 0xd6,
0x0d, 0xad, 0x81, 0x2b, 0x08, 0xa4, 0x87, 0x3e, 0xda, 0xa1, 0xb3, 0xbe, 0xa9, 0xd9, 0x1c, 0xd3,
0x0f, 0x40, 0xea, 0xf7, 0xff, 0x3b, 0x60, 0xfa, 0x08, 0xe3, 0x85, 0xe4, 0xb5, 0xe6, 0xbb, 0x0d,
0x9f, 0x43, 0x90, 0xe2, 0x2a, 0x2e, 0x99, 0xee, 0xa6, 0xb8, 0xfa, 0x6a, 0x7d, 0x5f, 0xc0, 0xc0,
0x1e, 0xd5, 0xbc, 0xf7, 0x53, 0x5c, 0x2d, 0x3c, 0x45, 0xdf, 0x02, 0xa9, 0x37, 0xda, 0x37, 0x83,
0x2b, 0x18, 0x17, 0x43, 0xdb, 0xfb, 0x36, 0xab, 0x5e, 0x2f, 0xdd, 0xa3, 0x7e, 0xfb, 0xa7, 0x09,
0xad, 0x3b, 0x7c, 0x21, 0x1f, 0x61, 0x50, 0xde, 0x4e, 0x72, 0x52, 0xac, 0x58, 0x75, 0xd1, 0x27,
0xaf, 0x76, 0xb0, 0x5a, 0xd2, 0x03, 0x7b, 0xbd, 0xbc, 0x59, 0xfe, 0x7a, 0x6d, 0x1f, 0xfd, 0xf5,
0xfa, 0x0a, 0xd2, 0x03, 0x32, 0x87, 0x51, 0x75, 0x78, 0xe4, 0xb4, 0xd4, 0xa9, 0x64, 0x7c, 0x72,
0xb6, 0x93, 0x5f, 0x8b, 0x54, 0xb3, 0xf5, 0x22, 0x5b, 0x93, 0xf5, 0x22, 0xdb, 0x83, 0x28, 0x44,
0xaa, 0x11, 0x7a, 0x91, 0xad, 0x11, 0x78, 0x91, 0xed, 0xbc, 0xe9, 0xc1, 0x43, 0xc7, 0xfd, 0xf2,
0xde, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x63, 0xfb, 0xcd, 0x93, 0x03, 0x05, 0x00, 0x00,
} }

View File

@ -37,10 +37,59 @@ message DeleteClientResp {
// TODO(ericchiang): expand this. // TODO(ericchiang): expand this.
// Password is an email for password mapping managed by the storage.
message Password {
string email = 1;
// Currently we do not accept plain text passwords. Could be an option in the future.
bytes hash = 2;
string username = 3;
string user_id = 4;
}
// CreatePasswordReq is a request to make a password.
message CreatePasswordReq {
Password password = 1;
}
// CreatePasswordResp returns the response from creating a password.
message CreatePasswordResp {
bool already_exists = 1;
}
// UpdatePasswordReq is a request to modify an existing password.
message UpdatePasswordReq {
// The email used to lookup the password. This field cannot be modified
string email = 1;
bytes new_hash = 2;
string new_username = 3;
}
// UpdatePasswordResp returns the response from modifying an existing password.
message UpdatePasswordResp {
bool not_found = 1;
}
// DeletePasswordReq is a request to delete a password.
message DeletePasswordReq {
string email = 1;
}
// DeletePasswordResp returns the response from deleting a password.
message DeletePasswordResp {
bool not_found = 1;
}
// Dex represents the dex gRPC service. // Dex represents the dex gRPC service.
service Dex { service Dex {
// CreateClient attempts to create the client. // CreateClient attempts to create the client.
rpc CreateClient(CreateClientReq) returns (CreateClientResp) {}; rpc CreateClient(CreateClientReq) returns (CreateClientResp) {};
// DeleteClient attempts to delete the provided client. // DeleteClient attempts to delete the provided client.
rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {}; rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
// CreatePassword attempts to create the password.
rpc CreatePassword(CreatePasswordReq) returns (CreatePasswordResp) {};
// UpdatePassword attempts to modify existing password.
rpc UpdatePassword(UpdatePasswordReq) returns (UpdatePasswordResp) {};
// DeletePassword attempts to delete the password.
rpc DeletePassword(DeletePasswordReq) returns (DeletePasswordResp) {};
} }

View File

@ -2,8 +2,10 @@ package server
import ( import (
"errors" "errors"
"fmt"
"log" "log"
"golang.org/x/crypto/bcrypt"
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/coreos/dex/api" "github.com/coreos/dex/api"
@ -43,7 +45,7 @@ func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*ap
if err := d.s.CreateClient(c); err != nil { if err := d.s.CreateClient(c); err != nil {
log.Printf("api: failed to create client: %v", err) log.Printf("api: failed to create client: %v", err)
// TODO(ericchiang): Surface "already exists" errors. // TODO(ericchiang): Surface "already exists" errors.
return nil, err return nil, fmt.Errorf("create client: %v", err)
} }
return &api.CreateClientResp{ return &api.CreateClientResp{
@ -58,7 +60,102 @@ func (d dexAPI) DeleteClient(ctx context.Context, req *api.DeleteClientReq) (*ap
return &api.DeleteClientResp{NotFound: true}, nil return &api.DeleteClientResp{NotFound: true}, nil
} }
log.Printf("api: failed to delete client: %v", err) log.Printf("api: failed to delete client: %v", err)
return nil, err return nil, fmt.Errorf("delete client: %v", err)
} }
return &api.DeleteClientResp{}, nil return &api.DeleteClientResp{}, nil
} }
// checkCost returns an error if the hash provided does not meet minimum cost requirement
func checkCost(hash []byte) error {
actual, err := bcrypt.Cost(hash)
if err != nil {
return fmt.Errorf("parsing bcrypt hash: %v", err)
}
if actual < bcrypt.DefaultCost {
return fmt.Errorf("given hash cost = %d, does not meet minimum cost requirement = %d", actual, bcrypt.DefaultCost)
}
return nil
}
func (d dexAPI) CreatePassword(ctx context.Context, req *api.CreatePasswordReq) (*api.CreatePasswordResp, error) {
if req.Password == nil {
return nil, errors.New("no password supplied")
}
if req.Password.UserId == "" {
return nil, errors.New("no user ID supplied")
}
if req.Password.Hash != nil {
if err := checkCost(req.Password.Hash); err != nil {
return nil, err
}
} else {
return nil, errors.New("no hash of password supplied")
}
p := storage.Password{
Email: req.Password.Email,
Hash: req.Password.Hash,
Username: req.Password.Username,
UserID: req.Password.UserId,
}
if err := d.s.CreatePassword(p); err != nil {
log.Printf("api: failed to create password: %v", err)
return nil, fmt.Errorf("create password: %v", err)
}
return &api.CreatePasswordResp{}, nil
}
func (d dexAPI) UpdatePassword(ctx context.Context, req *api.UpdatePasswordReq) (*api.UpdatePasswordResp, error) {
if req.Email == "" {
return nil, errors.New("no email supplied")
}
if req.NewHash == nil && req.NewUsername == "" {
return nil, errors.New("nothing to update")
}
if req.NewHash != nil {
if err := checkCost(req.NewHash); err != nil {
return nil, err
}
}
updater := func(old storage.Password) (storage.Password, error) {
if req.NewHash != nil {
old.Hash = req.NewHash
}
if req.NewUsername != "" {
old.Username = req.NewUsername
}
return old, nil
}
if err := d.s.UpdatePassword(req.Email, updater); err != nil {
if err == storage.ErrNotFound {
return &api.UpdatePasswordResp{NotFound: true}, nil
}
log.Printf("api: failed to update password: %v", err)
return nil, fmt.Errorf("update password: %v", err)
}
return &api.UpdatePasswordResp{}, nil
}
func (d dexAPI) DeletePassword(ctx context.Context, req *api.DeletePasswordReq) (*api.DeletePasswordResp, error) {
if req.Email == "" {
return nil, errors.New("no email supplied")
}
err := d.s.DeletePassword(req.Email)
if err != nil {
if err == storage.ErrNotFound {
return &api.DeletePasswordResp{NotFound: true}, nil
}
log.Printf("api: failed to delete password: %v", err)
return nil, fmt.Errorf("delete password: %v", err)
}
return &api.DeletePasswordResp{}, nil
}

View File

@ -1 +1,59 @@
package server package server
import (
"context"
"testing"
"github.com/coreos/dex/api"
"github.com/coreos/dex/storage/memory"
)
// Attempts to create, update and delete a test Password
func TestPassword(t *testing.T) {
s := memory.New()
serv := NewAPI(s)
ctx := context.Background()
p := api.Password{
Email: "test@example.com",
// bcrypt hash of the value "test1" with cost 10
Hash: []byte("$2a$10$XVMN/Fid.Ks4CXgzo8fpR.iU1khOMsP5g9xQeXuBm1wXjRX8pjUtO"),
Username: "test",
UserId: "test123",
}
createReq := api.CreatePasswordReq{
Password: &p,
}
if _, err := serv.CreatePassword(ctx, &createReq); err != nil {
t.Fatalf("Unable to create password: %v", err)
}
updateReq := api.UpdatePasswordReq{
Email: "test@example.com",
NewUsername: "test1",
}
if _, err := serv.UpdatePassword(ctx, &updateReq); err != nil {
t.Fatalf("Unable to update password: %v", err)
}
pass, err := s.GetPassword(updateReq.Email)
if err != nil {
t.Fatalf("Unable to retrieve password: %v", err)
}
if pass.Username != updateReq.NewUsername {
t.Fatalf("UpdatePassword failed. Expected username %s retrieved %s", updateReq.NewUsername, pass.Username)
}
deleteReq := api.DeletePasswordReq{
Email: "test@example.com",
}
if _, err := serv.DeletePassword(ctx, &deleteReq); err != nil {
t.Fatalf("Unable to delete password: %v", err)
}
}

View File

@ -249,8 +249,7 @@ type Password struct {
// (cough cough, kubernetes), must map this value appropriately. // (cough cough, kubernetes), must map this value appropriately.
Email string `yaml:"email"` Email string `yaml:"email"`
// Bcrypt encoded hash of the password. This package recommends a cost value of at // Bcrypt encoded hash of the password. This package enforces a min cost value of 10
// least 14.
Hash []byte `yaml:"hash"` Hash []byte `yaml:"hash"`
// Optional username to display. NOT used during login. // Optional username to display. NOT used during login.