diff --git a/cmd/drone-agent/agent.go b/cmd/drone-agent/agent.go index 6319055b9..359538f93 100644 --- a/cmd/drone-agent/agent.go +++ b/cmd/drone-agent/agent.go @@ -21,15 +21,10 @@ import ( "github.com/tevino/abool" "github.com/urfave/cli" + oldcontext "golang.org/x/net/context" ) func loop(c *cli.Context) error { - // endpoint, err := url.Parse( - // c.String("drone-server"), - // ) - // if err != nil { - // return err - // } filter := rpc.Filter{ Labels: map[string]string{ "platform": c.String("platform"), @@ -39,9 +34,15 @@ func loop(c *cli.Context) error { // TODO pass version information to grpc server // TODO authenticate to grpc server + // grpc.Dial(target, )) + conn, err := grpc.Dial( c.String("server"), grpc.WithInsecure(), + grpc.WithPerRPCCredentials(&credentials{ + username: c.String("username"), + password: c.String("password"), + }), ) if err != nil { return err @@ -282,3 +283,19 @@ func run(ctx context.Context, client rpc.Peer, filter rpc.Filter) error { return nil } + +type credentials struct { + username string + password string +} + +func (c *credentials) GetRequestMetadata(oldcontext.Context, ...string) (map[string]string, error) { + return map[string]string{ + "username": c.username, + "password": c.password, + }, nil +} + +func (c *credentials) RequireTransportSecurity() bool { + return false +} diff --git a/cmd/drone-agent/main.go b/cmd/drone-agent/main.go index aeff90e82..a1955f591 100644 --- a/cmd/drone-agent/main.go +++ b/cmd/drone-agent/main.go @@ -24,9 +24,15 @@ func main() { Value: "localhost:9000", }, cli.StringFlag{ - EnvVar: "DRONE_SECRET", - Name: "secret", - Usage: "drone agent secret", + EnvVar: "DRONE_USERNAME", + Name: "username", + Usage: "drone auth username", + Value: "x-oauth-basic", + }, + cli.StringFlag{ + EnvVar: "DRONE_PASSWORD,DRONE_SECRET", + Name: "password", + Usage: "drone auth password", }, cli.BoolFlag{ EnvVar: "DRONE_DEBUG", diff --git a/cmd/drone-server/server.go b/cmd/drone-server/server.go index 3c0a04bc6..0f75169ee 100644 --- a/cmd/drone-server/server.go +++ b/cmd/drone-server/server.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "net" "net/http" "net/url" @@ -9,6 +10,7 @@ import ( "time" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "golang.org/x/crypto/acme/autocert" "golang.org/x/sync/errgroup" @@ -28,6 +30,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/gin-gonic/contrib/ginrus" "github.com/urfave/cli" + oldcontext "golang.org/x/net/context" ) var flags = []cli.Flag{ @@ -422,7 +425,13 @@ func server(c *cli.Context) error { logrus.Error(err) return err } - s := grpc.NewServer() + auther := &authorizer{ + password: c.String("agent-secret"), + } + s := grpc.NewServer( + grpc.StreamInterceptor(auther.streamInterceptor), + grpc.UnaryInterceptor(auther.unaryIntercaptor), + ) ss := new(droneserver.DroneServer) ss.Queue = droneserver.Config.Services.Queue ss.Logger = droneserver.Config.Services.Logs @@ -527,3 +536,32 @@ func setupEvilGlobals(c *cli.Context, v store.Store, r remote.Remote) { // droneserver.Config.Server.Orgs = sliceToMap(cli.StringSlice("orgs")) // droneserver.Config.Server.Admins = sliceToMap(cli.StringSlice("admin")) } + +type authorizer struct { + username string + password string +} + +func (a *authorizer) streamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + if err := a.authorize(stream.Context()); err != nil { + return err + } + return handler(srv, stream) +} + +func (a *authorizer) unaryIntercaptor(ctx oldcontext.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + if err := a.authorize(ctx); err != nil { + return nil, err + } + return handler(ctx, req) +} + +func (a *authorizer) authorize(ctx context.Context) error { + if md, ok := metadata.FromContext(ctx); ok { + if len(md["password"]) > 0 && md["password"][0] == a.password { + return nil + } + return errors.New("invalid agent token") + } + return errors.New("missing agent token") +}