github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/proxy/server/auth.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	"github.com/tickoalcantara12/micro/v3/service/auth"
     8  	"github.com/tickoalcantara12/micro/v3/service/context/metadata"
     9  	"github.com/tickoalcantara12/micro/v3/service/errors"
    10  	"github.com/tickoalcantara12/micro/v3/service/server"
    11  	inauth "github.com/tickoalcantara12/micro/v3/util/auth"
    12  	"github.com/tickoalcantara12/micro/v3/util/auth/namespace"
    13  )
    14  
    15  // authHandler wraps a server handler to perform auth
    16  func authHandler() server.HandlerWrapper {
    17  	return func(h server.HandlerFunc) server.HandlerFunc {
    18  		return func(ctx context.Context, req server.Request, rsp interface{}) error {
    19  			// Extract the token if the header is present. We will inspect the token regardless of if it's
    20  			// present or not since noop auth will return a blank account upon Inspecting a blank token.
    21  			var token string
    22  			if header, ok := metadata.Get(ctx, "Authorization"); ok {
    23  				// Ensure the correct scheme is being used
    24  				if !strings.HasPrefix(header, inauth.BearerScheme) {
    25  					return errors.Unauthorized(req.Service(), "invalid authorization header. expected Bearer schema")
    26  				}
    27  
    28  				// Strip the bearer scheme prefix
    29  				token = strings.TrimPrefix(header, inauth.BearerScheme)
    30  			}
    31  
    32  			// Inspect the token and decode an account
    33  			account, _ := auth.Inspect(token)
    34  
    35  			// Extract the namespace header
    36  			ns, ok := metadata.Get(ctx, "Micro-Namespace")
    37  			if !ok && account != nil {
    38  				ns = account.Issuer
    39  				ctx = metadata.Set(ctx, "Micro-Namespace", ns)
    40  			} else if !ok {
    41  				ns = namespace.DefaultNamespace
    42  				ctx = metadata.Set(ctx, "Micro-Namespace", ns)
    43  			}
    44  
    45  			// construct the resource
    46  			res := &auth.Resource{
    47  				Type:     "service",
    48  				Name:     req.Service(),
    49  				Endpoint: req.Endpoint(),
    50  			}
    51  
    52  			// Verify the caller has access to the resource.
    53  			err := auth.Verify(account, res, auth.VerifyNamespace(ns))
    54  			if err == auth.ErrForbidden && account != nil {
    55  				return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID)
    56  			} else if err == auth.ErrForbidden {
    57  				return errors.Unauthorized(req.Service(), "Unauthorized call made to %v:%v", req.Service(), req.Endpoint())
    58  			} else if err != nil {
    59  				return errors.InternalServerError("proxy", "Error authorizing request: %v", err)
    60  			}
    61  
    62  			// The user is authorised, allow the call
    63  			return h(ctx, req, rsp)
    64  		}
    65  	}
    66  }