main.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. *
  3. * Copyright 2018 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // The server demonstrates how to consume and validate OAuth2 tokens provided by
  19. // clients for each RPC.
  20. package main
  21. import (
  22. "context"
  23. "crypto/tls"
  24. "log"
  25. "net"
  26. "strings"
  27. "google.golang.org/grpc"
  28. "google.golang.org/grpc/codes"
  29. "google.golang.org/grpc/credentials"
  30. pb "google.golang.org/grpc/examples/helloworld/helloworld"
  31. "google.golang.org/grpc/metadata"
  32. "google.golang.org/grpc/status"
  33. "google.golang.org/grpc/testdata"
  34. )
  35. var (
  36. errMissingMetadata = status.Errorf(codes.InvalidArgument, "missing metadata")
  37. errInvalidToken = status.Errorf(codes.Unauthenticated, "invalid token")
  38. )
  39. func main() {
  40. log.Println("server starting on port 8080...")
  41. cert, err := tls.LoadX509KeyPair(testdata.Path("server1.pem"), testdata.Path("server1.key"))
  42. if err != nil {
  43. log.Fatalf("failed to load key pair: %s", err)
  44. }
  45. opts := []grpc.ServerOption{
  46. // The following grpc.ServerOption adds an interceptor for all unary
  47. // RPCs. To configure an interceptor for streaming RPCs, see:
  48. // https://godoc.org/google.golang.org/grpc#StreamInterceptor
  49. grpc.UnaryInterceptor(ensureValidToken),
  50. // Enable TLS for all incoming connections.
  51. grpc.Creds(credentials.NewServerTLSFromCert(&cert)),
  52. }
  53. s := grpc.NewServer(opts...)
  54. pb.RegisterGreeterServer(s, &server{})
  55. lis, err := net.Listen("tcp", ":8080")
  56. if err != nil {
  57. log.Fatalf("failed to listen: %v", err)
  58. }
  59. if err := s.Serve(lis); err != nil {
  60. log.Fatalf("failed to serve: %v", err)
  61. }
  62. }
  63. // server is used to implement helloworld.GreeterServer.
  64. type server struct{}
  65. // SayHello implements helloworld.GreeterServer
  66. func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
  67. return &pb.HelloReply{Message: "Hello " + in.Name}, nil
  68. }
  69. // valid validates the authorization.
  70. func valid(authorization []string) bool {
  71. if len(authorization) < 1 {
  72. return false
  73. }
  74. token := strings.TrimPrefix(authorization[0], "Bearer ")
  75. // Perform the token validation here. For the sake of this example, the code
  76. // here forgoes any of the usual OAuth2 token validation and instead checks
  77. // for a token matching an arbitrary string.
  78. if token != "some-secret-token" {
  79. return false
  80. }
  81. return true
  82. }
  83. // ensureValidToken ensures a valid token exists within a request's metadata. If
  84. // the token is missing or invalid, the interceptor blocks execution of the
  85. // handler and returns an error. Otherwise, the interceptor invokes the unary
  86. // handler.
  87. func ensureValidToken(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
  88. md, ok := metadata.FromIncomingContext(ctx)
  89. if !ok {
  90. return nil, errMissingMetadata
  91. }
  92. // The keys within metadata.MD are normalized to lowercase.
  93. // See: https://godoc.org/google.golang.org/grpc/metadata#New
  94. if !valid(md["authorization"]) {
  95. return nil, errInvalidToken
  96. }
  97. // Continue execution of handler after ensuring a valid token.
  98. return handler(ctx, req)
  99. }