Merge branch 'update-scs'
This commit is contained in:
commit
4c0faeee3e
6 changed files with 36 additions and 59 deletions
|
@ -19,8 +19,7 @@ ENV \
|
|||
VPN_DEV="tun" \
|
||||
VPN_HOST="vpn.example.com" \
|
||||
VPN_PORT="1194" \
|
||||
VPN_PROTO="udp" \
|
||||
APP_KEY=""
|
||||
VPN_PROTO="udp"
|
||||
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=0 /go/src/github.com/zom-bi/ovpn-certman/certman /
|
||||
COPY --from=0 /go/src/github.com/zom-bi/ovpn-certman/ovpn-certman /certman
|
||||
ENTRYPOINT ["/certman"]
|
||||
|
|
|
@ -38,7 +38,6 @@ variables:
|
|||
* `OAUTH2_TOKEN_URL` the URL to the "/token" endpoint of the identity provider
|
||||
* `OAUTH2_REDIRECT_URL` the redirect URL used by the app, usually the hostname suffixed by "/login/oauth2/redirect"
|
||||
* `USER_ENDPOINT` the URL to the Identity provider user endpoint, for gitlab this is "/api/v4/user". The "username" attribute of the returned JSON will used for authentication.
|
||||
* `APP_KEY` random ASCII string, 32 characters in length. Used for cookie generation.
|
||||
* `APP_LISTEN` port and ip to listen on, e.g. `:8000` or `127.0.0.1:3000`
|
||||
* `VPN_DEV` which device is used by the network, either `tun` or `tap` (check server cfg)
|
||||
* `VPN_HOST` Hostname or IP address of the server
|
||||
|
|
6
main.go
6
main.go
|
@ -22,10 +22,8 @@ func main() {
|
|||
c := services.Config{
|
||||
CollectionPath: "./clients.json",
|
||||
Sessions: &services.SessionsConfig{
|
||||
SessionName: "_session",
|
||||
CookieKey: os.Getenv("APP_KEY"),
|
||||
HttpOnly: true,
|
||||
Lifetime: 24 * time.Hour,
|
||||
HTTPOnly: true,
|
||||
Lifetime: 24 * time.Hour,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ func RequireLogin(sessions *services.Sessions) func(http.Handler) http.Handler {
|
|||
fn := func(w http.ResponseWriter, req *http.Request) {
|
||||
if username := sessions.GetUsername(req); username == "" {
|
||||
http.Redirect(w, req, "/login", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, req)
|
||||
|
|
|
@ -5,25 +5,24 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/zom-bi/ovpn-certman/services"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/gorilla/securecookie"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/zom-bi/ovpn-certman/assets"
|
||||
"github.com/zom-bi/ovpn-certman/handlers"
|
||||
"github.com/zom-bi/ovpn-certman/views"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/gorilla/csrf"
|
||||
|
||||
mw "github.com/zom-bi/ovpn-certman/middleware"
|
||||
"github.com/zom-bi/ovpn-certman/services"
|
||||
"github.com/zom-bi/ovpn-certman/views"
|
||||
)
|
||||
|
||||
var (
|
||||
// TODO: make this configurable
|
||||
csrfCookieName = "csrf"
|
||||
csrfFieldName = "csrf_token"
|
||||
csrfKey = []byte("7Oj4DllZ9lTsxJnisTuWiiQBGQIzi6gX")
|
||||
cookieKey = []byte("osx70sMD8HZG2ouUl8uKI4wcMugiJ2WH")
|
||||
csrfKey = securecookie.GenerateRandomKey(32)
|
||||
)
|
||||
|
||||
func HandleRoutes(provider *services.Provider) http.Handler {
|
||||
|
@ -34,7 +33,7 @@ func HandleRoutes(provider *services.Provider) http.Handler {
|
|||
mux.Use(middleware.RealIP) // use proxy headers
|
||||
mux.Use(middleware.RedirectSlashes) // redirect trailing slashes
|
||||
mux.Use(mw.Recoverer) // recover on panic
|
||||
mux.Use(provider.Sessions.Manager.Use) // use session storage
|
||||
mux.Use(provider.Sessions.LoadAndSave) // use session storage
|
||||
|
||||
// TODO: move this code away from here
|
||||
oauth2Config := &oauth2.Config{
|
||||
|
|
|
@ -2,6 +2,7 @@ package services
|
|||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
|
@ -11,7 +12,7 @@ import (
|
|||
"github.com/alexedwards/scs"
|
||||
)
|
||||
|
||||
var (
|
||||
const (
|
||||
// FlashesKey is the key used for the flashes in the cookie
|
||||
FlashesKey = "_flashes"
|
||||
// UserEmailKey is the key used to reference usernames
|
||||
|
@ -24,29 +25,24 @@ func init() {
|
|||
}
|
||||
|
||||
type SessionsConfig struct {
|
||||
SessionName string
|
||||
CookieKey string
|
||||
HttpOnly bool
|
||||
Secure bool
|
||||
Lifetime time.Duration
|
||||
HTTPOnly bool
|
||||
Secure bool
|
||||
Lifetime time.Duration
|
||||
}
|
||||
|
||||
// Sessions is a wrapped scs.Store in order to implement custom logic
|
||||
type Sessions struct {
|
||||
*scs.Manager
|
||||
*scs.Session
|
||||
}
|
||||
|
||||
// NewSessions populates the default sessions Store
|
||||
func NewSessions(conf *SessionsConfig) *Sessions {
|
||||
store := scs.NewCookieManager(
|
||||
conf.CookieKey,
|
||||
)
|
||||
store.Name(conf.SessionName)
|
||||
store.HttpOnly(true)
|
||||
store.Lifetime(conf.Lifetime)
|
||||
store.Secure(conf.Secure)
|
||||
session := scs.NewSession()
|
||||
session.Lifetime = conf.Lifetime
|
||||
session.Cookie.HttpOnly = true
|
||||
session.Cookie.Secure = conf.Secure
|
||||
|
||||
return &Sessions{store}
|
||||
return &Sessions{session}
|
||||
}
|
||||
|
||||
func (store *Sessions) GetUsername(req *http.Request) string {
|
||||
|
@ -56,17 +52,8 @@ func (store *Sessions) GetUsername(req *http.Request) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
sess := store.Load(req)
|
||||
|
||||
email, err := sess.GetString(UserEmailKey)
|
||||
if err != nil {
|
||||
// Username found
|
||||
return ""
|
||||
|
||||
}
|
||||
|
||||
// User is logged in
|
||||
return email
|
||||
email := store.GetString(req.Context(), UserEmailKey)
|
||||
return email // "" if no user is logged in
|
||||
}
|
||||
|
||||
func (store *Sessions) SetUsername(w http.ResponseWriter, req *http.Request, username string) {
|
||||
|
@ -75,13 +62,10 @@ func (store *Sessions) SetUsername(w http.ResponseWriter, req *http.Request, use
|
|||
return
|
||||
}
|
||||
|
||||
sess := store.Load(req)
|
||||
|
||||
// renew token to avoid session pinning/fixation attack
|
||||
sess.RenewToken(w)
|
||||
|
||||
sess.PutString(w, UserEmailKey, username)
|
||||
store.RenewToken(req.Context())
|
||||
|
||||
store.Put(req.Context(), UserEmailKey, username)
|
||||
}
|
||||
|
||||
type Flash struct {
|
||||
|
@ -101,23 +85,20 @@ func (flash Flash) Render() template.HTML {
|
|||
|
||||
// Flash add flash message to session data
|
||||
func (store *Sessions) Flash(w http.ResponseWriter, req *http.Request, flash Flash) error {
|
||||
var flashes []Flash
|
||||
|
||||
sess := store.Load(req)
|
||||
|
||||
if err := sess.GetObject(FlashesKey, &flashes); err != nil {
|
||||
return err
|
||||
flashes, ok := store.Get(req.Context(), FlashesKey).([]Flash)
|
||||
if !ok {
|
||||
return errors.New("Could not get flashes")
|
||||
}
|
||||
|
||||
flashes = append(flashes, flash)
|
||||
|
||||
return sess.PutObject(w, FlashesKey, flashes)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flashes returns a slice of flash messages from session data
|
||||
func (store *Sessions) Flashes(w http.ResponseWriter, req *http.Request) []Flash {
|
||||
var flashes []Flash
|
||||
sess := store.Load(req)
|
||||
sess.PopObject(w, FlashesKey, &flashes)
|
||||
flashes, ok := store.Pop(req.Context(), FlashesKey).([]Flash)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return flashes
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue