Advertisement
malusevd998

gRPC Authentication Interceptor

Jun 27th, 2021
1,105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 3.27 KB | None | 0 0
  1. package middleware
  2.  
  3. import (
  4.     "context"
  5.     "errors"
  6.     "sort"
  7.     "strings"
  8.  
  9.     "github.com/rs/zerolog/log"
  10.     "google.golang.org/grpc"
  11.     "google.golang.org/grpc/codes"
  12.     "google.golang.org/grpc/metadata"
  13.     "google.golang.org/grpc/status"
  14.  
  15.     "github.com/BrosSquad/ts-1-chat-app/backend/services/auth"
  16. )
  17.  
  18. type AuthConfig struct {
  19.     Allowed sort.StringSlice
  20.     Blocked sort.StringSlice
  21. }
  22.  
  23. func authCheck(ctx context.Context, token, method string, config *AuthConfig, tokenService auth.TokenService) error {
  24.     blockedLen := len(config.Blocked)
  25.     allowedLen := len(config.Allowed)
  26.  
  27.     // Both lists are empty, everything should go through
  28.     if blockedLen == 0 && allowedLen == 0 {
  29.         return nil
  30.     }
  31.  
  32.     if blockedLen != 0 {
  33.         idx := config.Blocked.Search(method)
  34.  
  35.         // Found in blacklist
  36.         if idx != blockedLen {
  37.             return tokenService.Verify(ctx, token)
  38.         }
  39.  
  40.         // If not found in blacklist, then it is allowed to pass
  41.         return nil
  42.     }
  43.  
  44.     if allowedLen != 0 {
  45.         idx := config.Allowed.Search(method)
  46.  
  47.         // Found in whitelist
  48.         if idx != allowedLen {
  49.             return nil
  50.         }
  51.     }
  52.  
  53.     // If not found in whitelist, then token must be checked
  54.     return tokenService.Verify(ctx, token)
  55. }
  56.  
  57. func extractToken(ctx context.Context) (string, error) {
  58.     md, ok := metadata.FromIncomingContext(ctx)
  59.  
  60.     if !ok {
  61.         return "", errors.New("metadata not found")
  62.     }
  63.  
  64.     header := md.Get("authorization")
  65.  
  66.     if len(header) != 1 {
  67.         return "", errors.New("authorization header not found")
  68.     }
  69.  
  70.     typeAndToken := strings.SplitN(header[0], " ", 1)
  71.  
  72.     if len(typeAndToken) != 2 {
  73.         return "", errors.New("authorization token invalid format: $TOKEN_TYPE$ $TOKEN$")
  74.     }
  75.  
  76.     return typeAndToken[1], nil
  77. }
  78.  
  79. func UnaryAuth(config AuthConfig, tokenService auth.TokenService) grpc.UnaryServerInterceptor {
  80.     if len(config.Blocked) != 0 && len(config.Allowed) != 0 {
  81.         log.Fatal().Msg("Use either whitelist or blacklist")
  82.     }
  83.  
  84.     return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
  85.         method, exist := grpc.Method(ctx)
  86.  
  87.         if !exist {
  88.             return nil, status.Error(codes.Unauthenticated, "unauthenticated")
  89.         }
  90.  
  91.         log.Debug().Str("method", method).Msg("Unary Request method name")
  92.  
  93.         token, err := extractToken(ctx)
  94.  
  95.         if err != nil {
  96.             return nil, status.Error(codes.Unauthenticated, err.Error())
  97.         }
  98.  
  99.         if err := authCheck(ctx, token, method, &config, tokenService); err != nil {
  100.             return nil, status.Error(codes.Unauthenticated, "unauthenticated")
  101.         }
  102.  
  103.         return handler(ctx, req)
  104.     }
  105. }
  106.  
  107. func StreamAuth(config AuthConfig, tokenService auth.TokenService) grpc.StreamServerInterceptor {
  108.     return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
  109.         method, exist := grpc.MethodFromServerStream(ss)
  110.  
  111.         if !exist {
  112.             return status.Error(codes.Unauthenticated, "unauthenticated")
  113.         }
  114.  
  115.         log.Debug().Str("method", method).Msg("Stream Request method name")
  116.  
  117.         token, err := extractToken(ss.Context())
  118.  
  119.         if err != nil {
  120.             return status.Error(codes.Unauthenticated, err.Error())
  121.         }
  122.  
  123.         if err := authCheck(ss.Context(), token, method, &config, tokenService); err != nil {
  124.             return status.Error(codes.Unauthenticated, "unauthenticated")
  125.         }
  126.  
  127.         return handler(srv, ss)
  128.     }
  129. }
  130.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement