...

Source file src/github.com/ory/fosite/access_request_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  	"net/http"
    27  	"strings"
    28  
    29  	"github.com/ory/fosite/i18n"
    30  	"github.com/ory/x/errorsx"
    31  
    32  	"github.com/pkg/errors"
    33  )
    34  
    35  // Implements
    36  // * https://tools.ietf.org/html/rfc6749#section-2.3.1
    37  //   Clients in possession of a client password MAY use the HTTP Basic
    38  //   authentication scheme as defined in [RFC2617] to authenticate with
    39  //   the authorization server.  The client identifier is encoded using the
    40  //   "application/x-www-form-urlencoded" encoding algorithm per
    41  //   Appendix B, and the encoded value is used as the username; the client
    42  //   password is encoded using the same algorithm and used as the
    43  //   password.  The authorization server MUST support the HTTP Basic
    44  //   authentication scheme for authenticating clients that were issued a
    45  //   client password.
    46  //   Including the client credentials in the request-body using the two
    47  //   parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
    48  //   to directly utilize the HTTP Basic authentication scheme (or other
    49  //   password-based HTTP authentication schemes).  The parameters can only
    50  //   be transmitted in the request-body and MUST NOT be included in the
    51  //   request URI.
    52  //   * https://tools.ietf.org/html/rfc6749#section-3.2.1
    53  //   - Confidential clients or other clients issued client credentials MUST
    54  //   authenticate with the authorization server as described in
    55  //   Section 2.3 when making requests to the token endpoint.
    56  //   - If the client type is confidential or the client was issued client
    57  //   credentials (or assigned other authentication requirements), the
    58  //   client MUST authenticate with the authorization server as described
    59  //   in Section 3.2.1.
    60  func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session Session) (AccessRequester, error) {
    61  	accessRequest := NewAccessRequest(session)
    62  	accessRequest.Request.Lang = i18n.GetLangFromRequest(f.MessageCatalog, r)
    63  
    64  	ctx = context.WithValue(ctx, RequestContextKey, r)
    65  	ctx = context.WithValue(ctx, AccessRequestContextKey, accessRequest)
    66  
    67  	if r.Method != "POST" {
    68  		return accessRequest, errorsx.WithStack(ErrInvalidRequest.WithHintf("HTTP method is '%s', expected 'POST'.", r.Method))
    69  	} else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart {
    70  		return accessRequest, errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error()))
    71  	} else if len(r.PostForm) == 0 {
    72  		return accessRequest, errorsx.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty."))
    73  	}
    74  
    75  	accessRequest.Form = r.PostForm
    76  	if session == nil {
    77  		return accessRequest, errors.New("Session must not be nil")
    78  	}
    79  
    80  	accessRequest.SetRequestedScopes(RemoveEmpty(strings.Split(r.PostForm.Get("scope"), " ")))
    81  	accessRequest.SetRequestedAudience(GetAudiences(r.PostForm))
    82  	accessRequest.GrantTypes = RemoveEmpty(strings.Split(r.PostForm.Get("grant_type"), " "))
    83  	if len(accessRequest.GrantTypes) < 1 {
    84  		return accessRequest, errorsx.WithStack(ErrInvalidRequest.WithHint("Request parameter 'grant_type' is missing"))
    85  	}
    86  
    87  	client, clientErr := f.AuthenticateClient(ctx, r, r.PostForm)
    88  	if clientErr == nil {
    89  		accessRequest.Client = client
    90  	}
    91  
    92  	var found = false
    93  	for _, loader := range f.TokenEndpointHandlers {
    94  		// Is the loader responsible for handling the request?
    95  		if !loader.CanHandleTokenEndpointRequest(accessRequest) {
    96  			continue
    97  		}
    98  
    99  		// The handler **is** responsible!
   100  
   101  		// Is the client supplied in the request? If not can this handler skip client auth?
   102  		if !loader.CanSkipClientAuth(accessRequest) && clientErr != nil {
   103  			// No client and handler can not skip client auth -> error.
   104  			return accessRequest, clientErr
   105  		}
   106  
   107  		// All good.
   108  		if err := loader.HandleTokenEndpointRequest(ctx, accessRequest); err == nil {
   109  			found = true
   110  		} else if errors.Is(err, ErrUnknownRequest) {
   111  			// This is a duplicate because it should already have been handled by
   112  			// `loader.CanHandleTokenEndpointRequest(accessRequest)` but let's keep it for sanity.
   113  			//
   114  			continue
   115  		} else if err != nil {
   116  			return accessRequest, err
   117  		}
   118  	}
   119  
   120  	if !found {
   121  		return nil, errorsx.WithStack(ErrInvalidRequest)
   122  	}
   123  	return accessRequest, nil
   124  }
   125  

View as plain text