nano-run/server/ui/authorization.go
2020-10-02 12:40:18 +08:00

125 lines
3.1 KiB
Go

package ui
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"golang.org/x/oauth2"
)
const (
redirectToCookie = "redirect-to"
ctxLogin = "login"
ctxAuthorized = "authorized"
)
type Strategy struct {
Icon string `yaml:"icon"`
Title string `yaml:"title"`
Key string `yaml:"key"`
Secret string `yaml:"secret"`
AuthURL string `yaml:"auth_url"`
TokenURL string `yaml:"token_url"`
ProfileURL string `yaml:"profile_url"`
CallbackURL string `yaml:"callback_url"`
LoginField string `yaml:"login_field"`
Scopes []string `yaml:"scopes"`
}
func (st *Strategy) Enable(router gin.IRouter, sessionStorage SessionStorage) {
if st == nil {
return
}
ep := &OAuth2{
Config: oauth2.Config{
ClientID: st.Key,
ClientSecret: st.Secret,
Endpoint: oauth2.Endpoint{
AuthURL: st.AuthURL,
TokenURL: st.TokenURL,
},
RedirectURL: st.CallbackURL,
Scopes: st.Scopes,
},
ProfileURL: st.ProfileURL,
RedirectTo: "../success",
LoginField: st.LoginField,
}
ep.Attach(router, sessionStorage)
}
type Authorization struct {
OAuth2 *Strategy `yaml:"oauth2"`
AllowedUsers []string `yaml:"users"`
}
func (auth Authorization) Enabled() bool {
return auth.OAuth2 != nil
}
func (auth Authorization) attach(router gin.IRouter, loginTemplate string, sessionStorage SessionStorage) {
auth.OAuth2.Enable(router.Group("/oauth2/"), sessionStorage)
router.GET("/logout", func(gctx *gin.Context) {
id, _ := gctx.Cookie(sessionCookie)
sessionStorage.Delete(id)
gctx.Redirect(http.StatusTemporaryRedirect, "../")
})
router.GET("/success", func(gctx *gin.Context) {
redirectTo, err := gctx.Cookie(redirectToCookie)
if err == nil && redirectTo != "" {
gctx.SetCookie(redirectToCookie, "", -1, "", "", false, true)
gctx.Redirect(http.StatusTemporaryRedirect, redirectTo)
} else {
gctx.Redirect(http.StatusTemporaryRedirect, "../../")
}
})
router.GET("/", func(gctx *gin.Context) {
var reply struct {
Auth Authorization
}
reply.Auth = auth
gctx.HTML(http.StatusOK, loginTemplate, reply)
})
}
func (auth Authorization) restrict(redirectTo func(gctx *gin.Context) string, sessionStorage SessionStorage) gin.HandlerFunc {
if !auth.Enabled() {
return func(gctx *gin.Context) {
gctx.Set(ctxAuthorized, false)
gctx.Set(ctxLogin, "")
gctx.Next()
}
}
return func(gctx *gin.Context) {
sessionID, err := gctx.Cookie(sessionCookie)
session, ok := sessionStorage.Get(sessionID)
if err != nil || !ok || session == nil || !session.Valid() {
gctx.SetCookie(redirectToCookie, gctx.Request.RequestURI, 3600, "", "", false, true)
gctx.Redirect(http.StatusTemporaryRedirect, redirectTo(gctx))
gctx.Abort()
return
}
login := session.Login()
found := len(auth.AllowedUsers) == 0
for _, u := range auth.AllowedUsers {
if u == login {
found = true
break
}
}
if !found {
log.Println("user", login, "not allowed")
gctx.Redirect(http.StatusTemporaryRedirect, redirectTo(gctx))
gctx.Abort()
return
}
gctx.Set(ctxAuthorized, true)
gctx.Set(ctxLogin, login)
gctx.Next()
}
}