implement github oauth, set demo to github auth

This commit is contained in:
vx3r 2020-04-30 18:14:46 +09:00
parent dd99358f8f
commit 6fcd70bf80
5 changed files with 149 additions and 46 deletions

4
.env
View File

@ -32,10 +32,10 @@ OAUTH2_REDIRECT_URL=

# example with github
OAUTH2_PROVIDER_NAME=github
OAUTH2_PROVIDER=
OAUTH2_PROVIDER=https://github.com
OAUTH2_CLIENT_ID=
OAUTH2_CLIENT_SECRET=
OAUTH2_REDIRECT_URL=
OAUTH2_REDIRECT_URL=https://wg-gen-web-demo.127-0-0-1.fr

# set provider name to fake to disable auth, also the default
OAUTH2_PROVIDER_NAME=fake

View File

@ -1,8 +1,14 @@
package auth

import (
"fmt"
log "github.com/sirupsen/logrus"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/fake"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/github"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/oauth2oidc"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model"
"golang.org/x/oauth2"
"os"
)

type Auth interface {
@ -11,3 +17,31 @@ type Auth interface {
Exchange(code string) (*oauth2.Token, error)
UserInfo(oauth2Token *oauth2.Token) (*model.User, error)
}

func GetAuthProvider() (Auth, error) {
var oauth2Client Auth
var err error

switch os.Getenv("OAUTH2_PROVIDER_NAME") {
case "fake":
log.Warn("Oauth is set to fake, no actual authentication will be performed")
oauth2Client = &fake.Fake{}

case "oauth2oidc":
log.Warn("Oauth is set to oauth2oidc, must be RFC implementation on server side")
oauth2Client = &oauth2oidc.Oauth2idc{}

case "github":
log.Warn("Oauth is set to github, no openid will be used")
oauth2Client = &github.Github{}

case "google":
return nil, fmt.Errorf("auth provider name %s not yet implemented", os.Getenv("OAUTH2_PROVIDER_NAME"))
default:
return nil, fmt.Errorf("auth provider name %s unknown", os.Getenv("OAUTH2_PROVIDER_NAME"))
}

err = oauth2Client.Setup()

return oauth2Client, err
}

View File

@ -1 +1,102 @@
package github

import (
"context"
"encoding/json"
"fmt"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/model"
"golang.org/x/oauth2"
oauth2Github "golang.org/x/oauth2/github"
"io/ioutil"
"net/http"
"os"
"time"
)

type Github struct{}

var (
oauth2Config *oauth2.Config
)

// Setup validate provider
func (o *Github) Setup() error {
oauth2Config = &oauth2.Config{
ClientID: os.Getenv("OAUTH2_CLIENT_ID"),
ClientSecret: os.Getenv("OAUTH2_CLIENT_SECRET"),
RedirectURL: os.Getenv("OAUTH2_REDIRECT_URL"),
Scopes: []string{"user"},
Endpoint: oauth2Github.Endpoint,
}

return nil
}

// CodeUrl get url to redirect client for auth
func (o *Github) CodeUrl(state string) string {
return oauth2Config.AuthCodeURL(state)
}

// Exchange exchange code for Oauth2 token
func (o *Github) Exchange(code string) (*oauth2.Token, error) {
oauth2Token, err := oauth2Config.Exchange(context.TODO(), code)
if err != nil {
return nil, err
}

return oauth2Token, nil
}

// UserInfo get token user
func (o *Github) UserInfo(oauth2Token *oauth2.Token) (*model.User, error) {
// https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/

// we have the token, lets get user information
req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
if err != nil {
return nil, err
}

req.Header.Set("Authorization", fmt.Sprintf("token %s", oauth2Token.AccessToken))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}

if resp.StatusCode != 200 {
return nil, fmt.Errorf("http status %s expect 200 OK", resp.Status)
}

bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
defer resp.Body.Close()

var data map[string]interface{}
err = json.Unmarshal(bodyBytes, &data)
if err != nil {
return nil, err
}

// get some infos about user
user := &model.User{}

if val, ok := data["name"]; ok && val != nil {
user.Name = val.(string)
}
if val, ok := data["email"]; ok && val != nil {
user.Email = val.(string)
}
if val, ok := data["html_url"]; ok && val != nil {
user.Profile = val.(string)
}

// openid specific
user.Sub = "github is not an openid provider"
user.Issuer = "https://github.com"
user.IssuedAt = time.Now().UTC()

return user, nil
}

View File

@ -11,8 +11,6 @@ import (
log "github.com/sirupsen/logrus"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/api"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/fake"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/auth/oauth2oidc"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/core"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/util"
"gitlab.127-0-0-1.fr/vx3r/wg-gen-web/version"
@ -20,6 +18,7 @@ import (
"net/http"
"os"
"path/filepath"
"strings"
"time"
)

@ -106,45 +105,14 @@ func main() {
// serve static files
app.Use(static.Serve("/", static.LocalFile("./ui/dist", false)))

// setup Oauth2 client if enabled
var oauth2Client auth.Auth

switch os.Getenv("OAUTH2_PROVIDER_NAME") {
case "fake":
log.Warn("Oauth is set to fake, no actual authentication will be performed")
oauth2Client = &fake.Fake{}
err = oauth2Client.Setup()
if err != nil {
log.WithFields(log.Fields{
"OAUTH2_PROVIDER_NAME": "oauth2oidc",
"err": err,
}).Fatal("failed to setup Oauth2")
}
case "oauth2oidc":
log.Warn("Oauth is set to oauth2oidc, must be RFC implementation on server side")
oauth2Client = &oauth2oidc.Oauth2idc{}
err = oauth2Client.Setup()
if err != nil {
log.WithFields(log.Fields{
"OAUTH2_PROVIDER_NAME": "oauth2oidc",
"err": err,
}).Fatal("failed to setup Oauth2")
}
default:
// setup Oauth2 client
oauth2Client, err := auth.GetAuthProvider()
if err != nil {
log.WithFields(log.Fields{
"OAUTH2_PROVIDER_NAME": os.Getenv("OAUTH2_PROVIDER_NAME"),
}).Fatal("auth provider name unknown")
"err": err,
}).Fatal("failed to setup Oauth2")
}

if os.Getenv("OAUTH2_ENABLE") == "true" {
oauth2Client = &oauth2oidc.Oauth2idc{}
err = oauth2Client.Setup()
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Fatal("failed to setup Oauth2")
}
}
app.Use(func(ctx *gin.Context) {
ctx.Set("oauth2Client", oauth2Client)
ctx.Next()
@ -167,6 +135,12 @@ func main() {
return
}

// avoid 401 page for refresh after logout
if !strings.Contains(c.Request.URL.Path, "/api/") {
c.Redirect(301, "/index.html")
return
}

c.AbortWithStatus(http.StatusUnauthorized)
return
})

6
go.mod
View File

@ -3,17 +3,11 @@ module gitlab.127-0-0-1.fr/vx3r/wg-gen-web
go 1.14

require (
github.com/appleboy/gin-jwt/v2 v2.6.3 // indirect
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e
github.com/gin-contrib/cors v1.3.1
github.com/gin-contrib/sessions v0.0.3
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2
github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607 // indirect
github.com/gin-gonic/gin v1.6.2
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/gorilla/sessions v1.2.0 // indirect
github.com/joho/godotenv v1.3.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect