You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.5 KiB
Go
93 lines
2.5 KiB
Go
// Copyright 2017 Drone.IO Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package oauth2
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.awesome-for.me/liuzhiguo/go-login/login"
|
|
"git.awesome-for.me/liuzhiguo/go-login/login/logger"
|
|
)
|
|
|
|
// Handler returns a Handler that runs h at the completion
|
|
// of the oauth2 authorization flow.
|
|
func Handler(h http.Handler, c *Config) http.Handler {
|
|
return &handler{next: h, conf: c, logs: c.Logger}
|
|
}
|
|
|
|
type handler struct {
|
|
conf *Config
|
|
next http.Handler
|
|
logs logger.Logger
|
|
}
|
|
|
|
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
// checks for the error query parameter in the request.
|
|
// If non-empty, write to the context and proceed with
|
|
// the next http.Handler in the chain.
|
|
if erro := r.FormValue("error"); erro != "" {
|
|
h.logger().Errorf("oauth: authorization error: %s", erro)
|
|
ctx = login.WithError(ctx, errors.New(erro))
|
|
h.next.ServeHTTP(w, r.WithContext(ctx))
|
|
return
|
|
}
|
|
|
|
// checks for the code query parameter in the request
|
|
// If empty, redirect to the authorization endpoint.
|
|
code := r.FormValue("code")
|
|
if len(code) == 0 {
|
|
state := createState(w)
|
|
http.Redirect(w, r, h.conf.authorizeRedirect(state), 303)
|
|
return
|
|
}
|
|
|
|
// checks for the state query parameter in the requet.
|
|
// If empty, write the error to the context and proceed
|
|
// with the next http.Handler in the chain.
|
|
state := r.FormValue("state")
|
|
deleteState(w)
|
|
if err := validateState(r, state); err != nil {
|
|
h.logger().Errorln("oauth: invalid or missing state")
|
|
ctx = login.WithError(ctx, err)
|
|
h.next.ServeHTTP(w, r.WithContext(ctx))
|
|
return
|
|
}
|
|
|
|
// requests the access_token and refresh_token from the
|
|
// authorization server. If an error is encountered,
|
|
// write the error to the context and prceed with the
|
|
// next http.Handler in the chain.
|
|
source, err := h.conf.exchange(code, state)
|
|
if err != nil {
|
|
h.logger().Errorf("oauth: cannot exchange code: %s: %s", code, err)
|
|
ctx = login.WithError(ctx, err)
|
|
h.next.ServeHTTP(w, r.WithContext(ctx))
|
|
return
|
|
}
|
|
|
|
// converts the oauth2 token type to the internal Token
|
|
// type and attaches to the context.
|
|
ctx = login.WithToken(ctx, &login.Token{
|
|
Access: source.AccessToken,
|
|
Refresh: source.RefreshToken,
|
|
Expires: time.Now().UTC().Add(
|
|
time.Duration(source.Expires) * time.Second,
|
|
),
|
|
})
|
|
|
|
h.next.ServeHTTP(w, r.WithContext(ctx))
|
|
}
|
|
|
|
func (h *handler) logger() logger.Logger {
|
|
if h.logs == nil {
|
|
return logger.Discard()
|
|
}
|
|
return h.logs
|
|
}
|