github.com/hellofresh/janus@v0.0.0-20230925145208-ce8de8183c67/pkg/plugin/oauth2/oauth_introspection.go (about)

     1  package oauth2
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  
    10  	log "github.com/sirupsen/logrus"
    11  
    12  	"github.com/hellofresh/janus/pkg/proxy"
    13  	"github.com/hellofresh/janus/pkg/proxy/balancer"
    14  )
    15  
    16  type oAuthResponse struct {
    17  	Active bool `json:"active"`
    18  }
    19  
    20  // IntrospectionManager is responsible for using OAuth2 Introspection definition to
    21  // validate tokens from an authentication provider
    22  type IntrospectionManager struct {
    23  	balancer balancer.Balancer
    24  	urls     proxy.Targets
    25  	settings *IntrospectionSettings
    26  }
    27  
    28  // NewIntrospectionManager creates a new instance of Introspection
    29  func NewIntrospectionManager(def *proxy.Definition, settings *IntrospectionSettings) (*IntrospectionManager, error) {
    30  	bb, err := balancer.New(def.Upstreams.Balancing)
    31  	if err != nil {
    32  		return nil, fmt.Errorf("could not create a bb: %w", err)
    33  	}
    34  
    35  	return &IntrospectionManager{bb, def.Upstreams.Targets, settings}, nil
    36  }
    37  
    38  // IsKeyAuthorized checks if the access token is valid
    39  func (o *IntrospectionManager) IsKeyAuthorized(ctx context.Context, accessToken string) bool {
    40  	resp, err := o.doStatusRequest(accessToken)
    41  	defer resp.Body.Close()
    42  
    43  	if err != nil {
    44  		log.WithError(err).
    45  			Error("Error making a request to the authentication provider")
    46  	}
    47  
    48  	if resp.StatusCode != http.StatusOK {
    49  		log.Info("The token check was invalid")
    50  		return false
    51  	}
    52  
    53  	var oauthResp oAuthResponse
    54  	decoder := json.NewDecoder(resp.Body)
    55  	err = decoder.Decode(&oauthResp)
    56  	if err != nil {
    57  		return false
    58  	}
    59  
    60  	return oauthResp.Active
    61  }
    62  
    63  func (o *IntrospectionManager) doStatusRequest(accessToken string) (*http.Response, error) {
    64  	upstream, err := o.balancer.Elect(o.urls.ToBalancerTargets())
    65  	if err != nil {
    66  		return nil, fmt.Errorf("could not elect one upstream: %w", err)
    67  	}
    68  
    69  	req, err := http.NewRequest(http.MethodGet, upstream.Target, nil)
    70  	if err != nil {
    71  		log.WithError(err).Error("Creating the request for the health check failed")
    72  		return nil, err
    73  	}
    74  
    75  	if o.settings.UseAuthHeader {
    76  		req.Header.Add("Authorization", fmt.Sprintf("%s %s", o.settings.AuthHeaderType, accessToken))
    77  	} else if o.settings.UseCustomHeader {
    78  		req.Header.Add(o.settings.HeaderName, accessToken)
    79  	} else {
    80  		req.Form = make(url.Values)
    81  		req.Form.Add(o.settings.ParamName, accessToken)
    82  	}
    83  
    84  	// Inform to close the connection after the transaction is complete
    85  	req.Header.Set("Connection", "close")
    86  
    87  	resp, err := http.DefaultClient.Do(req)
    88  	if err != nil {
    89  		log.WithError(err).Error("Making the request for the health check failed")
    90  		return resp, err
    91  	}
    92  
    93  	return resp, err
    94  }