github.com/orange-cloudfoundry/cli@v7.1.0+incompatible/api/uaa/auth.go (about)

     1  package uaa
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"errors"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  
    11  	"code.cloudfoundry.org/cli/api/uaa/constant"
    12  	"code.cloudfoundry.org/cli/api/uaa/internal"
    13  )
    14  
    15  // AuthResponse contains the access token and refresh token which are granted
    16  // after UAA has authorized a user.
    17  type AuthResponse struct {
    18  	AccessToken  string `json:"access_token"`
    19  	RefreshToken string `json:"refresh_token"`
    20  }
    21  
    22  // Authenticate sends a username and password to UAA then returns an access
    23  // token and a refresh token.
    24  func (client Client) Authenticate(creds map[string]string, origin string, grantType constant.GrantType) (string, string, error) {
    25  	requestBody := url.Values{
    26  		"grant_type": {string(grantType)},
    27  	}
    28  
    29  	for k, v := range creds {
    30  		requestBody.Set(k, v)
    31  	}
    32  
    33  	type loginHint struct {
    34  		Origin string `json:"origin"`
    35  	}
    36  
    37  	originStruct := loginHint{origin}
    38  	originParam, err := json.Marshal(originStruct)
    39  	if err != nil {
    40  		return "", "", err
    41  	}
    42  
    43  	var query url.Values
    44  	if origin != "" {
    45  		query = url.Values{
    46  			"login_hint": {string(originParam)},
    47  		}
    48  	}
    49  
    50  	request, err := client.newRequest(requestOptions{
    51  		RequestName: internal.PostOAuthTokenRequest,
    52  		Header: http.Header{
    53  			"Content-Type": {"application/x-www-form-urlencoded"},
    54  		},
    55  		Body:  strings.NewReader(requestBody.Encode()),
    56  		Query: query,
    57  	})
    58  
    59  	if err != nil {
    60  		return "", "", err
    61  	}
    62  
    63  	if grantType == constant.GrantTypePassword {
    64  		request.SetBasicAuth(client.config.UAAOAuthClient(), client.config.UAAOAuthClientSecret())
    65  	}
    66  
    67  	responseBody := AuthResponse{}
    68  	response := Response{
    69  		Result: &responseBody,
    70  	}
    71  
    72  	err = client.connection.Make(request, &response)
    73  	return responseBody.AccessToken, responseBody.RefreshToken, err
    74  }
    75  
    76  func (client Client) Revoke(token string) error {
    77  	jti, err := client.getJtiFromToken(token)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	revokeRequest, err := client.newRequest(requestOptions{
    83  		RequestName: internal.DeleteTokenRequest,
    84  		URIParams: map[string]string{
    85  			"token_id": jti,
    86  		},
    87  	})
    88  	revokeRequest.Header.Set("Authorization", "Bearer "+token)
    89  
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	err = client.connection.Make(revokeRequest, &Response{})
    95  	return err
    96  }
    97  
    98  func (client Client) getJtiFromToken(token string) (string, error) {
    99  	segments := strings.Split(token, ".")
   100  
   101  	if len(segments) < 2 {
   102  		return "", errors.New("access token missing segments")
   103  	}
   104  
   105  	jsonPayload, err := base64.RawURLEncoding.DecodeString(segments[1])
   106  
   107  	if err != nil {
   108  		return "", errors.New("could not base64 decode token payload")
   109  	}
   110  
   111  	payload := make(map[string]interface{})
   112  	json.Unmarshal(jsonPayload, &payload)
   113  	jti, ok := payload["jti"].(string)
   114  
   115  	if !ok {
   116  		return "", errors.New("could not parse jti from payload")
   117  	}
   118  
   119  	return jti, nil
   120  }