...

Source file src/github.com/ory/fosite/errors.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  	"encoding/json"
    26  	"fmt"
    27  	"net/http"
    28  	"net/url"
    29  	"strings"
    30  
    31  	"github.com/ory/fosite/i18n"
    32  	"github.com/ory/x/errorsx"
    33  	"golang.org/x/text/language"
    34  
    35  	stderr "errors"
    36  
    37  	"github.com/pkg/errors"
    38  )
    39  
    40  var (
    41  	// ErrInvalidatedAuthorizeCode is an error indicating that an authorization code has been
    42  	// used previously.
    43  	ErrInvalidatedAuthorizeCode = errors.New("Authorization code has ben invalidated")
    44  	// ErrSerializationFailure is an error indicating that the transactional capable storage could not guarantee
    45  	// consistency of Update & Delete operations on the same rows between multiple sessions.
    46  	ErrSerializationFailure = errors.New("The request could not be completed due to concurrent access")
    47  	ErrUnknownRequest       = &RFC6749Error{
    48  		ErrorField:       errUnknownErrorName,
    49  		DescriptionField: "The handler is not responsible for this request.",
    50  		CodeField:        http.StatusBadRequest,
    51  	}
    52  	ErrRequestForbidden = &RFC6749Error{
    53  		ErrorField:       errRequestForbidden,
    54  		DescriptionField: "The request is not allowed.",
    55  		HintField:        "You are not allowed to perform this action.",
    56  		CodeField:        http.StatusForbidden,
    57  	}
    58  	ErrInvalidRequest = &RFC6749Error{
    59  		ErrorField:       errInvalidRequestName,
    60  		DescriptionField: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
    61  		HintField:        "Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.",
    62  		CodeField:        http.StatusBadRequest,
    63  	}
    64  	ErrUnauthorizedClient = &RFC6749Error{
    65  		ErrorField:       errUnauthorizedClientName,
    66  		DescriptionField: "The client is not authorized to request a token using this method.",
    67  		HintField:        "Make sure that client id and secret are correctly specified and that the client exists.",
    68  		CodeField:        http.StatusBadRequest,
    69  	}
    70  	ErrAccessDenied = &RFC6749Error{
    71  		ErrorField:       errAccessDeniedName,
    72  		DescriptionField: "The resource owner or authorization server denied the request.",
    73  		HintField:        "Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.",
    74  		CodeField:        http.StatusForbidden,
    75  	}
    76  	ErrUnsupportedResponseType = &RFC6749Error{
    77  		ErrorField:       errUnsupportedResponseTypeName,
    78  		DescriptionField: "The authorization server does not support obtaining a token using this method.",
    79  		CodeField:        http.StatusBadRequest,
    80  	}
    81  	ErrUnsupportedResponseMode = &RFC6749Error{
    82  		ErrorField:       errUnsupportedResponseModeName,
    83  		DescriptionField: "The authorization server does not support obtaining a response using this response mode.",
    84  		CodeField:        http.StatusBadRequest,
    85  	}
    86  	ErrInvalidScope = &RFC6749Error{
    87  		ErrorField:       errInvalidScopeName,
    88  		DescriptionField: "The requested scope is invalid, unknown, or malformed.",
    89  		CodeField:        http.StatusBadRequest,
    90  	}
    91  	ErrServerError = &RFC6749Error{
    92  		ErrorField:       errServerErrorName,
    93  		DescriptionField: "The authorization server encountered an unexpected condition that prevented it from fulfilling the request.",
    94  		CodeField:        http.StatusInternalServerError,
    95  	}
    96  	ErrTemporarilyUnavailable = &RFC6749Error{
    97  		ErrorField:       errTemporarilyUnavailableName,
    98  		DescriptionField: "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.",
    99  		CodeField:        http.StatusServiceUnavailable,
   100  	}
   101  	ErrUnsupportedGrantType = &RFC6749Error{
   102  		ErrorField:       errUnsupportedGrantTypeName,
   103  		DescriptionField: "The authorization grant type is not supported by the authorization server.",
   104  		CodeField:        http.StatusBadRequest,
   105  	}
   106  	ErrInvalidGrant = &RFC6749Error{
   107  		ErrorField:       errInvalidGrantName,
   108  		DescriptionField: "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
   109  		CodeField:        http.StatusBadRequest,
   110  	}
   111  	ErrInvalidClient = &RFC6749Error{
   112  		ErrorField:       errInvalidClientName,
   113  		DescriptionField: "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method).",
   114  		CodeField:        http.StatusUnauthorized,
   115  	}
   116  	ErrInvalidState = &RFC6749Error{
   117  		ErrorField:       errInvalidStateName,
   118  		DescriptionField: "The state is missing or does not have enough characters and is therefore considered too weak.",
   119  		CodeField:        http.StatusBadRequest,
   120  	}
   121  	ErrMisconfiguration = &RFC6749Error{
   122  		ErrorField:       errMisconfigurationName,
   123  		DescriptionField: "The request failed because of an internal error that is probably caused by misconfiguration.",
   124  		CodeField:        http.StatusInternalServerError,
   125  	}
   126  	ErrInsufficientEntropy = &RFC6749Error{
   127  		ErrorField:       errInsufficientEntropyName,
   128  		DescriptionField: "The request used a security parameter (e.g., anti-replay, anti-csrf) with insufficient entropy.",
   129  		CodeField:        http.StatusBadRequest,
   130  	}
   131  	ErrNotFound = &RFC6749Error{
   132  		ErrorField:       errNotFoundName,
   133  		DescriptionField: "Could not find the requested resource(s).",
   134  		CodeField:        http.StatusNotFound,
   135  	}
   136  	ErrRequestUnauthorized = &RFC6749Error{
   137  		ErrorField:       errRequestUnauthorizedName,
   138  		DescriptionField: "The request could not be authorized.",
   139  		HintField:        "Check that you provided valid credentials in the right format.",
   140  		CodeField:        http.StatusUnauthorized,
   141  	}
   142  	ErrTokenSignatureMismatch = &RFC6749Error{
   143  		ErrorField:       errTokenSignatureMismatchName,
   144  		DescriptionField: "Token signature mismatch.",
   145  		HintField:        "Check that you provided  a valid token in the right format.",
   146  		CodeField:        http.StatusBadRequest,
   147  	}
   148  	ErrInvalidTokenFormat = &RFC6749Error{
   149  		ErrorField:       errInvalidTokenFormatName,
   150  		DescriptionField: "Invalid token format.",
   151  		HintField:        "Check that you provided a valid token in the right format.",
   152  		CodeField:        http.StatusBadRequest,
   153  	}
   154  	ErrTokenExpired = &RFC6749Error{
   155  		ErrorField:       errTokenExpiredName,
   156  		DescriptionField: "Token expired.",
   157  		HintField:        "The token expired.",
   158  		CodeField:        http.StatusUnauthorized,
   159  	}
   160  	ErrScopeNotGranted = &RFC6749Error{
   161  		ErrorField:       errScopeNotGrantedName,
   162  		DescriptionField: "The token was not granted the requested scope.",
   163  		HintField:        "The resource owner did not grant the requested scope.",
   164  		CodeField:        http.StatusForbidden,
   165  	}
   166  	ErrTokenClaim = &RFC6749Error{
   167  		ErrorField:       errTokenClaimName,
   168  		DescriptionField: "The token failed validation due to a claim mismatch.",
   169  		HintField:        "One or more token claims failed validation.",
   170  		CodeField:        http.StatusUnauthorized,
   171  	}
   172  	ErrInactiveToken = &RFC6749Error{
   173  		ErrorField:       errTokenInactiveName,
   174  		DescriptionField: "Token is inactive because it is malformed, expired or otherwise invalid.",
   175  		HintField:        "Token validation failed.",
   176  		CodeField:        http.StatusUnauthorized,
   177  	}
   178  	ErrLoginRequired = &RFC6749Error{
   179  		ErrorField:       errLoginRequired,
   180  		DescriptionField: "The Authorization Server requires End-User authentication.",
   181  		CodeField:        http.StatusBadRequest,
   182  	}
   183  	ErrInteractionRequired = &RFC6749Error{
   184  		DescriptionField: "The Authorization Server requires End-User interaction of some form to proceed.",
   185  		ErrorField:       errInteractionRequired,
   186  		CodeField:        http.StatusBadRequest,
   187  	}
   188  	ErrConsentRequired = &RFC6749Error{
   189  		DescriptionField: "The Authorization Server requires End-User consent.",
   190  		ErrorField:       errConsentRequired,
   191  		CodeField:        http.StatusBadRequest,
   192  	}
   193  	ErrRequestNotSupported = &RFC6749Error{
   194  		DescriptionField: "The OP does not support use of the request parameter.",
   195  		ErrorField:       errRequestNotSupportedName,
   196  		CodeField:        http.StatusBadRequest,
   197  	}
   198  	ErrRequestURINotSupported = &RFC6749Error{
   199  		DescriptionField: "The OP does not support use of the request_uri parameter.",
   200  		ErrorField:       errRequestURINotSupportedName,
   201  		CodeField:        http.StatusBadRequest,
   202  	}
   203  	ErrRegistrationNotSupported = &RFC6749Error{
   204  		DescriptionField: "The OP does not support use of the registration parameter.",
   205  		ErrorField:       errRegistrationNotSupportedName,
   206  		CodeField:        http.StatusBadRequest,
   207  	}
   208  	ErrInvalidRequestURI = &RFC6749Error{
   209  		DescriptionField: "The request_uri in the Authorization Request returns an error or contains invalid data.",
   210  		ErrorField:       errInvalidRequestURI,
   211  		CodeField:        http.StatusBadRequest,
   212  	}
   213  	ErrInvalidRequestObject = &RFC6749Error{
   214  		DescriptionField: "The request parameter contains an invalid Request Object.",
   215  		ErrorField:       errInvalidRequestObject,
   216  		CodeField:        http.StatusBadRequest,
   217  	}
   218  	ErrJTIKnown = &RFC6749Error{
   219  		DescriptionField: "The jti was already used.",
   220  		ErrorField:       errJTIKnownName,
   221  		CodeField:        http.StatusBadRequest,
   222  	}
   223  )
   224  
   225  const (
   226  	errInvalidRequestURI           = "invalid_request_uri"
   227  	errInvalidRequestObject        = "invalid_request_object"
   228  	errConsentRequired             = "consent_required"
   229  	errInteractionRequired         = "interaction_required"
   230  	errLoginRequired               = "login_required"
   231  	errRequestUnauthorizedName     = "request_unauthorized"
   232  	errRequestForbidden            = "request_forbidden"
   233  	errInvalidRequestName          = "invalid_request"
   234  	errUnauthorizedClientName      = "unauthorized_client"
   235  	errAccessDeniedName            = "access_denied"
   236  	errUnsupportedResponseTypeName = "unsupported_response_type"
   237  	errUnsupportedResponseModeName = "unsupported_response_mode"
   238  	errInvalidScopeName            = "invalid_scope"
   239  	errServerErrorName             = "server_error"
   240  	errTemporarilyUnavailableName  = "temporarily_unavailable"
   241  	errUnsupportedGrantTypeName    = "unsupported_grant_type"
   242  	errInvalidGrantName            = "invalid_grant"
   243  	errInvalidClientName           = "invalid_client"
   244  	errNotFoundName                = "not_found"
   245  	errInvalidStateName            = "invalid_state"
   246  	errMisconfigurationName        = "misconfiguration"
   247  	errInsufficientEntropyName     = "insufficient_entropy"
   248  	errInvalidTokenFormatName      = "invalid_token"
   249  	errTokenSignatureMismatchName  = "token_signature_mismatch"
   250  	errTokenExpiredName            = "invalid_token" // https://tools.ietf.org/html/rfc6750#section-3.1
   251  	errScopeNotGrantedName         = "scope_not_granted"
   252  	errTokenClaimName              = "token_claim"
   253  	errTokenInactiveName           = "token_inactive"
   254  	// errAuthorizationCodeInactiveName = "authorization_code_inactive"
   255  	errUnknownErrorName             = "error"
   256  	errRequestNotSupportedName      = "request_not_supported"
   257  	errRequestURINotSupportedName   = "request_uri_not_supported"
   258  	errRegistrationNotSupportedName = "registration_not_supported"
   259  	errJTIKnownName                 = "jti_known"
   260  )
   261  
   262  type (
   263  	RFC6749Error struct {
   264  		ErrorField       string
   265  		DescriptionField string
   266  		HintField        string
   267  		CodeField        int
   268  		DebugField       string
   269  		cause            error
   270  		useLegacyFormat  bool
   271  		exposeDebug      bool
   272  
   273  		// Fields for globalization
   274  		hintIDField string
   275  		hintArgs    []interface{}
   276  		catalog     i18n.MessageCatalog
   277  		lang        language.Tag
   278  	}
   279  	stackTracer interface {
   280  		StackTrace() errors.StackTrace
   281  	}
   282  )
   283  
   284  var (
   285  	_ errorsx.DebugCarrier      = new(RFC6749Error)
   286  	_ errorsx.ReasonCarrier     = new(RFC6749Error)
   287  	_ errorsx.RequestIDCarrier  = new(RFC6749Error)
   288  	_ errorsx.StatusCarrier     = new(RFC6749Error)
   289  	_ errorsx.StatusCodeCarrier = new(RFC6749Error)
   290  	// _ errorsx.DetailsCarrier = new(RFC6749Error)
   291  )
   292  
   293  func ErrorToRFC6749Error(err error) *RFC6749Error {
   294  	var e *RFC6749Error
   295  	if errors.As(err, &e) {
   296  		return e
   297  	}
   298  	return &RFC6749Error{
   299  		ErrorField:       errUnknownErrorName,
   300  		DescriptionField: "The error is unrecognizable",
   301  		DebugField:       err.Error(),
   302  		CodeField:        http.StatusInternalServerError,
   303  		cause:            err,
   304  	}
   305  }
   306  
   307  // StackTrace returns the error's stack trace.
   308  func (e *RFC6749Error) StackTrace() (trace errors.StackTrace) {
   309  	if e.cause == e || e.cause == nil {
   310  		return
   311  	}
   312  
   313  	if st := stackTracer(nil); stderr.As(e.cause, &st) {
   314  		trace = st.StackTrace()
   315  	}
   316  
   317  	return
   318  }
   319  
   320  func (e RFC6749Error) Unwrap() error {
   321  	return e.cause
   322  }
   323  
   324  func (e *RFC6749Error) Wrap(err error) {
   325  	e.cause = err
   326  }
   327  
   328  func (e RFC6749Error) WithWrap(cause error) *RFC6749Error {
   329  	e.cause = cause
   330  	return &e
   331  }
   332  
   333  func (e RFC6749Error) WithLegacyFormat(useLegacyFormat bool) *RFC6749Error {
   334  	e.useLegacyFormat = useLegacyFormat
   335  	return &e
   336  }
   337  
   338  func (e *RFC6749Error) WithTrace(err error) *RFC6749Error {
   339  	if st := stackTracer(nil); !stderr.As(e.cause, &st) {
   340  		e.Wrap(errorsx.WithStack(err))
   341  	} else {
   342  		e.Wrap(err)
   343  	}
   344  	return e
   345  }
   346  
   347  func (e RFC6749Error) Is(err error) bool {
   348  	switch te := err.(type) {
   349  	case RFC6749Error:
   350  		return e.ErrorField == te.ErrorField &&
   351  			e.CodeField == te.CodeField
   352  	case *RFC6749Error:
   353  		return e.ErrorField == te.ErrorField &&
   354  			e.CodeField == te.CodeField
   355  	}
   356  	return false
   357  }
   358  
   359  func (e *RFC6749Error) Status() string {
   360  	return http.StatusText(e.CodeField)
   361  }
   362  
   363  func (e RFC6749Error) Error() string {
   364  	return e.ErrorField
   365  }
   366  
   367  func (e *RFC6749Error) RequestID() string {
   368  	return ""
   369  }
   370  
   371  func (e *RFC6749Error) Reason() string {
   372  	return e.HintField
   373  }
   374  
   375  func (e *RFC6749Error) StatusCode() int {
   376  	return e.CodeField
   377  }
   378  
   379  func (e *RFC6749Error) Cause() error {
   380  	return e.cause
   381  }
   382  
   383  func (e *RFC6749Error) WithHintf(hint string, args ...interface{}) *RFC6749Error {
   384  	err := *e
   385  	if err.hintIDField == "" {
   386  		err.hintIDField = hint
   387  	}
   388  
   389  	err.hintArgs = args
   390  	err.HintField = fmt.Sprintf(hint, args...)
   391  	return &err
   392  }
   393  
   394  func (e *RFC6749Error) WithHint(hint string) *RFC6749Error {
   395  	err := *e
   396  	if err.hintIDField == "" {
   397  		err.hintIDField = hint
   398  	}
   399  
   400  	err.HintField = hint
   401  	return &err
   402  }
   403  
   404  // WithHintIDOrDefaultf accepts the ID of the hint message
   405  func (e *RFC6749Error) WithHintIDOrDefaultf(ID string, def string, args ...interface{}) *RFC6749Error {
   406  	err := *e
   407  	err.hintIDField = ID
   408  	err.hintArgs = args
   409  	err.HintField = fmt.Sprintf(def, args...)
   410  	return &err
   411  }
   412  
   413  // WithHintTranslationID accepts the ID of the hint message and should be paired with
   414  // WithHint and WithHintf to add a default message and vaargs.
   415  func (e *RFC6749Error) WithHintTranslationID(ID string) *RFC6749Error {
   416  	err := *e
   417  	err.hintIDField = ID
   418  	return &err
   419  }
   420  
   421  func (e *RFC6749Error) Debug() string {
   422  	return e.DebugField
   423  }
   424  
   425  func (e *RFC6749Error) WithDebug(debug string) *RFC6749Error {
   426  	err := *e
   427  	err.DebugField = debug
   428  	return &err
   429  }
   430  
   431  func (e *RFC6749Error) WithDebugf(debug string, args ...interface{}) *RFC6749Error {
   432  	return e.WithDebug(fmt.Sprintf(debug, args...))
   433  }
   434  
   435  func (e *RFC6749Error) WithDescription(description string) *RFC6749Error {
   436  	err := *e
   437  	err.DescriptionField = description
   438  	return &err
   439  }
   440  
   441  func (e *RFC6749Error) WithLocalizer(catalog i18n.MessageCatalog, lang language.Tag) *RFC6749Error {
   442  	err := *e
   443  	err.catalog = catalog
   444  	err.lang = lang
   445  	return &err
   446  }
   447  
   448  // Sanitize strips the debug field
   449  //
   450  // Deprecated: Use WithExposeDebug instead.
   451  func (e *RFC6749Error) Sanitize() *RFC6749Error {
   452  	err := *e
   453  	err.DebugField = ""
   454  	return &err
   455  }
   456  
   457  // WithExposeDebug if set to true exposes debug messages
   458  func (e *RFC6749Error) WithExposeDebug(exposeDebug bool) *RFC6749Error {
   459  	err := *e
   460  	err.exposeDebug = exposeDebug
   461  	return &err
   462  }
   463  
   464  // GetDescription returns a more description description, combined with hint and debug (when available).
   465  func (e *RFC6749Error) GetDescription() string {
   466  	description := i18n.GetMessageOrDefault(e.catalog, e.ErrorField, e.lang, e.DescriptionField)
   467  	e.computeHintField()
   468  	if e.HintField != "" {
   469  		description += " " + e.HintField
   470  	}
   471  	if e.DebugField != "" && e.exposeDebug {
   472  		description += " " + e.DebugField
   473  	}
   474  	return strings.ReplaceAll(description, "\"", "'")
   475  }
   476  
   477  // RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error.
   478  type RFC6749ErrorJson struct {
   479  	Name        string `json:"error"`
   480  	Description string `json:"error_description"`
   481  	Hint        string `json:"error_hint,omitempty"`
   482  	Code        int    `json:"status_code,omitempty"`
   483  	Debug       string `json:"error_debug,omitempty"`
   484  }
   485  
   486  func (e *RFC6749Error) UnmarshalJSON(b []byte) error {
   487  	var data RFC6749ErrorJson
   488  
   489  	if err := json.Unmarshal(b, &data); err != nil {
   490  		return err
   491  	}
   492  
   493  	e.ErrorField = data.Name
   494  	e.CodeField = data.Code
   495  	e.DescriptionField = data.Description
   496  
   497  	if len(data.Hint+data.Debug) > 0 {
   498  		e.HintField = data.Hint
   499  		e.DebugField = data.Debug
   500  		e.useLegacyFormat = true
   501  	}
   502  
   503  	return nil
   504  }
   505  
   506  func (e RFC6749Error) MarshalJSON() ([]byte, error) {
   507  	if !e.useLegacyFormat {
   508  		return json.Marshal(&RFC6749ErrorJson{
   509  			Name:        e.ErrorField,
   510  			Description: e.GetDescription(),
   511  		})
   512  	}
   513  
   514  	var debug string
   515  	if e.exposeDebug {
   516  		debug = e.DebugField
   517  	}
   518  
   519  	return json.Marshal(&RFC6749ErrorJson{
   520  		Name:        e.ErrorField,
   521  		Description: e.DescriptionField,
   522  		Hint:        e.HintField,
   523  		Code:        e.CodeField,
   524  		Debug:       debug,
   525  	})
   526  }
   527  
   528  func (e *RFC6749Error) ToValues() url.Values {
   529  	values := url.Values{}
   530  	values.Set("error", e.ErrorField)
   531  	values.Set("error_description", e.GetDescription())
   532  
   533  	if e.useLegacyFormat {
   534  		values.Set("error_description", e.DescriptionField)
   535  		if e.HintField != "" {
   536  			values.Set("error_hint", e.HintField)
   537  		}
   538  
   539  		if e.DebugField != "" && e.exposeDebug {
   540  			values.Set("error_debug", e.DebugField)
   541  		}
   542  	}
   543  
   544  	return values
   545  }
   546  
   547  func (e *RFC6749Error) computeHintField() {
   548  	if e.hintIDField == "" {
   549  		return
   550  	}
   551  
   552  	e.HintField = i18n.GetMessageOrDefault(e.catalog, e.hintIDField, e.lang, e.HintField, e.hintArgs...)
   553  }
   554  

View as plain text