Merge pull request #585 from ericchiang/dev-api

dev branch: add a simple gRPC API
This commit is contained in:
Eric Chiang
2016-10-05 14:14:28 -07:00
committed by GitHub
154 changed files with 30539 additions and 26 deletions
+24 -7
View File
@@ -8,21 +8,26 @@ VERSION=$(shell ./scripts/git-version)
DOCKER_REPO=quay.io/ericchiang/dex
DOCKER_IMAGE=$(DOCKER_REPO):$(VERSION)
$( shell mkdir -p bin )
export GOBIN=$(PWD)/bin
# Prefer ./bin instead of system packages for things like protoc, where we want
# to use the version dex uses, not whatever a developer has installed.
export PATH=$(GOBIN):$(shell printenv PATH)
export GO15VENDOREXPERIMENT=1
LD_FLAGS="-w -X $(REPO_PATH)/version.Version=$(VERSION)"
GOOS=$(shell go env GOOS)
GOARCH=$(shell go env GOARCH)
build: bin/dex bin/example-app
bin/dex: FORCE server/templates_default.go
@go install -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex
bin/dex: FORCE generated
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex
bin/example-app: FORCE
@go install -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/example-app
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/example-app
.PHONY: generated
generated: server/templates_default.go
test:
@go test -v -i $(shell go list ./... | grep -v '/vendor/')
@@ -39,7 +44,7 @@ fmt:
@go fmt $(shell go list ./... | grep -v '/vendor/')
lint:
@for package in $(shell go list ./... | grep -v '/vendor/' | grep -v 'api/apipb'); do \
@for package in $(shell go list ./... | grep -v '/vendor/' | grep -v '/api'); do \
golint -set_exit_status $$package; \
done
@@ -56,6 +61,18 @@ docker-push: docker-build
@docker push $(DOCKER_IMAGE)
@docker push $(DOCKER_REPO):latest
.PHONY: grpc
grpc: api/api.pb.go
api/api.pb.go: api/api.proto bin/protoc bin/protoc-gen-go
@protoc --go_out=plugins=grpc:. api/*.proto
bin/protoc: scripts/get-protoc
@./scripts/get-protoc bin/protoc
bin/protoc-gen-go:
@go install -v $(REPO_PATH)/vendor/github.com/golang/protobuf/protoc-gen-go
clean:
@rm bin/*
-9
View File
@@ -8,15 +8,6 @@ OpenID Connect / OAuth2
- [ ] Add a "NextSigningKey" to the storage.Keys type so clients can cache more aggressively
- [ ] Support grant_type=password
API
- [ ] Determine best way to expose an API
- [ ] Use access tokens so we don't expose the underlying credentials implementation
- [ ] Support grant_type=client_credentials so clients can operate on their own
- [ ] Figure out a spec for the access tokens so other services can use them
- [ ] Group API, ability to list groups, members, etc.
- [ ] Expose capabilities of the server (implicit support, group API, etc.)
Connectors
- [ ] Port BitBucket connector
+255
View File
@@ -0,0 +1,255 @@
// Code generated by protoc-gen-go.
// source: api/api.proto
// DO NOT EDIT!
/*
Package api is a generated protocol buffer package.
It is generated from these files:
api/api.proto
It has these top-level messages:
Client
CreateClientReq
CreateClientResp
DeleteClientReq
DeleteClientResp
*/
package api
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.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 _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// Client represents an OAuth2 client.
type Client struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Secret string `protobuf:"bytes,2,opt,name=secret" json:"secret,omitempty"`
RedirectUris []string `protobuf:"bytes,3,rep,name=redirect_uris,json=redirectUris" json:"redirect_uris,omitempty"`
TrustedPeers []string `protobuf:"bytes,4,rep,name=trusted_peers,json=trustedPeers" json:"trusted_peers,omitempty"`
Public bool `protobuf:"varint,5,opt,name=public" json:"public,omitempty"`
Name string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"`
LogoUrl string `protobuf:"bytes,7,opt,name=logo_url,json=logoUrl" json:"logo_url,omitempty"`
}
func (m *Client) Reset() { *m = Client{} }
func (m *Client) String() string { return proto.CompactTextString(m) }
func (*Client) ProtoMessage() {}
func (*Client) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
// CreateClientReq is a request to make a client.
type CreateClientReq struct {
Client *Client `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
}
func (m *CreateClientReq) Reset() { *m = CreateClientReq{} }
func (m *CreateClientReq) String() string { return proto.CompactTextString(m) }
func (*CreateClientReq) ProtoMessage() {}
func (*CreateClientReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *CreateClientReq) GetClient() *Client {
if m != nil {
return m.Client
}
return nil
}
// CreateClientResp returns the response from creating a client.
type CreateClientResp struct {
AlreadyExists bool `protobuf:"varint,1,opt,name=already_exists,json=alreadyExists" json:"already_exists,omitempty"`
Client *Client `protobuf:"bytes,2,opt,name=client" json:"client,omitempty"`
}
func (m *CreateClientResp) Reset() { *m = CreateClientResp{} }
func (m *CreateClientResp) String() string { return proto.CompactTextString(m) }
func (*CreateClientResp) ProtoMessage() {}
func (*CreateClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *CreateClientResp) GetClient() *Client {
if m != nil {
return m.Client
}
return nil
}
// DeleteClientReq is a request to delete a client.
type DeleteClientReq struct {
// The ID of the client.
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
}
func (m *DeleteClientReq) Reset() { *m = DeleteClientReq{} }
func (m *DeleteClientReq) String() string { return proto.CompactTextString(m) }
func (*DeleteClientReq) ProtoMessage() {}
func (*DeleteClientReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
// DeleteClientResp determines if the.
type DeleteClientResp struct {
NotFound bool `protobuf:"varint,1,opt,name=not_found,json=notFound" json:"not_found,omitempty"`
}
func (m *DeleteClientResp) Reset() { *m = DeleteClientResp{} }
func (m *DeleteClientResp) String() string { return proto.CompactTextString(m) }
func (*DeleteClientResp) ProtoMessage() {}
func (*DeleteClientResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func init() {
proto.RegisterType((*Client)(nil), "api.Client")
proto.RegisterType((*CreateClientReq)(nil), "api.CreateClientReq")
proto.RegisterType((*CreateClientResp)(nil), "api.CreateClientResp")
proto.RegisterType((*DeleteClientReq)(nil), "api.DeleteClientReq")
proto.RegisterType((*DeleteClientResp)(nil), "api.DeleteClientResp")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion3
// Client API for Dex service
type DexClient interface {
// CreateClient attempts to create the client.
CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error)
// DeleteClient attempts to delete the provided client.
DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error)
}
type dexClient struct {
cc *grpc.ClientConn
}
func NewDexClient(cc *grpc.ClientConn) DexClient {
return &dexClient{cc}
}
func (c *dexClient) CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error) {
out := new(CreateClientResp)
err := grpc.Invoke(ctx, "/api.Dex/CreateClient", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error) {
out := new(DeleteClientResp)
err := grpc.Invoke(ctx, "/api.Dex/DeleteClient", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Dex service
type DexServer interface {
// CreateClient attempts to create the client.
CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error)
// DeleteClient attempts to delete the provided client.
DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error)
}
func RegisterDexServer(s *grpc.Server, srv DexServer) {
s.RegisterService(&_Dex_serviceDesc, srv)
}
func _Dex_CreateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).CreateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/CreateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).CreateClient(ctx, req.(*CreateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_DeleteClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).DeleteClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/DeleteClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).DeleteClient(ctx, req.(*DeleteClientReq))
}
return interceptor(ctx, in, info, handler)
}
var _Dex_serviceDesc = grpc.ServiceDesc{
ServiceName: "api.Dex",
HandlerType: (*DexServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateClient",
Handler: _Dex_CreateClient_Handler,
},
{
MethodName: "DeleteClient",
Handler: _Dex_DeleteClient_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: fileDescriptor0,
}
func init() { proto.RegisterFile("api/api.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 337 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x92, 0x4f, 0x6b, 0xe3, 0x30,
0x10, 0xc5, 0x63, 0x3b, 0xeb, 0x38, 0x93, 0xbf, 0x88, 0xdd, 0xc5, 0xbb, 0xbd, 0xa4, 0x0e, 0x85,
0x9c, 0x12, 0x48, 0xa1, 0xb7, 0x9e, 0x92, 0xf6, 0x5c, 0x0c, 0xb9, 0xd6, 0x28, 0xf6, 0xb4, 0x08,
0x54, 0x4b, 0x95, 0x64, 0x48, 0xcf, 0xfd, 0x64, 0xfd, 0x66, 0x45, 0x8a, 0x0a, 0x4e, 0x68, 0x6f,
0x7e, 0x3f, 0xcd, 0xcc, 0x7b, 0x33, 0x18, 0x46, 0x54, 0xb2, 0x15, 0x95, 0x6c, 0x29, 0x95, 0x30,
0x82, 0x44, 0x54, 0xb2, 0xec, 0x23, 0x80, 0x78, 0xc3, 0x19, 0xd6, 0x86, 0x8c, 0x21, 0x64, 0x55,
0x1a, 0xcc, 0x82, 0x45, 0x3f, 0x0f, 0x59, 0x45, 0xfe, 0x42, 0xac, 0xb1, 0x54, 0x68, 0xd2, 0xd0,
0x31, 0xaf, 0xc8, 0x1c, 0x46, 0x0a, 0x2b, 0xa6, 0xb0, 0x34, 0x45, 0xa3, 0x98, 0x4e, 0xa3, 0x59,
0xb4, 0xe8, 0xe7, 0xc3, 0x2f, 0xb8, 0x53, 0x4c, 0xdb, 0x22, 0xa3, 0x1a, 0x6d, 0xb0, 0x2a, 0x24,
0xa2, 0xd2, 0x69, 0xf7, 0x58, 0xe4, 0xe1, 0x83, 0x65, 0xd6, 0x41, 0x36, 0x7b, 0xce, 0xca, 0xf4,
0xd7, 0x2c, 0x58, 0x24, 0xb9, 0x57, 0x84, 0x40, 0xb7, 0xa6, 0x2f, 0x98, 0xc6, 0xce, 0xd7, 0x7d,
0x93, 0x7f, 0x90, 0x70, 0xf1, 0x2c, 0x8a, 0x46, 0xf1, 0xb4, 0xe7, 0x78, 0xcf, 0xea, 0x9d, 0xe2,
0xd9, 0x0d, 0x4c, 0x36, 0x0a, 0xa9, 0xc1, 0xe3, 0x22, 0x39, 0xbe, 0x92, 0x39, 0xc4, 0xa5, 0x13,
0x6e, 0x9f, 0xc1, 0x7a, 0xb0, 0xb4, 0x7b, 0xfb, 0x77, 0xff, 0x94, 0x3d, 0xc2, 0xf4, 0xb4, 0x4f,
0x4b, 0x72, 0x05, 0x63, 0xca, 0x15, 0xd2, 0xea, 0xad, 0xc0, 0x03, 0xd3, 0x46, 0xbb, 0x01, 0x49,
0x3e, 0xf2, 0xf4, 0xce, 0xc1, 0xd6, 0xfc, 0xf0, 0xe7, 0xf9, 0x97, 0x30, 0xd9, 0x22, 0xc7, 0x76,
0xae, 0xb3, 0x1b, 0x67, 0x2b, 0x98, 0x9e, 0x96, 0x68, 0x49, 0x2e, 0xa0, 0x5f, 0x0b, 0x53, 0x3c,
0x89, 0xa6, 0xae, 0xbc, 0x7b, 0x52, 0x0b, 0x73, 0x6f, 0xf5, 0xfa, 0x3d, 0x80, 0x68, 0x8b, 0x07,
0x72, 0x0b, 0xc3, 0x76, 0x76, 0xf2, 0xfb, 0x18, 0xe0, 0xf4, 0x0c, 0xff, 0xff, 0x7c, 0x43, 0xb5,
0xcc, 0x3a, 0xb6, 0xbd, 0xed, 0xeb, 0xdb, 0xcf, 0xd2, 0xfa, 0xf6, 0xf3, 0x80, 0x59, 0x67, 0x1f,
0xbb, 0x3f, 0xe8, 0xfa, 0x33, 0x00, 0x00, 0xff, 0xff, 0xd1, 0x13, 0xbd, 0x1b, 0x52, 0x02, 0x00,
0x00,
}
+46
View File
@@ -0,0 +1,46 @@
syntax = "proto3";
package api;
// Client represents an OAuth2 client.
message Client {
string id = 1;
string secret = 2;
repeated string redirect_uris = 3;
repeated string trusted_peers = 4;
bool public = 5;
string name = 6;
string logo_url = 7;
}
// CreateClientReq is a request to make a client.
message CreateClientReq {
Client client = 1;
}
// CreateClientResp returns the response from creating a client.
message CreateClientResp {
bool already_exists = 1;
Client client = 2;
}
// DeleteClientReq is a request to delete a client.
message DeleteClientReq {
// The ID of the client.
string id = 1;
}
// DeleteClientResp determines if the.
message DeleteClientResp {
bool not_found = 1;
}
// TODO(ericchiang): expand this.
// Dex represents the dex gRPC service.
service Dex {
// CreateClient attempts to create the client.
rpc CreateClient(CreateClientReq) returns (CreateClientResp) {};
// DeleteClient attempts to delete the provided client.
rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
}
+9
View File
@@ -22,6 +22,7 @@ type Config struct {
Connectors []Connector `yaml:"connectors"`
Web Web `yaml:"web"`
OAuth2 OAuth2 `yaml:"oauth2"`
GRPC GRPC `yaml:"grpc"`
Templates server.TemplateConfig `yaml:"templates"`
@@ -41,6 +42,14 @@ type Web struct {
TLSKey string `yaml:"tlsKey"`
}
// GRPC is the config for the gRPC API.
type GRPC struct {
// The port to listen on.
Addr string `yaml:"addr"`
TLSCert string `yaml:"tlsCert"`
TLSKey string `yaml:"tlsKey"`
}
// Storage holds app's storage configuration.
type Storage struct {
Type string `yaml:"type"`
-1
View File
@@ -1 +0,0 @@
package main
+36 -5
View File
@@ -5,11 +5,15 @@ import (
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
yaml "gopkg.in/yaml.v2"
"github.com/coreos/dex/api"
"github.com/coreos/dex/server"
"github.com/coreos/dex/storage"
)
@@ -19,7 +23,7 @@ func commandServe() *cobra.Command {
Use: "serve [ config file ]",
Short: "Connect to the storage and begin serving requests.",
Long: ``,
Example: "dex serve c.yaml",
Example: "dex serve config.yaml",
RunE: serve,
}
}
@@ -56,6 +60,9 @@ func serve(cmd *cobra.Command, args []string) error {
{c.Web.HTTP == "" && c.Web.HTTPS == "", "must supply a HTTP/HTTPS address to listen on"},
{c.Web.HTTPS != "" && c.Web.TLSCert == "", "no cert specified for HTTPS"},
{c.Web.HTTPS != "" && c.Web.TLSKey == "", "no private key specified for HTTPS"},
{c.GRPC.TLSCert != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{c.GRPC.TLSKey != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{(c.GRPC.TLSCert == "") != (c.GRPC.TLSKey == ""), "must specific both a gRPC TLS cert and key"},
}
for _, check := range checks {
@@ -64,6 +71,15 @@ func serve(cmd *cobra.Command, args []string) error {
}
}
var grpcOptions []grpc.ServerOption
if c.GRPC.TLSCert != "" {
opt, err := credentials.NewServerTLSFromFile(c.GRPC.TLSCert, c.GRPC.TLSKey)
if err != nil {
return fmt.Errorf("load grpc certs: %v", err)
}
grpcOptions = append(grpcOptions, grpc.Creds(opt))
}
connectors := make([]server.Connector, len(c.Connectors))
for i, conn := range c.Connectors {
if conn.Config == nil {
@@ -96,22 +112,37 @@ func serve(cmd *cobra.Command, args []string) error {
TemplateConfig: c.Templates,
}
serv, err := server.New(serverConfig)
serv, err := server.NewServer(serverConfig)
if err != nil {
return fmt.Errorf("initializing server: %v", err)
}
errc := make(chan error, 2)
errc := make(chan error, 3)
if c.Web.HTTP != "" {
log.Printf("listening (http) on %s", c.Web.HTTP)
go func() {
log.Printf("listening on %s", c.Web.HTTP)
errc <- http.ListenAndServe(c.Web.HTTP, serv)
}()
}
if c.Web.HTTPS != "" {
log.Printf("listening (https) on %s", c.Web.HTTPS)
go func() {
log.Printf("listening on %s", c.Web.HTTPS)
errc <- http.ListenAndServeTLS(c.Web.HTTPS, c.Web.TLSCert, c.Web.TLSKey, serv)
}()
}
if c.GRPC.Addr != "" {
log.Printf("listening (grpc) on %s", c.GRPC.Addr)
go func() {
errc <- func() error {
list, err := net.Listen("tcp", c.GRPC.Addr)
if err != nil {
return fmt.Errorf("listen grpc: %v", err)
}
s := grpc.NewServer(grpcOptions...)
api.RegisterDexServer(s, server.NewAPI(serverConfig.Storage))
return s.Serve(list)
}()
}()
}
return <-errc
}
+29
View File
@@ -0,0 +1,29 @@
issuer: http://127.0.0.1:5556
storage:
type: sqlite3
config:
file: examples/dex.db
web:
http: 127.0.0.1:5556
grpc:
addr: 127.0.0.1:5557
connectors:
- type: mockCallback
id: mock-callback
name: Mock
- type: mockPassword
id: mock-password
name: Password
config:
username: "admin"
password: "PASSWORD"
staticClients:
- id: example-app
redirectURIs:
- 'http://127.0.0.1:5555/callback'
name: 'Example App'
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
Generated
+18 -2
View File
@@ -1,5 +1,5 @@
hash: 149c717bc83cc279ab6192364776b8c1b6bad8a620ce9d64c56d946276630437
updated: 2016-09-30T21:01:57.607704513-07:00
hash: 8b7a5f94584ecd144fc3ce94bb0b09f8e96c94b5a8e10d5053bd24bb597367ce
updated: 2016-10-03T23:25:41.280181088-07:00
imports:
- name: github.com/cockroachdb/cockroach-go
version: 31611c0501c812f437d4861d87d117053967c955
@@ -52,6 +52,11 @@ imports:
version: 6a513affb38dc9788b449d59ffed099b8de18fa0
subpackages:
- context
- http2
- http2/hpack
- internal/timeseries
- lex/httplex
- trace
- name: golang.org/x/oauth2
version: 08c8d727d2392d18286f9f88ad775ad98f09ab33
subpackages:
@@ -67,6 +72,17 @@ imports:
- internal/remote_api
- internal/urlfetch
- urlfetch
- name: google.golang.org/grpc
version: b1a2821ca5a4fd6b6e48ddfbb7d6d7584d839d21
subpackages:
- codes
- credentials
- grpclog
- internal
- metadata
- naming
- peer
- transport
- name: gopkg.in/asn1-ber.v1
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
- name: gopkg.in/ldap.v2
+18
View File
@@ -26,6 +26,11 @@ import:
version: 6a513affb38dc9788b449d59ffed099b8de18fa0
subpackages:
- context
- http2
- http2/hpack
- internal/timeseries
- lex/httplex
- trace
- package: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
@@ -89,3 +94,16 @@ import:
version: 31611c0501c812f437d4861d87d117053967c955
subpackages:
- crdb
# gRPC also imports protobuf and the x/net/http2 stack.
- package: google.golang.org/grpc
version: b1a2821ca5a4fd6b6e48ddfbb7d6d7584d839d21
subpackages:
- codes
- credentials
- grpclog
- internal
- metadata
- naming
- peer
- transport
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash -e
# This is a script to download protoc. Rather than depending on the version on
# a developer's machine, always download a specific version.
VERSION="3.1.0"
if [ $# -ne 1 ]; then
echo "Usage: ./get-protoc [dest]"
exit 2
fi
# Use the go tool to determine OS.
OS=$( go env GOOS )
if [ "$OS" = "darwin" ]; then
OS="osx"
fi
# TODO(ericchiang): Architectures other than amd64?
ZIP="protoc-${VERSION}-${OS}-x86_64.zip"
URL="https://github.com/google/protobuf/releases/download/v${VERSION}/${ZIP}"
wget ${URL}
# Unpack the protoc binary. Later we might want to grab additional data.
unzip -p ${ZIP} bin/protoc > $1
chmod +x $1
rm ${ZIP}
+64
View File
@@ -0,0 +1,64 @@
package server
import (
"errors"
"log"
"golang.org/x/net/context"
"github.com/coreos/dex/api"
"github.com/coreos/dex/storage"
)
// NewAPI returns a server which implements the gRPC API interface.
func NewAPI(s storage.Storage) api.DexServer {
return dexAPI{s: s}
}
type dexAPI struct {
s storage.Storage
}
func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*api.CreateClientResp, error) {
if req.Client == nil {
return nil, errors.New("no client supplied")
}
if req.Client.Id == "" {
req.Client.Id = storage.NewID()
}
if req.Client.Secret == "" {
req.Client.Secret = storage.NewID() + storage.NewID()
}
c := storage.Client{
ID: req.Client.Id,
Secret: req.Client.Secret,
RedirectURIs: req.Client.RedirectUris,
TrustedPeers: req.Client.TrustedPeers,
Public: req.Client.Public,
Name: req.Client.Name,
LogoURL: req.Client.LogoUrl,
}
if err := d.s.CreateClient(c); err != nil {
log.Printf("api: failed to create client: %v", err)
// TODO(ericchiang): Surface "already exists" errors.
return nil, err
}
return &api.CreateClientResp{
Client: req.Client,
}, nil
}
func (d dexAPI) DeleteClient(ctx context.Context, req *api.DeleteClientReq) (*api.DeleteClientResp, error) {
err := d.s.DeleteClient(req.Id)
if err != nil {
if err == storage.ErrNotFound {
return &api.DeleteClientResp{NotFound: true}, nil
}
log.Printf("api: failed to delete client: %v", err)
return nil, err
}
return &api.DeleteClientResp{}, nil
}
+1
View File
@@ -0,0 +1 @@
package server
+2 -2
View File
@@ -78,8 +78,8 @@ type Server struct {
idTokensValidFor time.Duration
}
// New constructs a server from the provided config.
func New(c Config) (*Server, error) {
// NewServer constructs a server from the provided config.
func NewServer(c Config) (*Server, error) {
return newServer(c, defaultRotationStrategy(
value(c.RotateKeysAfter, 6*time.Hour),
value(c.IDTokensValidFor, 24*time.Hour),
+18
View File
@@ -0,0 +1,18 @@
language: go
go:
- 1.5.4
- 1.6.3
- 1.7
go_import_path: google.golang.org/grpc
before_install:
- go get -u golang.org/x/tools/cmd/goimports github.com/golang/lint/golint github.com/axw/gocov/gocov github.com/mattn/goveralls golang.org/x/tools/cmd/cover
script:
- '! gofmt -s -d -l . 2>&1 | read'
- '! goimports -l . | read'
- '! golint ./... | grep -vE "(_string|\.pb)\.go:"'
- '! go tool vet -all . 2>&1 | grep -vE "constant [0-9]+ not a string in call to Errorf" | grep -vF .pb.go:' # https://github.com/golang/protobuf/issues/214
- make test testrace
+46
View File
@@ -0,0 +1,46 @@
# How to contribute
We definitely welcome patches and contribution to grpc! Here are some guidelines
and information about how to do so.
## Sending patches
### Getting started
1. Check out the code:
$ go get google.golang.org/grpc
$ cd $GOPATH/src/google.golang.org/grpc
1. Create a fork of the grpc-go repository.
1. Add your fork as a remote:
$ git remote add fork git@github.com:$YOURGITHUBUSERNAME/grpc-go.git
1. Make changes, commit them.
1. Run the test suite:
$ make test
1. Push your changes to your fork:
$ git push fork ...
1. Open a pull request.
## Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
## Filing Issues
When filing an issue, make sure to answer these five questions:
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
### Contributing code
Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file.
+41
View File
@@ -0,0 +1,41 @@
# Authentication
As outlined in the [gRPC authentication guide](http://www.grpc.io/docs/guides/auth.html) there are a number of different mechanisms for asserting identity between an client and server. We'll present some code-samples here demonstrating how to provide TLS support encryption and identity assertions as well as passing OAuth2 tokens to services that support it.
# Enabling TLS on a gRPC client
```Go
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")))
```
# Enabling TLS on a gRPC server
```Go
creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
if err != nil {
log.Fatalf("Failed to generate credentials %v", err)
}
lis, err := net.Listen("tcp", ":0")
server := grpc.NewServer(grpc.Creds(creds))
...
server.Serve(lis)
```
# Authenticating with Google
## Google Compute Engine (GCE)
```Go
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, ""), grpc.WithPerRPCCredentials(oauth.NewComputeEngine())))
```
## JWT
```Go
jwtCreds, err := oauth.NewServiceAccountFromFile(*serviceAccountKeyFile, *oauthScope)
if err != nil {
log.Fatalf("Failed to create JWT credentials: %v", err)
}
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, ""), grpc.WithPerRPCCredentials(jwtCreds)))
```
+201
View File
@@ -0,0 +1,201 @@
# Metadata
gRPC supports sending metadata between client and server.
This doc shows how to send and receive metadata in gRPC-go.
## Background
Four kinds of service method:
- [Unary RPC](http://www.grpc.io/docs/guides/concepts.html#unary-rpc)
- [Server streaming RPC](http://www.grpc.io/docs/guides/concepts.html#server-streaming-rpc)
- [Client streaming RPC](http://www.grpc.io/docs/guides/concepts.html#client-streaming-rpc)
- [Bidirectional streaming RPC](http://www.grpc.io/docs/guides/concepts.html#bidirectional-streaming-rpc)
And concept of [metadata](http://www.grpc.io/docs/guides/concepts.html#metadata).
## Constructing metadata
A metadata can be created using package [metadata](https://godoc.org/google.golang.org/grpc/metadata).
The type MD is actually a map from string to a list of strings:
```go
type MD map[string][]string
```
Metadata can be read like a normal map.
Note that the value type of this map is `[]string`,
so that users can attach multiple values using a single key.
### Creating a new metadata
A metadata can be created from a `map[string]string` using function `New`:
```go
md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})
```
Another way is to use `Pairs`.
Values with the same key will be merged into a list:
```go
md := metadata.Pairs(
"key1", "val1",
"key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
"key2", "val2",
)
```
__Note:__ all the keys will be automatically converted to lowercase,
so "key1" and "kEy1" will be the same key and their values will be merged into the same list.
This happens for both `New` and `Pairs`.
### Storing binary data in metadata
In metadata, keys are always strings. But values can be strings or binary data.
To store binary data value in metadata, simply add "-bin" suffix to the key.
The values with "-bin" suffixed keys will be encoded when creating the metadata:
```go
md := metadata.Pairs(
"key", "string value",
"key-bin", string([]byte{96, 102}), // this binary data will be encoded (base64) before sending
// and will be decoded after being transferred.
)
```
## Retrieving metadata from context
Metadata can be retrieved from context using `FromContext`:
```go
func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
md, ok := metadata.FromContext(ctx)
// do something with metadata
}
```
## Sending and receiving metadata - client side
[//]: # "TODO: uncomment next line after example source added"
[//]: # "Real metadata sending and receiving examples are available [here](TODO:example_dir)."
### Sending metadata
To send metadata to server, the client can wrap the metadata into a context using `NewContext`, and make the RPC with this context:
```go
md := metadata.Pairs("key", "val")
// create a new context with this metadata
ctx := metadata.NewContext(context.Background(), md)
// make unary RPC
response, err := client.SomeRPC(ctx, someRequest)
// or make streaming RPC
stream, err := client.SomeStreamingRPC(ctx)
```
### Receiving metadata
Metadata that a client can receive includes header and trailer.
#### Unary call
Header and trailer sent along with a unary call can be retrieved using function [Header](https://godoc.org/google.golang.org/grpc#Header) and [Trailer](https://godoc.org/google.golang.org/grpc#Trailer) in [CallOption](https://godoc.org/google.golang.org/grpc#CallOption):
```go
var header, trailer metadata.MD // variable to store header and trailer
r, err := client.SomeRPC(
ctx,
someRequest,
grpc.Header(&header), // will retrieve header
grpc.Trailer(&trailer), // will retrieve trailer
)
// do something with header and trailer
```
#### Streaming call
For streaming calls including:
- Server streaming RPC
- Client streaming RPC
- Bidirectional streaming RPC
Header and trailer can be retrieved from the returned stream using function `Header` and `Trailer` in interface [ClientStream](https://godoc.org/google.golang.org/grpc#ClientStream):
```go
stream, err := client.SomeStreamingRPC(ctx)
// retrieve header
header, err := stream.Header()
// retrieve trailer
trailer := stream.Trailer()
```
## Sending and receiving metadata - server side
[//]: # "TODO: uncomment next line after example source added"
[//]: # "Real metadata sending and receiving examples are available [here](TODO:example_dir)."
### Receiving metadata
To read metadata sent by the client, the server needs to retrieve it from RPC context.
If it is a unary call, the RPC handler's context can be used.
For streaming calls, the server needs to get context from the stream.
#### Unary call
```go
func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
md, ok := metadata.FromContext(ctx)
// do something with metadata
}
```
#### Streaming call
```go
func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
md, ok := metadata.FromContext(stream.Context()) // get context from stream
// do something with metadata
}
```
### Sending metadata
#### Unary call
To send header and trailer to client in unary call, the server can call [SendHeader](https://godoc.org/google.golang.org/grpc#SendHeader) and [SetTrailer](https://godoc.org/google.golang.org/grpc#SetTrailer) functions in module [grpc](https://godoc.org/google.golang.org/grpc).
These two functions take a context as the first parameter.
It should be the RPC handler's context or one derived from it:
```go
func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
// create and send header
header := metadata.Pairs("header-key", "val")
grpc.SendHeader(ctx, header)
// create and set trailer
trailer := metadata.Pairs("trailer-key", "val")
grpc.SetTrailer(ctx, trailer)
}
```
#### Streaming call
For streaming calls, header and trailer can be sent using function `SendHeader` and `SetTrailer` in interface [ServerStream](https://godoc.org/google.golang.org/grpc#ServerStream):
```go
func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
// create and send header
header := metadata.Pairs("header-key", "val")
stream.SendHeader(header)
// create and set trailer
trailer := metadata.Pairs("trailer-key", "val")
stream.SetTrailer(trailer)
}
```
+28
View File
@@ -0,0 +1,28 @@
Copyright 2014, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+52
View File
@@ -0,0 +1,52 @@
all: test testrace
deps:
go get -d -v google.golang.org/grpc/...
updatedeps:
go get -d -v -u -f google.golang.org/grpc/...
testdeps:
go get -d -v -t google.golang.org/grpc/...
updatetestdeps:
go get -d -v -t -u -f google.golang.org/grpc/...
build: deps
go build google.golang.org/grpc/...
proto:
@ if ! which protoc > /dev/null; then \
echo "error: protoc not installed" >&2; \
exit 1; \
fi
go get -u -v github.com/golang/protobuf/protoc-gen-go
# use $$dir as the root for all proto files in the same directory
for dir in $$(git ls-files '*.proto' | xargs -n1 dirname | uniq); do \
protoc -I $$dir --go_out=plugins=grpc:$$dir $$dir/*.proto; \
done
test: testdeps
go test -v -cpu 1,4 google.golang.org/grpc/...
testrace: testdeps
go test -v -race -cpu 1,4 google.golang.org/grpc/...
clean:
go clean -i google.golang.org/grpc/...
coverage: testdeps
./coverage.sh --coveralls
.PHONY: \
all \
deps \
updatedeps \
testdeps \
updatetestdeps \
build \
proto \
test \
testrace \
clean \
coverage

Some files were not shown because too many files have changed in this diff Show More