...

Source file src/github.com/ory/fosite/revoke_handler.go

Documentation: github.com/ory/fosite

     1  /*
     2   * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   *
    20   */
    21  
    22  package fosite
    23  
    24  import (
    25  	"context"
    26  	"encoding/json"
    27  	"fmt"
    28  	"net/http"
    29  
    30  	"github.com/ory/x/errorsx"
    31  
    32  	"github.com/pkg/errors"
    33  )
    34  
    35  // NewRevocationRequest handles incoming token revocation requests and
    36  // validates various parameters as specified in:
    37  // https://tools.ietf.org/html/rfc7009#section-2.1
    38  //
    39  // The authorization server first validates the client credentials (in
    40  // case of a confidential client) and then verifies whether the token
    41  // was issued to the client making the revocation request.  If this
    42  // validation fails, the request is refused and the client is informed
    43  // of the error by the authorization server as described below.
    44  //
    45  // In the next step, the authorization server invalidates the token.
    46  // The invalidation takes place immediately, and the token cannot be
    47  // used again after the revocation.
    48  //
    49  // * https://tools.ietf.org/html/rfc7009#section-2.2
    50  // An invalid token type hint value is ignored by the authorization
    51  // server and does not influence the revocation response.
    52  func (f *Fosite) NewRevocationRequest(ctx context.Context, r *http.Request) error {
    53  	ctx = context.WithValue(ctx, RequestContextKey, r)
    54  
    55  	if r.Method != "POST" {
    56  		return errorsx.WithStack(ErrInvalidRequest.WithHintf("HTTP method is '%s' but expected 'POST'.", r.Method))
    57  	} else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart {
    58  		return errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error()))
    59  	} else if len(r.PostForm) == 0 {
    60  		return errorsx.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty."))
    61  	}
    62  
    63  	client, err := f.AuthenticateClient(ctx, r, r.PostForm)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	token := r.PostForm.Get("token")
    69  	tokenTypeHint := TokenType(r.PostForm.Get("token_type_hint"))
    70  
    71  	var found = false
    72  	for _, loader := range f.RevocationHandlers {
    73  		if err := loader.RevokeToken(ctx, token, tokenTypeHint, client); err == nil {
    74  			found = true
    75  		} else if errors.Is(err, ErrUnknownRequest) {
    76  			// do nothing
    77  		} else if err != nil {
    78  			return err
    79  		}
    80  	}
    81  
    82  	if !found {
    83  		return errorsx.WithStack(ErrInvalidRequest)
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  // WriteRevocationResponse writes a token revocation response as specified in:
    90  // https://tools.ietf.org/html/rfc7009#section-2.2
    91  //
    92  // The authorization server responds with HTTP status code 200 if the
    93  // token has been revoked successfully or if the client submitted an
    94  // invalid token.
    95  //
    96  // Note: invalid tokens do not cause an error response since the client
    97  // cannot handle such an error in a reasonable way.  Moreover, the
    98  // purpose of the revocation request, invalidating the particular token,
    99  // is already achieved.
   100  func (f *Fosite) WriteRevocationResponse(rw http.ResponseWriter, err error) {
   101  	rw.Header().Set("Cache-Control", "no-store")
   102  	rw.Header().Set("Pragma", "no-cache")
   103  
   104  	if err == nil {
   105  		rw.WriteHeader(http.StatusOK)
   106  		return
   107  	}
   108  
   109  	if errors.Is(err, ErrInvalidRequest) {
   110  		rw.Header().Set("Content-Type", "application/json;charset=UTF-8")
   111  
   112  		js, err := json.Marshal(ErrInvalidRequest)
   113  		if err != nil {
   114  			http.Error(rw, fmt.Sprintf(`{"error": "%s"}`, err.Error()), http.StatusInternalServerError)
   115  			return
   116  		}
   117  
   118  		rw.WriteHeader(ErrInvalidRequest.CodeField)
   119  		_, _ = rw.Write(js)
   120  	} else if errors.Is(err, ErrInvalidClient) {
   121  		rw.Header().Set("Content-Type", "application/json;charset=UTF-8")
   122  
   123  		js, err := json.Marshal(ErrInvalidClient)
   124  		if err != nil {
   125  			http.Error(rw, fmt.Sprintf(`{"error": "%s"}`, err.Error()), http.StatusInternalServerError)
   126  			return
   127  		}
   128  
   129  		rw.WriteHeader(ErrInvalidClient.CodeField)
   130  		_, _ = rw.Write(js)
   131  	} else {
   132  		// 200 OK
   133  		rw.WriteHeader(http.StatusOK)
   134  	}
   135  }
   136  

View as plain text