From c65ce31666032bf2781b35aae2d02fd92169c5fe Mon Sep 17 00:00:00 2001 From: ClydeDroid Date: Fri, 22 Sep 2017 10:36:52 -0400 Subject: [PATCH 1/9] Add API authentication mechanism --- cmd/soapboxd/main.go | 55 ++++++++++++- proto/activity.pb.go | 65 ++------------- proto/application.pb.go | 16 ++-- proto/configuration.pb.go | 73 ++++++++++++++--- proto/deployment.pb.go | 22 +++--- proto/environment.pb.go | 14 ++-- proto/soapbox.pb.go | 6 +- proto/user.pb.go | 79 +++++++++++-------- soapboxd/user.go | 24 ++++-- soapboxpb/user.proto | 1 + web/app/controllers/about_controller.rb | 2 +- web/app/controllers/application_controller.rb | 22 +++++- .../controllers/applications_controller.rb | 6 +- .../controllers/configurations_controller.rb | 6 +- web/app/controllers/dashboard_controller.rb | 10 +-- web/app/controllers/deployments_controller.rb | 10 +-- .../controllers/environments_controller.rb | 10 +-- web/app/controllers/users_controller.rb | 7 +- web/config/initializers/soapbox_api.rb | 24 +++--- web/lib/user_pb.rb | 1 + .../applications_controller_spec.rb | 2 +- 21 files changed, 272 insertions(+), 183 deletions(-) diff --git a/cmd/soapboxd/main.go b/cmd/soapboxd/main.go index 30fb417..883408e 100644 --- a/cmd/soapboxd/main.go +++ b/cmd/soapboxd/main.go @@ -1,6 +1,8 @@ package main import ( + "crypto/hmac" + "crypto/sha512" "database/sql" "flag" "fmt" @@ -18,6 +20,7 @@ import ( _ "github.com/lib/pq" "golang.org/x/net/context" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" ) func main() { @@ -49,8 +52,9 @@ func main() { } var opts []grpc.ServerOption + opts = append(opts, serverInterceptor(loginInterceptor)) if *logTiming { - opts = append(opts, serverInterceptor()) + opts = append(opts, serverInterceptor(timingInterceptor)) } server := grpc.NewServer(opts...) @@ -103,8 +107,8 @@ func getConfig() *soapbox.Config { return c } -func serverInterceptor() grpc.ServerOption { - return grpc.UnaryInterceptor(grpc.UnaryServerInterceptor(timingInterceptor)) +func serverInterceptor(interceptor grpc.UnaryServerInterceptor) grpc.ServerOption { + return grpc.UnaryInterceptor(interceptor) } func timingInterceptor( @@ -118,3 +122,48 @@ func timingInterceptor( log.Printf("method=%s duration=%s error=%v", info.FullMethod, time.Since(t0), err) return resp, err } + +func loginInterceptor( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, +) (interface{}, error) { + if err := authorize(ctx); err != nil { + return nil, err + } + + return handler(ctx, req) +} + +type accessDeniedErr struct { + userID []byte +} + +func (e *accessDeniedErr) Error() string { + return fmt.Sprintf("Incorrect login token for user %s", e.userID) +} + +type emptyMetadataErr struct{} + +func (e *emptyMetadataErr) Error() string { + return fmt.Sprint("No metadata attached with request") +} + +func authorize(ctx context.Context) error { + if md, ok := metadata.FromContext(ctx); ok { + userID := []byte(md["user_id"][0]) + sentToken := []byte(md["login_token"][0]) + key := []byte(os.Getenv("LOGIN_SECRET_KEY")) + h := hmac.New(sha512.New, key) + h.Write(userID) + calculated := h.Sum(nil) + if hmac.Equal(calculated, sentToken) { + return nil + } + + return &accessDeniedErr{userID} + } + + return &emptyMetadataErr{} +} diff --git a/proto/activity.pb.go b/proto/activity.pb.go index b3728c2..3a57295 100644 --- a/proto/activity.pb.go +++ b/proto/activity.pb.go @@ -1,55 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: activity.proto -/* -Package proto is a generated protocol buffer package. - -It is generated from these files: - activity.proto - application.proto - configuration.proto - deployment.proto - environment.proto - soapbox.proto - user.proto - version.proto - -It has these top-level messages: - ListActivitiesResponse - Activity - Application - ListApplicationRequest - ListApplicationResponse - GetApplicationRequest - ListConfigurationRequest - ListConfigurationResponse - GetLatestConfigurationRequest - Configuration - ConfigVar - CreateConfigurationRequest - DeleteConfigurationRequest - ListDeploymentRequest - ListDeploymentResponse - GetDeploymentRequest - GetLatestDeploymentRequest - Deployment - StartDeploymentResponse - GetDeploymentStatusRequest - GetDeploymentStatusResponse - TeardownDeploymentRequest - ListEnvironmentRequest - ListEnvironmentResponse - GetEnvironmentRequest - Environment - DestroyEnvironmentRequest - Empty - User - CreateUserRequest - GetUserRequest - LoginUserRequest - LoginUserResponse - GetVersionResponse -*/ package proto import proto1 "github.com/golang/protobuf/proto" @@ -67,12 +18,6 @@ var _ = proto1.Marshal var _ = fmt.Errorf var _ = math.Inf -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto1.ProtoPackageIsVersion2 // please upgrade the proto package - type ActivityType int32 const ( @@ -104,7 +49,7 @@ var ActivityType_value = map[string]int32{ func (x ActivityType) String() string { return proto1.EnumName(ActivityType_name, int32(x)) } -func (ActivityType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (ActivityType) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } type ListActivitiesResponse struct { Activities []*Activity `protobuf:"bytes,1,rep,name=activities" json:"activities,omitempty"` @@ -113,7 +58,7 @@ type ListActivitiesResponse struct { func (m *ListActivitiesResponse) Reset() { *m = ListActivitiesResponse{} } func (m *ListActivitiesResponse) String() string { return proto1.CompactTextString(m) } func (*ListActivitiesResponse) ProtoMessage() {} -func (*ListActivitiesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*ListActivitiesResponse) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } func (m *ListActivitiesResponse) GetActivities() []*Activity { if m != nil { @@ -135,7 +80,7 @@ type Activity struct { func (m *Activity) Reset() { *m = Activity{} } func (m *Activity) String() string { return proto1.CompactTextString(m) } func (*Activity) ProtoMessage() {} -func (*Activity) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (*Activity) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{1} } func (m *Activity) GetId() int32 { if m != nil { @@ -363,9 +308,9 @@ var _Activities_serviceDesc = grpc.ServiceDesc{ Metadata: "activity.proto", } -func init() { proto1.RegisterFile("activity.proto", fileDescriptor0) } +func init() { proto1.RegisterFile("activity.proto", fileDescriptor3) } -var fileDescriptor0 = []byte{ +var fileDescriptor3 = []byte{ // 490 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xdf, 0x6e, 0x12, 0x41, 0x14, 0xc6, 0xd9, 0xe5, 0x9f, 0x1e, 0xca, 0x86, 0x8e, 0x69, 0xbb, 0x25, 0xd1, 0x12, 0x8c, 0x09, diff --git a/proto/application.pb.go b/proto/application.pb.go index 9ddead9..9697d9c 100644 --- a/proto/application.pb.go +++ b/proto/application.pb.go @@ -37,7 +37,7 @@ var ApplicationType_value = map[string]int32{ func (x ApplicationType) String() string { return proto1.EnumName(ApplicationType_name, int32(x)) } -func (ApplicationType) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } +func (ApplicationType) EnumDescriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } type CreationState int32 @@ -61,7 +61,7 @@ var CreationState_value = map[string]int32{ func (x CreationState) String() string { return proto1.EnumName(CreationState_name, int32(x)) } -func (CreationState) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } +func (CreationState) EnumDescriptor() ([]byte, []int) { return fileDescriptor5, []int{1} } type Application struct { Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` @@ -82,7 +82,7 @@ type Application struct { func (m *Application) Reset() { *m = Application{} } func (m *Application) String() string { return proto1.CompactTextString(m) } func (*Application) ProtoMessage() {} -func (*Application) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } +func (*Application) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } func (m *Application) GetId() int32 { if m != nil { @@ -182,7 +182,7 @@ type ListApplicationRequest struct { func (m *ListApplicationRequest) Reset() { *m = ListApplicationRequest{} } func (m *ListApplicationRequest) String() string { return proto1.CompactTextString(m) } func (*ListApplicationRequest) ProtoMessage() {} -func (*ListApplicationRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } +func (*ListApplicationRequest) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{1} } func (m *ListApplicationRequest) GetUserId() int32 { if m != nil { @@ -198,7 +198,7 @@ type ListApplicationResponse struct { func (m *ListApplicationResponse) Reset() { *m = ListApplicationResponse{} } func (m *ListApplicationResponse) String() string { return proto1.CompactTextString(m) } func (*ListApplicationResponse) ProtoMessage() {} -func (*ListApplicationResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } +func (*ListApplicationResponse) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{2} } func (m *ListApplicationResponse) GetApplications() []*Application { if m != nil { @@ -214,7 +214,7 @@ type GetApplicationRequest struct { func (m *GetApplicationRequest) Reset() { *m = GetApplicationRequest{} } func (m *GetApplicationRequest) String() string { return proto1.CompactTextString(m) } func (*GetApplicationRequest) ProtoMessage() {} -func (*GetApplicationRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } +func (*GetApplicationRequest) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{3} } func (m *GetApplicationRequest) GetId() int32 { if m != nil { @@ -370,9 +370,9 @@ var _Applications_serviceDesc = grpc.ServiceDesc{ Metadata: "application.proto", } -func init() { proto1.RegisterFile("application.proto", fileDescriptor1) } +func init() { proto1.RegisterFile("application.proto", fileDescriptor5) } -var fileDescriptor1 = []byte{ +var fileDescriptor5 = []byte{ // 587 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0xcf, 0x4e, 0xdb, 0x40, 0x10, 0xc6, 0xe3, 0x00, 0x49, 0x33, 0xf9, 0x43, 0xd8, 0xb6, 0xb0, 0xca, 0x01, 0xdc, 0x1c, 0x4a, diff --git a/proto/configuration.pb.go b/proto/configuration.pb.go index 0780112..00ecebf 100644 --- a/proto/configuration.pb.go +++ b/proto/configuration.pb.go @@ -1,6 +1,55 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: configuration.proto +/* +Package proto is a generated protocol buffer package. + +It is generated from these files: + configuration.proto + environment.proto + user.proto + activity.proto + soapbox.proto + application.proto + deployment.proto + version.proto + +It has these top-level messages: + ListConfigurationRequest + ListConfigurationResponse + GetLatestConfigurationRequest + Configuration + ConfigVar + CreateConfigurationRequest + DeleteConfigurationRequest + ListEnvironmentRequest + ListEnvironmentResponse + GetEnvironmentRequest + Environment + DestroyEnvironmentRequest + User + CreateUserRequest + GetUserRequest + LoginUserRequest + LoginUserResponse + ListActivitiesResponse + Activity + Empty + Application + ListApplicationRequest + ListApplicationResponse + GetApplicationRequest + ListDeploymentRequest + ListDeploymentResponse + GetDeploymentRequest + GetLatestDeploymentRequest + Deployment + StartDeploymentResponse + GetDeploymentStatusRequest + GetDeploymentStatusResponse + TeardownDeploymentRequest + GetVersionResponse +*/ package proto import proto1 "github.com/golang/protobuf/proto" @@ -18,6 +67,12 @@ var _ = proto1.Marshal var _ = fmt.Errorf var _ = math.Inf +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto1.ProtoPackageIsVersion2 // please upgrade the proto package + type ListConfigurationRequest struct { EnvironmentId int32 `protobuf:"varint,1,opt,name=environment_id,json=environmentId" json:"environment_id,omitempty"` } @@ -25,7 +80,7 @@ type ListConfigurationRequest struct { func (m *ListConfigurationRequest) Reset() { *m = ListConfigurationRequest{} } func (m *ListConfigurationRequest) String() string { return proto1.CompactTextString(m) } func (*ListConfigurationRequest) ProtoMessage() {} -func (*ListConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } +func (*ListConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (m *ListConfigurationRequest) GetEnvironmentId() int32 { if m != nil { @@ -41,7 +96,7 @@ type ListConfigurationResponse struct { func (m *ListConfigurationResponse) Reset() { *m = ListConfigurationResponse{} } func (m *ListConfigurationResponse) String() string { return proto1.CompactTextString(m) } func (*ListConfigurationResponse) ProtoMessage() {} -func (*ListConfigurationResponse) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} } +func (*ListConfigurationResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } func (m *ListConfigurationResponse) GetConfigs() []*Configuration { if m != nil { @@ -57,7 +112,7 @@ type GetLatestConfigurationRequest struct { func (m *GetLatestConfigurationRequest) Reset() { *m = GetLatestConfigurationRequest{} } func (m *GetLatestConfigurationRequest) String() string { return proto1.CompactTextString(m) } func (*GetLatestConfigurationRequest) ProtoMessage() {} -func (*GetLatestConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{2} } +func (*GetLatestConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } func (m *GetLatestConfigurationRequest) GetEnvironmentId() int32 { if m != nil { @@ -76,7 +131,7 @@ type Configuration struct { func (m *Configuration) Reset() { *m = Configuration{} } func (m *Configuration) String() string { return proto1.CompactTextString(m) } func (*Configuration) ProtoMessage() {} -func (*Configuration) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{3} } +func (*Configuration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } func (m *Configuration) GetEnvironmentId() int32 { if m != nil { @@ -114,7 +169,7 @@ type ConfigVar struct { func (m *ConfigVar) Reset() { *m = ConfigVar{} } func (m *ConfigVar) String() string { return proto1.CompactTextString(m) } func (*ConfigVar) ProtoMessage() {} -func (*ConfigVar) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{4} } +func (*ConfigVar) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (m *ConfigVar) GetName() string { if m != nil { @@ -138,7 +193,7 @@ type CreateConfigurationRequest struct { func (m *CreateConfigurationRequest) Reset() { *m = CreateConfigurationRequest{} } func (m *CreateConfigurationRequest) String() string { return proto1.CompactTextString(m) } func (*CreateConfigurationRequest) ProtoMessage() {} -func (*CreateConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{5} } +func (*CreateConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (m *CreateConfigurationRequest) GetEnvironmentId() int32 { if m != nil { @@ -162,7 +217,7 @@ type DeleteConfigurationRequest struct { func (m *DeleteConfigurationRequest) Reset() { *m = DeleteConfigurationRequest{} } func (m *DeleteConfigurationRequest) String() string { return proto1.CompactTextString(m) } func (*DeleteConfigurationRequest) ProtoMessage() {} -func (*DeleteConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{6} } +func (*DeleteConfigurationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (m *DeleteConfigurationRequest) GetEnvironmentId() int32 { if m != nil { @@ -359,9 +414,9 @@ var _Configurations_serviceDesc = grpc.ServiceDesc{ Metadata: "configuration.proto", } -func init() { proto1.RegisterFile("configuration.proto", fileDescriptor2) } +func init() { proto1.RegisterFile("configuration.proto", fileDescriptor0) } -var fileDescriptor2 = []byte{ +var fileDescriptor0 = []byte{ // 416 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0x4d, 0x6b, 0xdb, 0x40, 0x10, 0xb5, 0x9c, 0xb8, 0x42, 0x63, 0xec, 0xc3, 0xb8, 0x04, 0x75, 0xa1, 0xd4, 0xdd, 0xd2, 0xe2, diff --git a/proto/deployment.pb.go b/proto/deployment.pb.go index 911c8e9..28b9d9b 100644 --- a/proto/deployment.pb.go +++ b/proto/deployment.pb.go @@ -25,7 +25,7 @@ type ListDeploymentRequest struct { func (m *ListDeploymentRequest) Reset() { *m = ListDeploymentRequest{} } func (m *ListDeploymentRequest) String() string { return proto1.CompactTextString(m) } func (*ListDeploymentRequest) ProtoMessage() {} -func (*ListDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } +func (*ListDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{0} } func (m *ListDeploymentRequest) GetApplicationId() int32 { if m != nil { @@ -41,7 +41,7 @@ type ListDeploymentResponse struct { func (m *ListDeploymentResponse) Reset() { *m = ListDeploymentResponse{} } func (m *ListDeploymentResponse) String() string { return proto1.CompactTextString(m) } func (*ListDeploymentResponse) ProtoMessage() {} -func (*ListDeploymentResponse) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{1} } +func (*ListDeploymentResponse) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{1} } func (m *ListDeploymentResponse) GetDeployments() []*Deployment { if m != nil { @@ -57,7 +57,7 @@ type GetDeploymentRequest struct { func (m *GetDeploymentRequest) Reset() { *m = GetDeploymentRequest{} } func (m *GetDeploymentRequest) String() string { return proto1.CompactTextString(m) } func (*GetDeploymentRequest) ProtoMessage() {} -func (*GetDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{2} } +func (*GetDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{2} } func (m *GetDeploymentRequest) GetId() int32 { if m != nil { @@ -74,7 +74,7 @@ type GetLatestDeploymentRequest struct { func (m *GetLatestDeploymentRequest) Reset() { *m = GetLatestDeploymentRequest{} } func (m *GetLatestDeploymentRequest) String() string { return proto1.CompactTextString(m) } func (*GetLatestDeploymentRequest) ProtoMessage() {} -func (*GetLatestDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{3} } +func (*GetLatestDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{3} } func (m *GetLatestDeploymentRequest) GetApplicationId() int32 { if m != nil { @@ -102,7 +102,7 @@ type Deployment struct { func (m *Deployment) Reset() { *m = Deployment{} } func (m *Deployment) String() string { return proto1.CompactTextString(m) } func (*Deployment) ProtoMessage() {} -func (*Deployment) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{4} } +func (*Deployment) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{4} } func (m *Deployment) GetId() int32 { if m != nil { @@ -153,7 +153,7 @@ type StartDeploymentResponse struct { func (m *StartDeploymentResponse) Reset() { *m = StartDeploymentResponse{} } func (m *StartDeploymentResponse) String() string { return proto1.CompactTextString(m) } func (*StartDeploymentResponse) ProtoMessage() {} -func (*StartDeploymentResponse) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{5} } +func (*StartDeploymentResponse) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{5} } func (m *StartDeploymentResponse) GetId() int32 { if m != nil { @@ -169,7 +169,7 @@ type GetDeploymentStatusRequest struct { func (m *GetDeploymentStatusRequest) Reset() { *m = GetDeploymentStatusRequest{} } func (m *GetDeploymentStatusRequest) String() string { return proto1.CompactTextString(m) } func (*GetDeploymentStatusRequest) ProtoMessage() {} -func (*GetDeploymentStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{6} } +func (*GetDeploymentStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{6} } func (m *GetDeploymentStatusRequest) GetId() int32 { if m != nil { @@ -185,7 +185,7 @@ type GetDeploymentStatusResponse struct { func (m *GetDeploymentStatusResponse) Reset() { *m = GetDeploymentStatusResponse{} } func (m *GetDeploymentStatusResponse) String() string { return proto1.CompactTextString(m) } func (*GetDeploymentStatusResponse) ProtoMessage() {} -func (*GetDeploymentStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{7} } +func (*GetDeploymentStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{7} } func (m *GetDeploymentStatusResponse) GetState() string { if m != nil { @@ -201,7 +201,7 @@ type TeardownDeploymentRequest struct { func (m *TeardownDeploymentRequest) Reset() { *m = TeardownDeploymentRequest{} } func (m *TeardownDeploymentRequest) String() string { return proto1.CompactTextString(m) } func (*TeardownDeploymentRequest) ProtoMessage() {} -func (*TeardownDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{8} } +func (*TeardownDeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{8} } func (m *TeardownDeploymentRequest) GetId() int32 { if m != nil { @@ -459,9 +459,9 @@ var _Deployments_serviceDesc = grpc.ServiceDesc{ Metadata: "deployment.proto", } -func init() { proto1.RegisterFile("deployment.proto", fileDescriptor3) } +func init() { proto1.RegisterFile("deployment.proto", fileDescriptor6) } -var fileDescriptor3 = []byte{ +var fileDescriptor6 = []byte{ // 500 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xdf, 0x6e, 0xd3, 0x30, 0x14, 0xc6, 0x9b, 0x96, 0x6e, 0xda, 0xa9, 0xda, 0xc1, 0x59, 0x81, 0x60, 0xc4, 0x56, 0x19, 0x98, diff --git a/proto/environment.pb.go b/proto/environment.pb.go index be8b51e..3dcf8ce 100644 --- a/proto/environment.pb.go +++ b/proto/environment.pb.go @@ -25,7 +25,7 @@ type ListEnvironmentRequest struct { func (m *ListEnvironmentRequest) Reset() { *m = ListEnvironmentRequest{} } func (m *ListEnvironmentRequest) String() string { return proto1.CompactTextString(m) } func (*ListEnvironmentRequest) ProtoMessage() {} -func (*ListEnvironmentRequest) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} } +func (*ListEnvironmentRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } func (m *ListEnvironmentRequest) GetApplicationId() int32 { if m != nil { @@ -41,7 +41,7 @@ type ListEnvironmentResponse struct { func (m *ListEnvironmentResponse) Reset() { *m = ListEnvironmentResponse{} } func (m *ListEnvironmentResponse) String() string { return proto1.CompactTextString(m) } func (*ListEnvironmentResponse) ProtoMessage() {} -func (*ListEnvironmentResponse) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{1} } +func (*ListEnvironmentResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } func (m *ListEnvironmentResponse) GetEnvironments() []*Environment { if m != nil { @@ -57,7 +57,7 @@ type GetEnvironmentRequest struct { func (m *GetEnvironmentRequest) Reset() { *m = GetEnvironmentRequest{} } func (m *GetEnvironmentRequest) String() string { return proto1.CompactTextString(m) } func (*GetEnvironmentRequest) ProtoMessage() {} -func (*GetEnvironmentRequest) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{2} } +func (*GetEnvironmentRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } func (m *GetEnvironmentRequest) GetId() int32 { if m != nil { @@ -77,7 +77,7 @@ type Environment struct { func (m *Environment) Reset() { *m = Environment{} } func (m *Environment) String() string { return proto1.CompactTextString(m) } func (*Environment) ProtoMessage() {} -func (*Environment) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{3} } +func (*Environment) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } func (m *Environment) GetId() int32 { if m != nil { @@ -121,7 +121,7 @@ type DestroyEnvironmentRequest struct { func (m *DestroyEnvironmentRequest) Reset() { *m = DestroyEnvironmentRequest{} } func (m *DestroyEnvironmentRequest) String() string { return proto1.CompactTextString(m) } func (*DestroyEnvironmentRequest) ProtoMessage() {} -func (*DestroyEnvironmentRequest) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{4} } +func (*DestroyEnvironmentRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} } func (m *DestroyEnvironmentRequest) GetId() int32 { if m != nil { @@ -309,9 +309,9 @@ var _Environments_serviceDesc = grpc.ServiceDesc{ Metadata: "environment.proto", } -func init() { proto1.RegisterFile("environment.proto", fileDescriptor4) } +func init() { proto1.RegisterFile("environment.proto", fileDescriptor1) } -var fileDescriptor4 = []byte{ +var fileDescriptor1 = []byte{ // 376 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xcb, 0x6a, 0xfa, 0x40, 0x14, 0xc6, 0x4d, 0xbc, 0xe1, 0x51, 0xc3, 0xdf, 0xf9, 0xf7, 0x92, 0x66, 0x51, 0xc3, 0x40, 0x69, diff --git a/proto/soapbox.pb.go b/proto/soapbox.pb.go index 68cb51e..3fab1ac 100644 --- a/proto/soapbox.pb.go +++ b/proto/soapbox.pb.go @@ -18,15 +18,15 @@ type Empty struct { func (m *Empty) Reset() { *m = Empty{} } func (m *Empty) String() string { return proto1.CompactTextString(m) } func (*Empty) ProtoMessage() {} -func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } +func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} } func init() { proto1.RegisterType((*Empty)(nil), "soapbox.Empty") } -func init() { proto1.RegisterFile("soapbox.proto", fileDescriptor5) } +func init() { proto1.RegisterFile("soapbox.proto", fileDescriptor4) } -var fileDescriptor5 = []byte{ +var fileDescriptor4 = []byte{ // 62 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0xce, 0x4f, 0x2c, 0x48, 0xca, 0xaf, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0x95, 0xd8, 0xb9, diff --git a/proto/user.pb.go b/proto/user.pb.go index 13ef6e8..a7d4c18 100644 --- a/proto/user.pb.go +++ b/proto/user.pb.go @@ -30,7 +30,7 @@ type User struct { func (m *User) Reset() { *m = User{} } func (m *User) String() string { return proto1.CompactTextString(m) } func (*User) ProtoMessage() {} -func (*User) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{0} } +func (*User) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } func (m *User) GetId() int32 { if m != nil { @@ -84,7 +84,7 @@ type CreateUserRequest struct { func (m *CreateUserRequest) Reset() { *m = CreateUserRequest{} } func (m *CreateUserRequest) String() string { return proto1.CompactTextString(m) } func (*CreateUserRequest) ProtoMessage() {} -func (*CreateUserRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{1} } +func (*CreateUserRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} } func (m *CreateUserRequest) GetId() int32 { if m != nil { @@ -122,7 +122,7 @@ type GetUserRequest struct { func (m *GetUserRequest) Reset() { *m = GetUserRequest{} } func (m *GetUserRequest) String() string { return proto1.CompactTextString(m) } func (*GetUserRequest) ProtoMessage() {} -func (*GetUserRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{2} } +func (*GetUserRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{2} } func (m *GetUserRequest) GetEmail() string { if m != nil { @@ -146,7 +146,7 @@ type LoginUserRequest struct { func (m *LoginUserRequest) Reset() { *m = LoginUserRequest{} } func (m *LoginUserRequest) String() string { return proto1.CompactTextString(m) } func (*LoginUserRequest) ProtoMessage() {} -func (*LoginUserRequest) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{3} } +func (*LoginUserRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{3} } func (m *LoginUserRequest) GetEmail() string { if m != nil { @@ -165,12 +165,13 @@ func (m *LoginUserRequest) GetPassword() string { type LoginUserResponse struct { Error string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` User *User `protobuf:"bytes,2,opt,name=user" json:"user,omitempty"` + Hmac string `protobuf:"bytes,3,opt,name=hmac" json:"hmac,omitempty"` } func (m *LoginUserResponse) Reset() { *m = LoginUserResponse{} } func (m *LoginUserResponse) String() string { return proto1.CompactTextString(m) } func (*LoginUserResponse) ProtoMessage() {} -func (*LoginUserResponse) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{4} } +func (*LoginUserResponse) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{4} } func (m *LoginUserResponse) GetError() string { if m != nil { @@ -186,6 +187,13 @@ func (m *LoginUserResponse) GetUser() *User { return nil } +func (m *LoginUserResponse) GetHmac() string { + if m != nil { + return m.Hmac + } + return "" +} + func init() { proto1.RegisterType((*User)(nil), "soapbox.User") proto1.RegisterType((*CreateUserRequest)(nil), "soapbox.CreateUserRequest") @@ -365,34 +373,35 @@ var _Users_serviceDesc = grpc.ServiceDesc{ Metadata: "user.proto", } -func init() { proto1.RegisterFile("user.proto", fileDescriptor6) } - -var fileDescriptor6 = []byte{ - // 413 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0x41, 0xaf, 0xd2, 0x40, - 0x18, 0x7c, 0xad, 0xed, 0x43, 0xbe, 0x17, 0x89, 0x6c, 0x8c, 0x96, 0x5e, 0xc0, 0x9e, 0xb8, 0x58, - 0x12, 0x48, 0x4c, 0x38, 0x56, 0x49, 0xb8, 0x90, 0x68, 0x1a, 0xbc, 0x78, 0x69, 0x96, 0x76, 0x2d, - 0x1b, 0x69, 0xb7, 0xee, 0x6e, 0xa3, 0xde, 0xfc, 0xb3, 0xfe, 0x0f, 0xb3, 0xbb, 0x65, 0x2d, 0x60, - 0xe2, 0xe1, 0x9d, 0xe0, 0xdb, 0xf9, 0xbe, 0x99, 0xce, 0x64, 0x00, 0x5a, 0x41, 0x78, 0xdc, 0x70, - 0x26, 0x19, 0x1a, 0x08, 0x86, 0x9b, 0x03, 0xfb, 0x11, 0x4e, 0x4b, 0xc6, 0xca, 0x13, 0x59, 0xe8, - 0xe7, 0x43, 0xfb, 0x65, 0x21, 0x69, 0x45, 0x84, 0xc4, 0x55, 0x63, 0x36, 0xa3, 0xdf, 0x0e, 0x78, - 0x9f, 0x04, 0xe1, 0x68, 0x04, 0x2e, 0x2d, 0x02, 0x67, 0xe6, 0xcc, 0xfd, 0xd4, 0xa5, 0x05, 0x42, - 0xe0, 0xd5, 0xb8, 0x22, 0x81, 0x3b, 0x73, 0xe6, 0xc3, 0x54, 0xff, 0x47, 0x2f, 0xc0, 0x27, 0x15, - 0xa6, 0xa7, 0xe0, 0x89, 0x7e, 0x34, 0x03, 0x7a, 0x03, 0x88, 0xd4, 0x39, 0xff, 0xd9, 0x48, 0x52, - 0x64, 0x0d, 0x16, 0xe2, 0x3b, 0xe3, 0x45, 0xe0, 0xe9, 0x95, 0xb1, 0x45, 0x3e, 0x76, 0x00, 0x5a, - 0xc3, 0xa4, 0xa4, 0xf2, 0xd8, 0x1e, 0x32, 0x86, 0x5b, 0x79, 0xcc, 0x70, 0x9e, 0x13, 0x21, 0x32, - 0xc9, 0xbe, 0x92, 0x3a, 0xf0, 0xf5, 0xd5, 0x4b, 0xb3, 0xf0, 0x41, 0xe1, 0x89, 0x86, 0xf7, 0x0a, - 0x45, 0x6b, 0x80, 0x9c, 0x13, 0xac, 0x74, 0xb0, 0x0c, 0xee, 0x67, 0xce, 0xfc, 0x61, 0x19, 0xc6, - 0xc6, 0x62, 0x7c, 0xb6, 0x18, 0xef, 0xcf, 0x16, 0xd3, 0x61, 0xb7, 0x9d, 0xc8, 0x88, 0xc2, 0xf8, - 0xbd, 0x1e, 0x94, 0xd9, 0x94, 0x7c, 0x6b, 0x89, 0x90, 0x8f, 0xf0, 0x1c, 0xc2, 0xd3, 0x2b, 0xa7, - 0x76, 0x8e, 0xde, 0xc2, 0x68, 0x4b, 0x64, 0x5f, 0xc7, 0x72, 0x38, 0x7d, 0x0e, 0xa3, 0xee, 0x9e, - 0xd5, 0xa3, 0x0d, 0x3c, 0xdf, 0xb1, 0x92, 0xd6, 0xff, 0xbf, 0xec, 0xab, 0xbb, 0x57, 0xea, 0x3b, - 0x18, 0xf7, 0x58, 0x44, 0xc3, 0x6a, 0x61, 0x4c, 0x70, 0xce, 0xb8, 0xa5, 0x51, 0x03, 0x7a, 0x0d, - 0x9e, 0xea, 0x8c, 0xa6, 0x78, 0x58, 0x3e, 0x8b, 0xbb, 0xd2, 0xc4, 0xfa, 0x54, 0x43, 0xcb, 0x5f, - 0x2e, 0xf8, 0x6a, 0x14, 0x2a, 0xfb, 0xbf, 0x01, 0xa2, 0xd0, 0x2e, 0xdf, 0xa4, 0x1a, 0x5e, 0x12, - 0x45, 0x77, 0x68, 0x05, 0x83, 0x2e, 0x10, 0xf4, 0xca, 0x62, 0x97, 0x11, 0xdd, 0x1e, 0x6d, 0x60, - 0x68, 0x7d, 0xa0, 0x89, 0x45, 0xaf, 0x13, 0x0a, 0xc3, 0x7f, 0x41, 0xc6, 0x76, 0x74, 0x87, 0x12, - 0x98, 0x26, 0x42, 0xd0, 0xb2, 0xde, 0x9a, 0x46, 0x55, 0x35, 0x55, 0xa5, 0xd2, 0x75, 0xda, 0x33, - 0xcd, 0x7d, 0xa9, 0x7c, 0xf3, 0x21, 0xef, 0x06, 0x9f, 0x7d, 0x53, 0xad, 0x7b, 0xfd, 0xb3, 0xfa, - 0x13, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x41, 0x5e, 0x63, 0x69, 0x03, 0x00, 0x00, +func init() { proto1.RegisterFile("user.proto", fileDescriptor2) } + +var fileDescriptor2 = []byte{ + // 423 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0x31, 0xcf, 0xd3, 0x30, + 0x10, 0xfd, 0x12, 0x92, 0xaf, 0xf4, 0x2a, 0x2a, 0x6a, 0x21, 0x48, 0xb3, 0xb4, 0x64, 0xea, 0x42, + 0x2a, 0xb5, 0x12, 0x52, 0xc7, 0x40, 0xa5, 0x2e, 0x48, 0xa0, 0xa8, 0x2c, 0x2c, 0xc1, 0x4d, 0x4c, + 0x6a, 0xd1, 0xc4, 0xc1, 0x76, 0x04, 0x6c, 0xfc, 0x59, 0xfe, 0x07, 0xb2, 0x9d, 0x9a, 0xb4, 0x45, + 0x62, 0xf8, 0xa6, 0xf8, 0xfc, 0xee, 0xde, 0xcb, 0x7b, 0x3e, 0x80, 0x56, 0x10, 0x1e, 0x37, 0x9c, + 0x49, 0x86, 0x06, 0x82, 0xe1, 0xe6, 0xc0, 0x7e, 0x84, 0xb3, 0x92, 0xb1, 0xf2, 0x44, 0x96, 0xfa, + 0xfa, 0xd0, 0x7e, 0x59, 0x4a, 0x5a, 0x11, 0x21, 0x71, 0xd5, 0x98, 0xce, 0xe8, 0xb7, 0x03, 0xde, + 0x47, 0x41, 0x38, 0x1a, 0x83, 0x4b, 0x8b, 0xc0, 0x99, 0x3b, 0x0b, 0x3f, 0x75, 0x69, 0x81, 0x10, + 0x78, 0x35, 0xae, 0x48, 0xe0, 0xce, 0x9d, 0xc5, 0x30, 0xd5, 0x67, 0xf4, 0x0c, 0x7c, 0x52, 0x61, + 0x7a, 0x0a, 0x1e, 0xe9, 0x4b, 0x53, 0xa0, 0x57, 0x80, 0x48, 0x9d, 0xf3, 0x9f, 0x8d, 0x24, 0x45, + 0xd6, 0x60, 0x21, 0xbe, 0x33, 0x5e, 0x04, 0x9e, 0x6e, 0x99, 0x58, 0xe4, 0x43, 0x07, 0xa0, 0x0d, + 0x4c, 0x4b, 0x2a, 0x8f, 0xed, 0x21, 0x63, 0xb8, 0x95, 0xc7, 0x0c, 0xe7, 0x39, 0x11, 0x22, 0x93, + 0xec, 0x2b, 0xa9, 0x03, 0x5f, 0x4f, 0x3d, 0x37, 0x0d, 0xef, 0x15, 0x9e, 0x68, 0x78, 0xaf, 0x50, + 0xb4, 0x01, 0xc8, 0x39, 0xc1, 0x4a, 0x07, 0xcb, 0xe0, 0x7e, 0xee, 0x2c, 0x46, 0xab, 0x30, 0x36, + 0x16, 0xe3, 0xb3, 0xc5, 0x78, 0x7f, 0xb6, 0x98, 0x0e, 0xbb, 0xee, 0x44, 0x46, 0x14, 0x26, 0x6f, + 0x75, 0xa1, 0xcc, 0xa6, 0xe4, 0x5b, 0x4b, 0x84, 0x7c, 0x80, 0xe7, 0x10, 0x1e, 0x5f, 0x39, 0xb5, + 0x75, 0xf4, 0x1a, 0xc6, 0x3b, 0x22, 0xfb, 0x3a, 0x96, 0xc3, 0xe9, 0x73, 0x18, 0x75, 0xf7, 0xac, + 0x1e, 0x6d, 0xe1, 0xe9, 0x3b, 0x56, 0xd2, 0xfa, 0xff, 0x93, 0x7d, 0x75, 0xf7, 0x4a, 0xfd, 0x33, + 0x4c, 0x7a, 0x2c, 0xa2, 0x61, 0xb5, 0x30, 0x26, 0x38, 0x67, 0xdc, 0xd2, 0xa8, 0x02, 0xbd, 0x04, + 0x4f, 0xed, 0x8c, 0xa6, 0x18, 0xad, 0x9e, 0xc4, 0xdd, 0xd2, 0xc4, 0x7a, 0x54, 0x43, 0x2a, 0x91, + 0x63, 0x85, 0xf3, 0xce, 0xbc, 0x3e, 0xaf, 0x7e, 0xb9, 0xe0, 0xab, 0x16, 0xa1, 0xde, 0xe3, 0x6f, + 0xa8, 0x28, 0xb4, 0x04, 0x37, 0x49, 0x87, 0x97, 0xe4, 0xd1, 0x1d, 0x5a, 0xc3, 0xa0, 0x0b, 0x09, + 0xbd, 0xb0, 0xd8, 0x65, 0x6c, 0xb7, 0x43, 0x5b, 0x18, 0x5a, 0x6f, 0x68, 0x6a, 0xd1, 0xeb, 0xd4, + 0xc2, 0xf0, 0x5f, 0x90, 0x89, 0x22, 0xba, 0x43, 0x09, 0xcc, 0x12, 0x21, 0x68, 0x59, 0xef, 0xcc, + 0x96, 0x55, 0x35, 0x55, 0x8b, 0xa6, 0x57, 0x6c, 0xcf, 0x34, 0xf7, 0xa5, 0xf2, 0xcd, 0x8f, 0xbc, + 0x19, 0x7c, 0xf2, 0xcd, 0xba, 0xdd, 0xeb, 0xcf, 0xfa, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xeb, + 0x06, 0x2b, 0xf3, 0x7d, 0x03, 0x00, 0x00, } diff --git a/soapboxd/user.go b/soapboxd/user.go index 51c1f0f..d977316 100644 --- a/soapboxd/user.go +++ b/soapboxd/user.go @@ -1,7 +1,11 @@ package soapboxd import ( + "crypto/hmac" + "crypto/sha512" "database/sql" + "encoding/base64" + "os" "github.com/adhocteam/soapbox/models" pb "github.com/adhocteam/soapbox/proto" @@ -91,20 +95,21 @@ func (s *server) LoginUser(ctx context.Context, req *pb.LoginUserRequest) (*pb.L Error: genericLoginErrorMsg, } - user, err := s.getUserByEmail(ctx, req.GetEmail()) - err = errors.Cause(err) - if err == sql.ErrNoRows { + user, getUserErr := s.getUserByEmail(ctx, req.GetEmail()) + getUserErr = errors.Cause(getUserErr) + if getUserErr == sql.ErrNoRows { return res, nil - } else if err != nil { - return nil, err + } else if getUserErr != nil { + return nil, getUserErr } - if err := bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(req.Password)); err != nil { + if bcryptErr := bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(req.Password)); bcryptErr != nil { return res, nil } res.User = user res.Error = "" + res.Hmac = computeHmac512(string(user.Id), os.Getenv("LOGIN_SECRET_KEY")) return res, nil } @@ -123,3 +128,10 @@ func (s *server) AssignGithubOmniauthTokenToUser(ctx context.Context, user *pb.U return user, nil } + +func computeHmac512(message string, secret string) string { + key := []byte(secret) + h := hmac.New(sha512.New, key) + h.Write([]byte(message)) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} diff --git a/soapboxpb/user.proto b/soapboxpb/user.proto index 5679d3b..c6d1caf 100644 --- a/soapboxpb/user.proto +++ b/soapboxpb/user.proto @@ -40,4 +40,5 @@ message LoginUserRequest { message LoginUserResponse { string error = 1; User user = 2; + string hmac = 3; } diff --git a/web/app/controllers/about_controller.rb b/web/app/controllers/about_controller.rb index 13d0ed0..6bbc23e 100644 --- a/web/app/controllers/about_controller.rb +++ b/web/app/controllers/about_controller.rb @@ -2,6 +2,6 @@ class AboutController < ApplicationController def index - @version = $api_version_client.get_version(Soapbox::Empty.new) + @version = $api_client.versions.get_version(Soapbox::Empty.new) end end diff --git a/web/app/controllers/application_controller.rb b/web/app/controllers/application_controller.rb index a2ff142..457bdff 100644 --- a/web/app/controllers/application_controller.rb +++ b/web/app/controllers/application_controller.rb @@ -6,7 +6,8 @@ class ApplicationController < ActionController::Base helper_method :octokit def require_login - redirect_to login_user_path unless current_user + redirect_to login_user_path unless current_user && session[:login_token] + wrap_api_calls end # Finds the User with the ID stored in the session with the key @@ -23,7 +24,7 @@ def refresh_user def get_user(email) req = Soapbox::GetUserRequest.new(email: email) - $api_user_client.get_user(req) + $api_client.users.get_user(req) end def octokit @@ -31,4 +32,21 @@ def octokit @octokit ||= Octokit::Client.new(access_token: current_user.github_oauth_access_token) end end + + private + + def wrap_api_calls + $api_client.to_h.values.each do |service| + service.class.class_exec do + old = instance_method(:request_response) + define_method(:request_response) do |route, req, marshal, unmarshal, _| + old.bind(self).call( + route, req, marshal, unmarshal, + user_id: current_user.id, + login_token: session[:login_token] + ) + end + end + end + end end diff --git a/web/app/controllers/applications_controller.rb b/web/app/controllers/applications_controller.rb index 6bfd5c0..f43dcd2 100644 --- a/web/app/controllers/applications_controller.rb +++ b/web/app/controllers/applications_controller.rb @@ -61,7 +61,7 @@ def show @app = $api_client.get_application(req) req = Soapbox::ListDeploymentRequest.new(application_id: params[:id].to_i) - res = $api_deployment_client.list_deployments(req) + res = $api_client.deployments.list_deployments(req) @deployment = res.deployments.sort_by { |d| -d.created_at.seconds }.first # strip the oauth token from the URL if present and remove trailing `.git` @@ -87,11 +87,11 @@ def find_repositories def get_environments(app_id) req = Soapbox::ListEnvironmentRequest.new(application_id: app_id) - $api_environment_client.list_environments(req).environments + $api_client.environments.list_environments(req).environments end def get_latest_deploy(app_id, env_id) req = Soapbox::GetLatestDeploymentRequest.new(application_id: app_id, environment_id: env_id) - $api_deployment_client.get_latest_deployment(req) + $api_client.deployments.get_latest_deployment(req) end end diff --git a/web/app/controllers/configurations_controller.rb b/web/app/controllers/configurations_controller.rb index 1c2c73b..76dbdaf 100644 --- a/web/app/controllers/configurations_controller.rb +++ b/web/app/controllers/configurations_controller.rb @@ -24,7 +24,7 @@ def create puts vars env_id = params[:environment_id].to_i req = Soapbox::CreateConfigurationRequest.new(environment_id: env_id, config_vars: vars) - $api_configurations_client.create_configuration(req) + $api_client.configurations.create_configuration(req) redirect_to application_environment_path(id: env_id) else render :index @@ -37,12 +37,12 @@ def set_context req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) @app = $api_client.get_application(req) req = Soapbox::GetEnvironmentRequest.new(id: params[:environment_id].to_i) - @environment = $api_environment_client.get_environment(req) + @environment = $api_client.environments.get_environment(req) end def get_latest_config(env) req = Soapbox::GetLatestConfigurationRequest.new(environment_id: env.id) - $api_configurations_client.get_latest_configuration(req) + $api_client.configurations.get_latest_configuration(req) end def form_from_config(config) diff --git a/web/app/controllers/dashboard_controller.rb b/web/app/controllers/dashboard_controller.rb index 62a5ad2..db3b2e0 100644 --- a/web/app/controllers/dashboard_controller.rb +++ b/web/app/controllers/dashboard_controller.rb @@ -38,30 +38,30 @@ def get_application_name(app_id) end def get_activities - @activities = $api_activity_client + @activities = $api_client.activities .list_activities(Soapbox::Empty.new) .activities.sort_by {|a| a.created_at.seconds}.reverse end def get_user_name(user_id) req = Soapbox::GetUserRequest.new(id: user_id) - @user_name = $api_user_client.get_user(req) + @user_name = $api_client.users.get_user(req) @user_name.name end def get_environment_name(env_id) req = Soapbox::GetEnvironmentRequest.new(id: env_id) - @env = $api_environment_client.get_environment(req) + @env = $api_client.environments.get_environment(req) @env.name end def get_environments(app_id) req = Soapbox::ListEnvironmentRequest.new(application_id: app_id) - $api_environment_client.list_environments(req).environments + $api_client.environments.list_environments(req).environments end def get_latest_deploy(app_id, env_id) req = Soapbox::GetLatestDeploymentRequest.new(application_id: app_id, environment_id: env_id) - $api_deployment_client.get_latest_deployment(req) + $api_client.deployments.get_latest_deployment(req) end end diff --git a/web/app/controllers/deployments_controller.rb b/web/app/controllers/deployments_controller.rb index dc20fa8..c0a74e3 100644 --- a/web/app/controllers/deployments_controller.rb +++ b/web/app/controllers/deployments_controller.rb @@ -6,7 +6,7 @@ class DeploymentsController < ApplicationController def index req = Soapbox::ListDeploymentRequest.new(application_id: params[:application_id].to_i) - res = $api_deployment_client.list_deployments(req) + res = $api_client.deployments.list_deployments(req) if res.deployments.count == 0 redirect_to new_application_deployment_path else @@ -23,7 +23,7 @@ def index def new req = Soapbox::ListEnvironmentRequest.new(application_id: params[:application_id].to_i) - res = $api_environment_client.list_environments(req) + res = $api_client.environments.list_environments(req) if res.environments.count == 0 redirect_to new_application_environment_path else @@ -37,7 +37,7 @@ def create env = Soapbox::Environment.new(id: @form.environment_id) app = Soapbox::Application.new(id: params[:application_id].to_i) req = Soapbox::Deployment.new(committish: @form.committish, application: app, env: env) - res = $api_deployment_client.start_deployment(req) + res = $api_client.deployments.start_deployment(req) redirect_to application_deployments_path(application_id: params[:application_id].to_i) else render :new @@ -46,7 +46,7 @@ def create def show req = Soapbox::GetDeploymentStatusRequest.new(id: params[:id].to_i) - res = $api_deployment_client.get_deployment_status(req) + res = $api_client.deployments.get_deployment_status(req) @state = res.state respond_to do |format| @@ -59,7 +59,7 @@ def show def list_environments(application_id) req = Soapbox::ListEnvironmentRequest.new(application_id: application_id) - $api_environment_client.list_environments(req).environments + $api_client.environments.list_environments(req).environments end def set_application diff --git a/web/app/controllers/environments_controller.rb b/web/app/controllers/environments_controller.rb index 2285601..17ac033 100644 --- a/web/app/controllers/environments_controller.rb +++ b/web/app/controllers/environments_controller.rb @@ -6,7 +6,7 @@ class EnvironmentsController < ApplicationController def index app_id = params[:application_id].to_i req = Soapbox::ListEnvironmentRequest.new(application_id: app_id) - res = $api_environment_client.list_environments(req) + res = $api_client.environments.list_environments(req) if res.environments.count == 0 redirect_to new_application_environment_path else @@ -30,7 +30,7 @@ def create @form = CreateEnvironmentForm.new(params[:environment]) if @form.valid? env = Soapbox::Environment.new(application_id: params[:application_id].to_i, name: @form.name) - $api_environment_client.create_environment(env) + $api_client.environments.create_environment(env) redirect_to application_environments_path else render :new @@ -44,7 +44,7 @@ def show def destroy req = Soapbox::DestroyEnvironmentRequest.new(id: params[:id].to_i) - $api_environment_client.destroy_environment(req) + $api_client.environments.destroy_environment(req) redirect_to application_environments_path end @@ -57,11 +57,11 @@ def set_application def get_environment(id) req = Soapbox::GetEnvironmentRequest.new(id: id) - $api_environment_client.get_environment(req) + $api_client.environments.get_environment(req) end def get_latest_deploy(app_id, env_id) req = Soapbox::GetLatestDeploymentRequest.new(application_id: app_id, environment_id: env_id) - $api_deployment_client.get_latest_deployment(req) + $api_client.deployments.get_latest_deployment(req) end end diff --git a/web/app/controllers/users_controller.rb b/web/app/controllers/users_controller.rb index db1b490..0e55c31 100644 --- a/web/app/controllers/users_controller.rb +++ b/web/app/controllers/users_controller.rb @@ -12,7 +12,7 @@ def create @form = CreateUserForm.new(params[:user]) if @form.valid? req = Soapbox::CreateUserRequest.new(name: @form.name, email: @form.email, password: @form.password) - @user = $api_user_client.create_user(req) + @user = $api_client.users.create_user(req) session[:current_user_email] = @user.email redirect_to profile_user_path else @@ -28,12 +28,13 @@ def attempt_login @form = LoginUserForm.new(params[:user]) if @form.valid? req = Soapbox::LoginUserRequest.new(email: @form.email, password: @form.password) - res = $api_user_client.login_user(req) + res = $api_client.users.login_user(req) if !res.error.blank? @form.errors.add(:password, :invalid) render :login else session[:current_user_email] = res.user.email + session[:login_token] = res.hmac redirect_to profile_user_path end else @@ -44,7 +45,7 @@ def attempt_login def omniauth auth = request.env['omniauth.auth'] @user.github_oauth_access_token = auth['credentials']['token'] - @user = $api_user_client.assign_github_omniauth_token_to_user(@user) + @user = $api_client.users.assign_github_omniauth_token_to_user(@user) refresh_user redirect_to profile_user_path end diff --git a/web/config/initializers/soapbox_api.rb b/web/config/initializers/soapbox_api.rb index 72b976b..4fc30a7 100644 --- a/web/config/initializers/soapbox_api.rb +++ b/web/config/initializers/soapbox_api.rb @@ -1,15 +1,13 @@ Dir[Rails.root.join('lib/*_services_pb.rb')].each { |f| require f } -api_server = if ENV['SOAPBOX_API_SERVER'].blank? - 'localhost:9090' - else - ENV['SOAPBOX_API_SERVER'] - end -# TODO(paulsmith): consolidate API clients -$api_client = Soapbox::Applications::Stub.new(api_server, :this_channel_is_insecure) -$api_environment_client = Soapbox::Environments::Stub.new(api_server, :this_channel_is_insecure) -$api_configurations_client = Soapbox::Configurations::Stub.new(api_server, :this_channel_is_insecure) -$api_deployment_client = Soapbox::Deployments::Stub.new(api_server, :this_channel_is_insecure) -$api_user_client = Soapbox::Users::Stub.new(api_server, :this_channel_is_insecure) -$api_version_client = Soapbox::Version::Stub.new(api_server, :this_channel_is_insecure) -$api_activity_client = Soapbox::Activities::Stub.new(api_server, :this_channel_is_insecure) +api_server = ENV['SOAPBOX_API_SERVER'] || 'localhost:9090' + +$api_client = OpenStruct.new( + applications: Soapbox::Applications::Stub.new(api_server, :this_channel_is_insecure), + environments: Soapbox::Environments::Stub.new(api_server, :this_channel_is_insecure), + configurations: Soapbox::Configurations::Stub.new(api_server, :this_channel_is_insecure), + deployments: Soapbox::Deployments::Stub.new(api_server, :this_channel_is_insecure), + users: Soapbox::Users::Stub.new(api_server, :this_channel_is_insecure), + versions: Soapbox::Version::Stub.new(api_server, :this_channel_is_insecure), + activities: Soapbox::Activities::Stub.new(api_server, :this_channel_is_insecure) +) diff --git a/web/lib/user_pb.rb b/web/lib/user_pb.rb index 9fd088e..050e402 100644 --- a/web/lib/user_pb.rb +++ b/web/lib/user_pb.rb @@ -30,6 +30,7 @@ add_message "soapbox.LoginUserResponse" do optional :error, :string, 1 optional :user, :message, 2, "soapbox.User" + optional :hmac, :string, 3 end end diff --git a/web/spec/controllers/applications_controller_spec.rb b/web/spec/controllers/applications_controller_spec.rb index eb763a7..b6595d8 100644 --- a/web/spec/controllers/applications_controller_spec.rb +++ b/web/spec/controllers/applications_controller_spec.rb @@ -22,7 +22,7 @@ before do allow($api_client).to receive(:get_application) { app } allow(Soapbox::ListDeploymentRequest).to receive(:new) { nil } - allow($api_deployment_client).to receive(:list_deployments) { + allow($api_client.deployments).to receive(:list_deployments) { ::Soapbox::ListDeploymentResponse.new( deployments: [dep] ) From 214c6194b72aadbc3fecaacb043fe146c63f307b Mon Sep 17 00:00:00 2001 From: ClydeDroid Date: Fri, 22 Sep 2017 14:53:53 -0400 Subject: [PATCH 2/9] Decode HMAC string correctly --- cmd/soapboxd/main.go | 13 +++++++-- soapboxd/user.go | 6 ++-- web/app/controllers/about_controller.rb | 2 +- web/app/controllers/application_controller.rb | 29 +++++++------------ .../controllers/applications_controller.rb | 12 ++++---- .../controllers/configurations_controller.rb | 8 ++--- web/app/controllers/dashboard_controller.rb | 16 +++++----- web/app/controllers/deployments_controller.rb | 12 ++++---- .../controllers/environments_controller.rb | 12 ++++---- web/app/controllers/users_controller.rb | 6 ++-- 10 files changed, 57 insertions(+), 59 deletions(-) diff --git a/cmd/soapboxd/main.go b/cmd/soapboxd/main.go index 883408e..f28b6a3 100644 --- a/cmd/soapboxd/main.go +++ b/cmd/soapboxd/main.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/sha512" "database/sql" + "encoding/base64" "flag" "fmt" "log" @@ -129,6 +130,11 @@ func loginInterceptor( info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { + if md, ok := metadata.FromContext(ctx); ok { + if _, ok := md["skip_auth"]; ok { + return handler(ctx, req) + } + } if err := authorize(ctx); err != nil { return nil, err } @@ -153,12 +159,15 @@ func (e *emptyMetadataErr) Error() string { func authorize(ctx context.Context) error { if md, ok := metadata.FromContext(ctx); ok { userID := []byte(md["user_id"][0]) - sentToken := []byte(md["login_token"][0]) + sentToken, err := base64.StdEncoding.DecodeString(md["login_token"][0]) + if err != nil { + return err + } key := []byte(os.Getenv("LOGIN_SECRET_KEY")) h := hmac.New(sha512.New, key) h.Write(userID) calculated := h.Sum(nil) - if hmac.Equal(calculated, sentToken) { + if hmac.Equal(sentToken, calculated) { return nil } diff --git a/soapboxd/user.go b/soapboxd/user.go index d977316..1fdfcbb 100644 --- a/soapboxd/user.go +++ b/soapboxd/user.go @@ -5,6 +5,7 @@ import ( "crypto/sha512" "database/sql" "encoding/base64" + "fmt" "os" "github.com/adhocteam/soapbox/models" @@ -109,7 +110,7 @@ func (s *server) LoginUser(ctx context.Context, req *pb.LoginUserRequest) (*pb.L res.User = user res.Error = "" - res.Hmac = computeHmac512(string(user.Id), os.Getenv("LOGIN_SECRET_KEY")) + res.Hmac = computeHmac512(fmt.Sprint(user.Id), os.Getenv("LOGIN_SECRET_KEY")) return res, nil } @@ -130,8 +131,7 @@ func (s *server) AssignGithubOmniauthTokenToUser(ctx context.Context, user *pb.U } func computeHmac512(message string, secret string) string { - key := []byte(secret) - h := hmac.New(sha512.New, key) + h := hmac.New(sha512.New, []byte(secret)) h.Write([]byte(message)) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } diff --git a/web/app/controllers/about_controller.rb b/web/app/controllers/about_controller.rb index 6bbc23e..1b626a6 100644 --- a/web/app/controllers/about_controller.rb +++ b/web/app/controllers/about_controller.rb @@ -2,6 +2,6 @@ class AboutController < ApplicationController def index - @version = $api_client.versions.get_version(Soapbox::Empty.new) + @version = $api_client.versions.get_version(Soapbox::Empty.new, user_metadata) end end diff --git a/web/app/controllers/application_controller.rb b/web/app/controllers/application_controller.rb index 457bdff..c2baab1 100644 --- a/web/app/controllers/application_controller.rb +++ b/web/app/controllers/application_controller.rb @@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base def require_login redirect_to login_user_path unless current_user && session[:login_token] - wrap_api_calls end # Finds the User with the ID stored in the session with the key @@ -24,7 +23,16 @@ def refresh_user def get_user(email) req = Soapbox::GetUserRequest.new(email: email) - $api_client.users.get_user(req) + $api_client.users.get_user(req, metadata: { skip_auth: 'true' }) + end + + def user_metadata + { + metadata: { + user_id: current_user.id.to_s, + login_token: session[:login_token] + } + } end def octokit @@ -32,21 +40,4 @@ def octokit @octokit ||= Octokit::Client.new(access_token: current_user.github_oauth_access_token) end end - - private - - def wrap_api_calls - $api_client.to_h.values.each do |service| - service.class.class_exec do - old = instance_method(:request_response) - define_method(:request_response) do |route, req, marshal, unmarshal, _| - old.bind(self).call( - route, req, marshal, unmarshal, - user_id: current_user.id, - login_token: session[:login_token] - ) - end - end - end - end end diff --git a/web/app/controllers/applications_controller.rb b/web/app/controllers/applications_controller.rb index f43dcd2..799ee42 100644 --- a/web/app/controllers/applications_controller.rb +++ b/web/app/controllers/applications_controller.rb @@ -6,7 +6,7 @@ class ApplicationsController < ApplicationController def index req = Soapbox::ListApplicationRequest.new(user_id: current_user.id) - res = $api_client.list_applications(req) + res = $api_client.list_applications(req, user_metadata) if res.applications.count == 0 redirect_to new_application_path else @@ -49,7 +49,7 @@ def create github_repo_url: @form.github_repo_url, type: type, user_id: current_user.id) - app = $api_client.create_application(app) + app = $api_client.create_application(app, user_metadata) redirect_to application_path(app.id) else render :new @@ -58,10 +58,10 @@ def create def show req = Soapbox::GetApplicationRequest.new(id: params[:id].to_i) - @app = $api_client.get_application(req) + @app = $api_client.get_application(req, user_metadata) req = Soapbox::ListDeploymentRequest.new(application_id: params[:id].to_i) - res = $api_client.deployments.list_deployments(req) + res = $api_client.deployments.list_deployments(req, user_metadata) @deployment = res.deployments.sort_by { |d| -d.created_at.seconds }.first # strip the oauth token from the URL if present and remove trailing `.git` @@ -87,11 +87,11 @@ def find_repositories def get_environments(app_id) req = Soapbox::ListEnvironmentRequest.new(application_id: app_id) - $api_client.environments.list_environments(req).environments + $api_client.environments.list_environments(req, user_metadata).environments end def get_latest_deploy(app_id, env_id) req = Soapbox::GetLatestDeploymentRequest.new(application_id: app_id, environment_id: env_id) - $api_client.deployments.get_latest_deployment(req) + $api_client.deployments.get_latest_deployment(req, user_metadata) end end diff --git a/web/app/controllers/configurations_controller.rb b/web/app/controllers/configurations_controller.rb index 76dbdaf..7e40152 100644 --- a/web/app/controllers/configurations_controller.rb +++ b/web/app/controllers/configurations_controller.rb @@ -24,7 +24,7 @@ def create puts vars env_id = params[:environment_id].to_i req = Soapbox::CreateConfigurationRequest.new(environment_id: env_id, config_vars: vars) - $api_client.configurations.create_configuration(req) + $api_client.configurations.create_configuration(req, user_metadata) redirect_to application_environment_path(id: env_id) else render :index @@ -35,14 +35,14 @@ def create def set_context req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) - @app = $api_client.get_application(req) + @app = $api_client.get_application(req, user_metadata) req = Soapbox::GetEnvironmentRequest.new(id: params[:environment_id].to_i) - @environment = $api_client.environments.get_environment(req) + @environment = $api_client.environments.get_environment(req, user_metadata) end def get_latest_config(env) req = Soapbox::GetLatestConfigurationRequest.new(environment_id: env.id) - $api_client.configurations.get_latest_configuration(req) + $api_client.configurations.get_latest_configuration(req, user_metadata) end def form_from_config(config) diff --git a/web/app/controllers/dashboard_controller.rb b/web/app/controllers/dashboard_controller.rb index db3b2e0..d54d2fd 100644 --- a/web/app/controllers/dashboard_controller.rb +++ b/web/app/controllers/dashboard_controller.rb @@ -1,16 +1,14 @@ require 'application_pb' class DashboardController < ApplicationController - before_action :get_activities - helper_method :get_application_name helper_method :get_environment_name helper_method :get_user_name def index req = Soapbox::ListApplicationRequest.new(user_id: current_user.id) - res = $api_client.list_applications(req) + res = $api_client.applications.list_applications(req, user_metadata) apps = res.applications @num_applications = apps.count @num_deployments = 0 @@ -33,35 +31,35 @@ def index def get_application_name(app_id) req = Soapbox::GetApplicationRequest.new(id: app_id) - @app = $api_client.get_application(req) + @app = $api_client.applications.get_application(req, user_metadata) @app.name end def get_activities @activities = $api_client.activities - .list_activities(Soapbox::Empty.new) + .list_activities(Soapbox::Empty.new, user_metadata) .activities.sort_by {|a| a.created_at.seconds}.reverse end def get_user_name(user_id) req = Soapbox::GetUserRequest.new(id: user_id) - @user_name = $api_client.users.get_user(req) + @user_name = $api_client.users.get_user(req, user_metadata) @user_name.name end def get_environment_name(env_id) req = Soapbox::GetEnvironmentRequest.new(id: env_id) - @env = $api_client.environments.get_environment(req) + @env = $api_client.environments.get_environment(req, user_metadata) @env.name end def get_environments(app_id) req = Soapbox::ListEnvironmentRequest.new(application_id: app_id) - $api_client.environments.list_environments(req).environments + $api_client.environments.list_environments(req, user_metadata).environments end def get_latest_deploy(app_id, env_id) req = Soapbox::GetLatestDeploymentRequest.new(application_id: app_id, environment_id: env_id) - $api_client.deployments.get_latest_deployment(req) + $api_client.deployments.get_latest_deployment(req, user_metadata) end end diff --git a/web/app/controllers/deployments_controller.rb b/web/app/controllers/deployments_controller.rb index c0a74e3..e784713 100644 --- a/web/app/controllers/deployments_controller.rb +++ b/web/app/controllers/deployments_controller.rb @@ -6,7 +6,7 @@ class DeploymentsController < ApplicationController def index req = Soapbox::ListDeploymentRequest.new(application_id: params[:application_id].to_i) - res = $api_client.deployments.list_deployments(req) + res = $api_client.deployments.list_deployments(req, user_metadata) if res.deployments.count == 0 redirect_to new_application_deployment_path else @@ -23,7 +23,7 @@ def index def new req = Soapbox::ListEnvironmentRequest.new(application_id: params[:application_id].to_i) - res = $api_client.environments.list_environments(req) + res = $api_client.environments.list_environments(req, user_metadata) if res.environments.count == 0 redirect_to new_application_environment_path else @@ -37,7 +37,7 @@ def create env = Soapbox::Environment.new(id: @form.environment_id) app = Soapbox::Application.new(id: params[:application_id].to_i) req = Soapbox::Deployment.new(committish: @form.committish, application: app, env: env) - res = $api_client.deployments.start_deployment(req) + res = $api_client.deployments.start_deployment(req, user_metadata) redirect_to application_deployments_path(application_id: params[:application_id].to_i) else render :new @@ -46,7 +46,7 @@ def create def show req = Soapbox::GetDeploymentStatusRequest.new(id: params[:id].to_i) - res = $api_client.deployments.get_deployment_status(req) + res = $api_client.deployments.get_deployment_status(req, user_metadata) @state = res.state respond_to do |format| @@ -59,12 +59,12 @@ def show def list_environments(application_id) req = Soapbox::ListEnvironmentRequest.new(application_id: application_id) - $api_client.environments.list_environments(req).environments + $api_client.environments.list_environments(req, user_metadata).environments end def set_application req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) - @app = $api_client.get_application(req) + @app = $api_client.get_application(req, user_metadata) end def set_environments diff --git a/web/app/controllers/environments_controller.rb b/web/app/controllers/environments_controller.rb index 17ac033..0437f13 100644 --- a/web/app/controllers/environments_controller.rb +++ b/web/app/controllers/environments_controller.rb @@ -6,7 +6,7 @@ class EnvironmentsController < ApplicationController def index app_id = params[:application_id].to_i req = Soapbox::ListEnvironmentRequest.new(application_id: app_id) - res = $api_client.environments.list_environments(req) + res = $api_client.environments.list_environments(req, user_metadata) if res.environments.count == 0 redirect_to new_application_environment_path else @@ -30,7 +30,7 @@ def create @form = CreateEnvironmentForm.new(params[:environment]) if @form.valid? env = Soapbox::Environment.new(application_id: params[:application_id].to_i, name: @form.name) - $api_client.environments.create_environment(env) + $api_client.environments.create_environment(env, user_metadata) redirect_to application_environments_path else render :new @@ -44,7 +44,7 @@ def show def destroy req = Soapbox::DestroyEnvironmentRequest.new(id: params[:id].to_i) - $api_client.environments.destroy_environment(req) + $api_client.environments.destroy_environment(req, user_metadata) redirect_to application_environments_path end @@ -52,16 +52,16 @@ def destroy def set_application req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) - @app = $api_client.get_application(req) + @app = $api_client.get_application(req, user_metadata) end def get_environment(id) req = Soapbox::GetEnvironmentRequest.new(id: id) - $api_client.environments.get_environment(req) + $api_client.environments.get_environment(req, user_metadata) end def get_latest_deploy(app_id, env_id) req = Soapbox::GetLatestDeploymentRequest.new(application_id: app_id, environment_id: env_id) - $api_client.deployments.get_latest_deployment(req) + $api_client.deployments.get_latest_deployment(req, user_metadata) end end diff --git a/web/app/controllers/users_controller.rb b/web/app/controllers/users_controller.rb index 0e55c31..c7e8912 100644 --- a/web/app/controllers/users_controller.rb +++ b/web/app/controllers/users_controller.rb @@ -12,7 +12,7 @@ def create @form = CreateUserForm.new(params[:user]) if @form.valid? req = Soapbox::CreateUserRequest.new(name: @form.name, email: @form.email, password: @form.password) - @user = $api_client.users.create_user(req) + @user = $api_client.users.create_user(req, skip_auth: true) session[:current_user_email] = @user.email redirect_to profile_user_path else @@ -28,7 +28,7 @@ def attempt_login @form = LoginUserForm.new(params[:user]) if @form.valid? req = Soapbox::LoginUserRequest.new(email: @form.email, password: @form.password) - res = $api_client.users.login_user(req) + res = $api_client.users.login_user(req, metadata: { skip_auth: 'true' }) if !res.error.blank? @form.errors.add(:password, :invalid) render :login @@ -45,7 +45,7 @@ def attempt_login def omniauth auth = request.env['omniauth.auth'] @user.github_oauth_access_token = auth['credentials']['token'] - @user = $api_client.users.assign_github_omniauth_token_to_user(@user) + @user = $api_client.users.assign_github_omniauth_token_to_user(@user, user_metadata) refresh_user redirect_to profile_user_path end From 1f6dd43d85970dfaae567710826d751d40779a16 Mon Sep 17 00:00:00 2001 From: ClydeDroid Date: Fri, 6 Oct 2017 15:05:28 -0400 Subject: [PATCH 3/9] Make server decide when to auth --- cmd/soapboxd/main.go | 16 ++++++++-------- web/app/controllers/application_controller.rb | 2 +- web/app/controllers/users_controller.rb | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/soapboxd/main.go b/cmd/soapboxd/main.go index f28b6a3..c10037b 100644 --- a/cmd/soapboxd/main.go +++ b/cmd/soapboxd/main.go @@ -12,6 +12,7 @@ import ( "os" "os/exec" "strconv" + "strings" "time" "github.com/adhocteam/soapbox" @@ -130,16 +131,15 @@ func loginInterceptor( info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { - if md, ok := metadata.FromContext(ctx); ok { - if _, ok := md["skip_auth"]; ok { - return handler(ctx, req) + switch strings.Split(info.FullMethod, "/")[2] { + case "LoginUser", "CreateUser", "GetUser": + return handler(ctx, req) + default: + if err := authorize(ctx); err != nil { + return nil, err } + return handler(ctx, req) } - if err := authorize(ctx); err != nil { - return nil, err - } - - return handler(ctx, req) } type accessDeniedErr struct { diff --git a/web/app/controllers/application_controller.rb b/web/app/controllers/application_controller.rb index c2baab1..45894e3 100644 --- a/web/app/controllers/application_controller.rb +++ b/web/app/controllers/application_controller.rb @@ -23,7 +23,7 @@ def refresh_user def get_user(email) req = Soapbox::GetUserRequest.new(email: email) - $api_client.users.get_user(req, metadata: { skip_auth: 'true' }) + $api_client.users.get_user(req) end def user_metadata diff --git a/web/app/controllers/users_controller.rb b/web/app/controllers/users_controller.rb index c7e8912..762db8e 100644 --- a/web/app/controllers/users_controller.rb +++ b/web/app/controllers/users_controller.rb @@ -12,7 +12,7 @@ def create @form = CreateUserForm.new(params[:user]) if @form.valid? req = Soapbox::CreateUserRequest.new(name: @form.name, email: @form.email, password: @form.password) - @user = $api_client.users.create_user(req, skip_auth: true) + @user = $api_client.users.create_user(req) session[:current_user_email] = @user.email redirect_to profile_user_path else @@ -28,7 +28,7 @@ def attempt_login @form = LoginUserForm.new(params[:user]) if @form.valid? req = Soapbox::LoginUserRequest.new(email: @form.email, password: @form.password) - res = $api_client.users.login_user(req, metadata: { skip_auth: 'true' }) + res = $api_client.users.login_user(req) if !res.error.blank? @form.errors.add(:password, :invalid) render :login From 1cc31093e7292460b2271bc18503884d4be2b000 Mon Sep 17 00:00:00 2001 From: Kalil Smith-Nuevelle Date: Thu, 2 Aug 2018 13:53:55 -0500 Subject: [PATCH 4/9] Fix call to removed grpc method (see https://github.com/grpc/grpc-go/pull/1157) --- cmd/soapboxd/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/soapboxd/main.go b/cmd/soapboxd/main.go index c10037b..5615252 100644 --- a/cmd/soapboxd/main.go +++ b/cmd/soapboxd/main.go @@ -157,7 +157,7 @@ func (e *emptyMetadataErr) Error() string { } func authorize(ctx context.Context) error { - if md, ok := metadata.FromContext(ctx); ok { + if md, ok := metadata.FromIncomingContext(ctx); ok { userID := []byte(md["user_id"][0]) sentToken, err := base64.StdEncoding.DecodeString(md["login_token"][0]) if err != nil { From 4786b763696c64c6698da103805acb6f88258689 Mon Sep 17 00:00:00 2001 From: Kalil Smith-Nuevelle Date: Thu, 2 Aug 2018 15:27:07 -0500 Subject: [PATCH 5/9] Fix api_client references --- web/app/controllers/application_controller.rb | 2 +- web/app/controllers/applications_controller.rb | 10 +++++----- web/app/controllers/configurations_controller.rb | 2 +- web/app/controllers/deployments_controller.rb | 2 +- web/app/controllers/environments_controller.rb | 2 +- web/spec/controllers/applications_controller_spec.rb | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/web/app/controllers/application_controller.rb b/web/app/controllers/application_controller.rb index fcabe14..f4de285 100644 --- a/web/app/controllers/application_controller.rb +++ b/web/app/controllers/application_controller.rb @@ -40,7 +40,7 @@ def user_metadata def get_metrics(app_id, metric_type) req = Soapbox::GetApplicationMetricsRequest.new(id: app_id, metric_type: metric_type) @metrics = [] - app_metrics = $api_client.get_application_metrics(req) + app_metrics = $api_client.applications.get_application_metrics(req) sorted_metrics = app_metrics.metrics.sort_by {|metric| Time.parse(metric.time) } diff --git a/web/app/controllers/applications_controller.rb b/web/app/controllers/applications_controller.rb index 7a9d52d..e70979d 100644 --- a/web/app/controllers/applications_controller.rb +++ b/web/app/controllers/applications_controller.rb @@ -6,7 +6,7 @@ class ApplicationsController < ApplicationController def index req = Soapbox::ListApplicationRequest.new(user_id: current_user.id) - res = $api_client.list_applications(req, user_metadata) + res = $api_client.applications.list_applications(req, user_metadata) if res.applications.count == 0 redirect_to new_application_path else @@ -49,7 +49,7 @@ def create github_repo_url: @form.github_repo_url, type: type, user_id: current_user.id) - app = $api_client.create_application(app, user_metadata) + app = $api_client.applications.create_application(app, user_metadata) redirect_to application_path(app.id) else render :new @@ -58,7 +58,7 @@ def create def show req = Soapbox::GetApplicationRequest.new(id: params[:id].to_i) - @app = $api_client.get_application(req, user_metadata) + @app = $api_client.applications.get_application(req, user_metadata) req = Soapbox::ListDeploymentRequest.new(application_id: params[:id].to_i) res = $api_client.deployments.list_deployments(req, user_metadata) @@ -75,8 +75,8 @@ def show def destroy req = Soapbox::GetApplicationRequest.new(id: params[:id].to_i) - @app = $api_client.get_application(req) - $api_client.delete_application(@app) + @app = $api_client.applications.get_application(req) + $api_client.applications.delete_application(@app) redirect_to application_path(@app.id) end diff --git a/web/app/controllers/configurations_controller.rb b/web/app/controllers/configurations_controller.rb index 7e40152..c80fd41 100644 --- a/web/app/controllers/configurations_controller.rb +++ b/web/app/controllers/configurations_controller.rb @@ -35,7 +35,7 @@ def create def set_context req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) - @app = $api_client.get_application(req, user_metadata) + @app = $api_client.applications.get_application(req, user_metadata) req = Soapbox::GetEnvironmentRequest.new(id: params[:environment_id].to_i) @environment = $api_client.environments.get_environment(req, user_metadata) end diff --git a/web/app/controllers/deployments_controller.rb b/web/app/controllers/deployments_controller.rb index 27ce678..b347951 100644 --- a/web/app/controllers/deployments_controller.rb +++ b/web/app/controllers/deployments_controller.rb @@ -65,7 +65,7 @@ def list_environments(application_id) def set_application req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) - @app = $api_client.get_application(req, user_metadata) + @app = $api_client.applications.get_application(req, user_metadata) end def set_environments diff --git a/web/app/controllers/environments_controller.rb b/web/app/controllers/environments_controller.rb index 0437f13..c9a97d3 100644 --- a/web/app/controllers/environments_controller.rb +++ b/web/app/controllers/environments_controller.rb @@ -52,7 +52,7 @@ def destroy def set_application req = Soapbox::GetApplicationRequest.new(id: params[:application_id].to_i) - @app = $api_client.get_application(req, user_metadata) + @app = $api_client.applications.get_application(req, user_metadata) end def get_environment(id) diff --git a/web/spec/controllers/applications_controller_spec.rb b/web/spec/controllers/applications_controller_spec.rb index b6595d8..9c3faec 100644 --- a/web/spec/controllers/applications_controller_spec.rb +++ b/web/spec/controllers/applications_controller_spec.rb @@ -20,7 +20,7 @@ } before do - allow($api_client).to receive(:get_application) { app } + allow($api_client.applications).to receive(:get_application) { app } allow(Soapbox::ListDeploymentRequest).to receive(:new) { nil } allow($api_client.deployments).to receive(:list_deployments) { ::Soapbox::ListDeploymentResponse.new( From 35f6f1e028572b2551977b0186afd15022257cfe Mon Sep 17 00:00:00 2001 From: Kalil Smith-Nuevelle Date: Thu, 2 Aug 2018 16:08:27 -0500 Subject: [PATCH 6/9] Add login token to controller spec --- web/spec/controllers/applications_controller_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/web/spec/controllers/applications_controller_spec.rb b/web/spec/controllers/applications_controller_spec.rb index 9c3faec..24b7a5d 100644 --- a/web/spec/controllers/applications_controller_spec.rb +++ b/web/spec/controllers/applications_controller_spec.rb @@ -18,6 +18,7 @@ committish: "abcdef0123456789" ) } + let(:session) { {login_token: 'ijkN8a5iAluZY4Cv7qOHsruLBJNheehdVTzCqp/tEzUK/VGM91OH6ZH6FwB9D4jZLKh4SYx51aVAr2VJpGHUeg=='} } before do allow($api_client.applications).to receive(:get_application) { app } @@ -34,12 +35,12 @@ context "github URL with oauth and .git" do it "responds correctly" do - get :show, params: {id: 1} + get :show, params: {id: 1}, session: session expect(response.success?) end it "sets the correct github url" do - get :show, params: {id: 1} + get :show, params: {id: 1}, session: session expect(@controller.instance_variable_get(:@github_url)).to eq "https://github.com/bananas/shorts" end end @@ -52,12 +53,12 @@ } it "responds correctly" do - get :show, params: {id: 1} + get :show, params: {id: 1}, session: session expect(response.success?) end it "sets the correct github url" do - get :show, params: {id: 1} + get :show, params: {id: 1}, session: session expect(@controller.instance_variable_get(:@github_url)).to eq "https://github.com/bananas/shorts" end end From f40ee5d0b4fc4bdcfcf6da8576dabcc9db3d1095 Mon Sep 17 00:00:00 2001 From: Kalil Smith-Nuevelle Date: Fri, 3 Aug 2018 11:43:37 -0500 Subject: [PATCH 7/9] Stop naming our error variables --- soapboxd/user.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/soapboxd/user.go b/soapboxd/user.go index 6a949ab..e2b033c 100644 --- a/soapboxd/user.go +++ b/soapboxd/user.go @@ -96,15 +96,15 @@ func (s *server) LoginUser(ctx context.Context, req *pb.LoginUserRequest) (*pb.L Error: genericLoginErrorMsg, } - user, getUserErr := s.getUserByEmail(ctx, req.GetEmail()) - getUserErr = errors.Cause(getUserErr) - if getUserErr == sql.ErrNoRows { + user, err := s.getUserByEmail(ctx, req.GetEmail()) + err = errors.Cause(err) + if err == sql.ErrNoRows { return res, nil - } else if getUserErr != nil { - return nil, errors.Cause(getUserErr) + } else if err != nil { + return nil, errors.Cause(err) } - if bcryptErr := bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(req.Password)); bcryptErr != nil { + if err = bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(req.Password)); err != nil { return res, nil } From 05bd4f28f3e0219a640efbab6a8eccc4f21a624b Mon Sep 17 00:00:00 2001 From: Kalil Smith-Nuevelle Date: Fri, 3 Aug 2018 11:56:23 -0500 Subject: [PATCH 8/9] Add comment about static auth token --- cmd/soapboxd/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/soapboxd/main.go b/cmd/soapboxd/main.go index 5615252..ed076a0 100644 --- a/cmd/soapboxd/main.go +++ b/cmd/soapboxd/main.go @@ -156,6 +156,8 @@ func (e *emptyMetadataErr) Error() string { return fmt.Sprint("No metadata attached with request") } +// TODO(kalilsn) The token calculated here is static, so it can't be revoked, and if stolen +// would allow an attacker to impersonate a user indefinitely. func authorize(ctx context.Context) error { if md, ok := metadata.FromIncomingContext(ctx); ok { userID := []byte(md["user_id"][0]) From 57ee8e6f0c5cc71b64f33c98502558715df68c85 Mon Sep 17 00:00:00 2001 From: Kalil Smith-Nuevelle Date: Fri, 3 Aug 2018 12:01:01 -0500 Subject: [PATCH 9/9] Fix merge error --- soapboxd/user.go | 1 - 1 file changed, 1 deletion(-) diff --git a/soapboxd/user.go b/soapboxd/user.go index e2b033c..a1578fa 100644 --- a/soapboxd/user.go +++ b/soapboxd/user.go @@ -97,7 +97,6 @@ func (s *server) LoginUser(ctx context.Context, req *pb.LoginUserRequest) (*pb.L } user, err := s.getUserByEmail(ctx, req.GetEmail()) - err = errors.Cause(err) if err == sql.ErrNoRows { return res, nil } else if err != nil {