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.
go-login/login/internal/oauth2/handler.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
}