replace zxq.co/ripple/hanayo
This commit is contained in:
275
vendor/github.com/RangelReale/osin/authorize.go
generated
vendored
Normal file
275
vendor/github.com/RangelReale/osin/authorize.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
package osin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AuthorizeRequestType is the type for OAuth param `response_type`
|
||||
type AuthorizeRequestType string
|
||||
|
||||
const (
|
||||
CODE AuthorizeRequestType = "code"
|
||||
TOKEN AuthorizeRequestType = "token"
|
||||
|
||||
PKCE_PLAIN = "plain"
|
||||
PKCE_S256 = "S256"
|
||||
)
|
||||
|
||||
var (
|
||||
pkceMatcher = regexp.MustCompile("^[a-zA-Z0-9~._-]{43,128}$")
|
||||
)
|
||||
|
||||
// Authorize request information
|
||||
type AuthorizeRequest struct {
|
||||
Type AuthorizeRequestType
|
||||
Client Client
|
||||
Scope string
|
||||
RedirectUri string
|
||||
State string
|
||||
|
||||
// Set if request is authorized
|
||||
Authorized bool
|
||||
|
||||
// Token expiration in seconds. Change if different from default.
|
||||
// If type = TOKEN, this expiration will be for the ACCESS token.
|
||||
Expiration int32
|
||||
|
||||
// Data to be passed to storage. Not used by the library.
|
||||
UserData interface{}
|
||||
|
||||
// HttpRequest *http.Request for special use
|
||||
HttpRequest *http.Request
|
||||
|
||||
// Optional code_challenge as described in rfc7636
|
||||
CodeChallenge string
|
||||
// Optional code_challenge_method as described in rfc7636
|
||||
CodeChallengeMethod string
|
||||
}
|
||||
|
||||
// Authorization data
|
||||
type AuthorizeData struct {
|
||||
// Client information
|
||||
Client Client
|
||||
|
||||
// Authorization code
|
||||
Code string
|
||||
|
||||
// Token expiration in seconds
|
||||
ExpiresIn int32
|
||||
|
||||
// Requested scope
|
||||
Scope string
|
||||
|
||||
// Redirect Uri from request
|
||||
RedirectUri string
|
||||
|
||||
// State data from request
|
||||
State string
|
||||
|
||||
// Date created
|
||||
CreatedAt time.Time
|
||||
|
||||
// Data to be passed to storage. Not used by the library.
|
||||
UserData interface{}
|
||||
|
||||
// Optional code_challenge as described in rfc7636
|
||||
CodeChallenge string
|
||||
// Optional code_challenge_method as described in rfc7636
|
||||
CodeChallengeMethod string
|
||||
}
|
||||
|
||||
// IsExpired is true if authorization expired
|
||||
func (d *AuthorizeData) IsExpired() bool {
|
||||
return d.IsExpiredAt(time.Now())
|
||||
}
|
||||
|
||||
// IsExpired is true if authorization expires at time 't'
|
||||
func (d *AuthorizeData) IsExpiredAt(t time.Time) bool {
|
||||
return d.ExpireAt().Before(t)
|
||||
}
|
||||
|
||||
// ExpireAt returns the expiration date
|
||||
func (d *AuthorizeData) ExpireAt() time.Time {
|
||||
return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second)
|
||||
}
|
||||
|
||||
// AuthorizeTokenGen is the token generator interface
|
||||
type AuthorizeTokenGen interface {
|
||||
GenerateAuthorizeToken(data *AuthorizeData) (string, error)
|
||||
}
|
||||
|
||||
// HandleAuthorizeRequest is the main http.HandlerFunc for handling
|
||||
// authorization requests
|
||||
func (s *Server) HandleAuthorizeRequest(w *Response, r *http.Request) *AuthorizeRequest {
|
||||
r.ParseForm()
|
||||
|
||||
// create the authorization request
|
||||
unescapedUri, err := url.QueryUnescape(r.Form.Get("redirect_uri"))
|
||||
if err != nil {
|
||||
w.SetErrorState(E_INVALID_REQUEST, "", "")
|
||||
w.InternalError = err
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := &AuthorizeRequest{
|
||||
State: r.Form.Get("state"),
|
||||
Scope: r.Form.Get("scope"),
|
||||
RedirectUri: unescapedUri,
|
||||
Authorized: false,
|
||||
HttpRequest: r,
|
||||
}
|
||||
|
||||
// must have a valid client
|
||||
ret.Client, err = w.Storage.GetClient(r.Form.Get("client_id"))
|
||||
if err == ErrNotFound {
|
||||
w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
w.SetErrorState(E_SERVER_ERROR, "", ret.State)
|
||||
w.InternalError = err
|
||||
return nil
|
||||
}
|
||||
if ret.Client == nil {
|
||||
w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
|
||||
return nil
|
||||
}
|
||||
if ret.Client.GetRedirectUri() == "" {
|
||||
w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
|
||||
return nil
|
||||
}
|
||||
|
||||
// check redirect uri, if there are multiple client redirect uri's
|
||||
// don't set the uri
|
||||
if ret.RedirectUri == "" && FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator) == ret.Client.GetRedirectUri() {
|
||||
ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
|
||||
}
|
||||
|
||||
if err = ValidateUriList(ret.Client.GetRedirectUri(), ret.RedirectUri, s.Config.RedirectUriSeparator); err != nil {
|
||||
w.SetErrorState(E_INVALID_REQUEST, "", ret.State)
|
||||
w.InternalError = err
|
||||
return nil
|
||||
}
|
||||
|
||||
w.SetRedirect(ret.RedirectUri)
|
||||
|
||||
requestType := AuthorizeRequestType(r.Form.Get("response_type"))
|
||||
if s.Config.AllowedAuthorizeTypes.Exists(requestType) {
|
||||
switch requestType {
|
||||
case CODE:
|
||||
ret.Type = CODE
|
||||
ret.Expiration = s.Config.AuthorizationExpiration
|
||||
|
||||
// Optional PKCE support (https://tools.ietf.org/html/rfc7636)
|
||||
if codeChallenge := r.Form.Get("code_challenge"); len(codeChallenge) == 0 {
|
||||
if s.Config.RequirePKCEForPublicClients && CheckClientSecret(ret.Client, "") {
|
||||
// https://tools.ietf.org/html/rfc7636#section-4.4.1
|
||||
w.SetErrorState(E_INVALID_REQUEST, "code_challenge (rfc7636) required for public clients", ret.State)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
codeChallengeMethod := r.Form.Get("code_challenge_method")
|
||||
// allowed values are "plain" (default) and "S256", per https://tools.ietf.org/html/rfc7636#section-4.3
|
||||
if len(codeChallengeMethod) == 0 {
|
||||
codeChallengeMethod = PKCE_PLAIN
|
||||
}
|
||||
if codeChallengeMethod != PKCE_PLAIN && codeChallengeMethod != PKCE_S256 {
|
||||
// https://tools.ietf.org/html/rfc7636#section-4.4.1
|
||||
w.SetErrorState(E_INVALID_REQUEST, "code_challenge_method transform algorithm not supported (rfc7636)", ret.State)
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc7636#section-4.2
|
||||
if matched := pkceMatcher.MatchString(codeChallenge); !matched {
|
||||
w.SetErrorState(E_INVALID_REQUEST, "code_challenge invalid (rfc7636)", ret.State)
|
||||
return nil
|
||||
}
|
||||
|
||||
ret.CodeChallenge = codeChallenge
|
||||
ret.CodeChallengeMethod = codeChallengeMethod
|
||||
}
|
||||
|
||||
case TOKEN:
|
||||
ret.Type = TOKEN
|
||||
ret.Expiration = s.Config.AccessExpiration
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
w.SetErrorState(E_UNSUPPORTED_RESPONSE_TYPE, "", ret.State)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) FinishAuthorizeRequest(w *Response, r *http.Request, ar *AuthorizeRequest) {
|
||||
// don't process if is already an error
|
||||
if w.IsError {
|
||||
return
|
||||
}
|
||||
|
||||
// force redirect response
|
||||
w.SetRedirect(ar.RedirectUri)
|
||||
|
||||
if ar.Authorized {
|
||||
if ar.Type == TOKEN {
|
||||
w.SetRedirectFragment(true)
|
||||
|
||||
// generate token directly
|
||||
ret := &AccessRequest{
|
||||
Type: IMPLICIT,
|
||||
Code: "",
|
||||
Client: ar.Client,
|
||||
RedirectUri: ar.RedirectUri,
|
||||
Scope: ar.Scope,
|
||||
GenerateRefresh: false, // per the RFC, should NOT generate a refresh token in this case
|
||||
Authorized: true,
|
||||
Expiration: ar.Expiration,
|
||||
UserData: ar.UserData,
|
||||
}
|
||||
|
||||
s.FinishAccessRequest(w, r, ret)
|
||||
if ar.State != "" && w.InternalError == nil {
|
||||
w.Output["state"] = ar.State
|
||||
}
|
||||
} else {
|
||||
// generate authorization token
|
||||
ret := &AuthorizeData{
|
||||
Client: ar.Client,
|
||||
CreatedAt: s.Now(),
|
||||
ExpiresIn: ar.Expiration,
|
||||
RedirectUri: ar.RedirectUri,
|
||||
State: ar.State,
|
||||
Scope: ar.Scope,
|
||||
UserData: ar.UserData,
|
||||
// Optional PKCE challenge
|
||||
CodeChallenge: ar.CodeChallenge,
|
||||
CodeChallengeMethod: ar.CodeChallengeMethod,
|
||||
}
|
||||
|
||||
// generate token code
|
||||
code, err := s.AuthorizeTokenGen.GenerateAuthorizeToken(ret)
|
||||
if err != nil {
|
||||
w.SetErrorState(E_SERVER_ERROR, "", ar.State)
|
||||
w.InternalError = err
|
||||
return
|
||||
}
|
||||
ret.Code = code
|
||||
|
||||
// save authorization token
|
||||
if err = w.Storage.SaveAuthorize(ret); err != nil {
|
||||
w.SetErrorState(E_SERVER_ERROR, "", ar.State)
|
||||
w.InternalError = err
|
||||
return
|
||||
}
|
||||
|
||||
// redirect with code
|
||||
w.Output["code"] = ret.Code
|
||||
w.Output["state"] = ret.State
|
||||
}
|
||||
} else {
|
||||
// redirect with error
|
||||
w.SetErrorState(E_ACCESS_DENIED, "", ar.State)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user