First OAuth implementation.
This commit is contained in:
parent
558f9d6029
commit
850a283083
|
|
@ -97,6 +97,10 @@ func Run() {
|
|||
http.HandleFunc(ROUTE_ROOT, indexHandler)
|
||||
http.HandleFunc(ROUTE_AUTH, authHandler)
|
||||
|
||||
// OAuth2
|
||||
LoadOAuth()
|
||||
LoadServer()
|
||||
|
||||
if HttpPortBind > 0 {
|
||||
go runHttp(BindAddressIPv4)
|
||||
if BindAddressIPv4 != "0.0.0.0" {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,148 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP.git/xmpp"
|
||||
|
||||
"gopkg.in/oauth2.v3/errors"
|
||||
"gopkg.in/oauth2.v3/manage"
|
||||
"gopkg.in/oauth2.v3/models"
|
||||
"gopkg.in/oauth2.v3/server"
|
||||
"gopkg.in/oauth2.v3/store"
|
||||
"gopkg.in/session.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
ROUTE_LOGIN = "/login"
|
||||
ROUTE_AUTHORIZE = "/authorize"
|
||||
ROUTE_TOKEN = "/token"
|
||||
)
|
||||
|
||||
var (
|
||||
globalSessions *session.Manager
|
||||
manager *manage.Manager
|
||||
clientList []models.Client
|
||||
)
|
||||
|
||||
func init() {
|
||||
globalSessions, _ = session.NewManager("memory", `{"cookieName":"gosessionid","gclifetime":3600}`)
|
||||
go globalSessions.GC()
|
||||
}
|
||||
|
||||
func LoadConfigClient(configFile string) error {
|
||||
file, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(file, &clientList)
|
||||
}
|
||||
|
||||
func LoadOAuth() {
|
||||
manager = manage.NewDefaultManager()
|
||||
// token store
|
||||
manager.MustTokenStorage(store.NewMemoryTokenStore())
|
||||
|
||||
clientStore := store.NewClientStore()
|
||||
for _, c := range clientList {
|
||||
clientStore.Set(c.ID, &c)
|
||||
}
|
||||
manager.MapClientStorage(clientStore)
|
||||
}
|
||||
|
||||
func LoadServer() {
|
||||
srv := server.NewServer(server.NewConfig(), manager)
|
||||
srv.SetUserAuthorizationHandler(userAuthorizeHandler)
|
||||
srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
|
||||
log.Println("Internal Error:", err.Error())
|
||||
return
|
||||
})
|
||||
srv.SetResponseErrorHandler(func(re *errors.Response) {
|
||||
log.Println("Response Error:", re.Error.Error())
|
||||
})
|
||||
|
||||
http.HandleFunc(ROUTE_LOGIN, loginHandler)
|
||||
http.HandleFunc(ROUTE_AUTHORIZE, func(w http.ResponseWriter, r *http.Request) {
|
||||
err := srv.HandleAuthorizeRequest(w, r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
})
|
||||
http.HandleFunc(ROUTE_TOKEN, func(w http.ResponseWriter, r *http.Request) {
|
||||
err := srv.HandleTokenRequest(w, r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func userAuthorizeHandler(w http.ResponseWriter, r *http.Request) (userID string, err error) {
|
||||
us, err := globalSessions.SessionStart(w, r)
|
||||
uid := us.Get("UserID")
|
||||
if uid == nil {
|
||||
if r.Form == nil {
|
||||
r.ParseForm()
|
||||
}
|
||||
us.Set("Form", r.Form)
|
||||
w.Header().Set("Location", ROUTE_LOGIN)
|
||||
w.WriteHeader(http.StatusFound)
|
||||
return
|
||||
}
|
||||
userID = uid.(string)
|
||||
us.Delete("UserID")
|
||||
return
|
||||
}
|
||||
|
||||
func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "POST" {
|
||||
us, err := globalSessions.SessionStart(w, r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
r.ParseForm()
|
||||
jid := strings.Join(r.Form["jid"], "")
|
||||
// TODO
|
||||
answer := xmpp.Confirm(jid, "GET", "toto.fr", "oauth2", -1)
|
||||
switch answer {
|
||||
case xmpp.REPLY_OK:
|
||||
us.Set("LoggedInUserID", jid)
|
||||
form := us.Get("Form").(url.Values)
|
||||
u := new(url.URL)
|
||||
u.Path = ROUTE_AUTHORIZE
|
||||
u.RawQuery = form.Encode()
|
||||
w.Header().Set("Location", u.String())
|
||||
w.WriteHeader(http.StatusFound)
|
||||
us.Delete("Form")
|
||||
us.Set("UserID", us.Get("LoggedInUserID"))
|
||||
|
||||
case xmpp.REPLY_DENY:
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
|
||||
case xmpp.REPLY_UNREACHABLE:
|
||||
w.WriteHeader(StatusUnreachable)
|
||||
|
||||
default:
|
||||
w.WriteHeader(StatusUnknownError)
|
||||
}
|
||||
return
|
||||
}
|
||||
outputHTML(w, r, "static/login.html")
|
||||
}
|
||||
|
||||
func outputHTML(w http.ResponseWriter, req *http.Request, filename string) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
fi, _ := file.Stat()
|
||||
http.ServeContent(w, req, file.Name(), fi.ModTime(), file)
|
||||
}
|
||||
73
main.go
73
main.go
|
|
@ -16,11 +16,13 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
Version = "v0.5-dev"
|
||||
configurationFilePath = "http-auth/httpAuth.conf"
|
||||
langFilePath = "http-auth/messages.lang"
|
||||
PathConfEnvVariable = "XDG_CONFIG_DIRS"
|
||||
DefaultXdgConfigDirs = "/etc/xdg"
|
||||
Version = "v0.5-dev"
|
||||
configurationDirectory = "http-auth"
|
||||
configurationFilePath = "httpAuth.conf"
|
||||
langFilePath = "messages.lang"
|
||||
oauthClientStoreFilePath = "clientStore.json"
|
||||
PathConfEnvVariable = "XDG_CONFIG_DIRS"
|
||||
DefaultXdgConfigDirs = "/etc/xdg"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -34,6 +36,7 @@ func init() {
|
|||
log.Fatal("Failed to load configuration file.")
|
||||
}
|
||||
loadLangFile()
|
||||
loadOauthClientStore()
|
||||
|
||||
// HTTP config
|
||||
httpTimeout, err := strconv.Atoi(mapConfig["http_timeout_sec"])
|
||||
|
|
@ -78,50 +81,56 @@ func init() {
|
|||
xmpp.VerifyCertValidity = mapConfig["xmpp_verify_cert_validity"] != "false" // Default TRUE
|
||||
}
|
||||
|
||||
func loadConfigFile() bool {
|
||||
ret := false
|
||||
func loadConfigurationFile(file string) string {
|
||||
ret := ""
|
||||
envVariable := os.Getenv(PathConfEnvVariable)
|
||||
if envVariable == "" {
|
||||
envVariable = DefaultXdgConfigDirs
|
||||
}
|
||||
for _, path := range strings.Split(envVariable, ":") {
|
||||
log.Println("Try to find configuration file into " + path)
|
||||
configFile := path + "/" + configurationFilePath
|
||||
log.Println("Try to find file (" + file + ") into " + path)
|
||||
configFile := path + "/" + configurationDirectory + "/" + file
|
||||
if _, err := os.Stat(configFile); err == nil {
|
||||
// The config file exist
|
||||
if cfg.Load(configFile, mapConfig) == nil {
|
||||
// And has been loaded succesfully
|
||||
log.Println("Find configuration file at " + configFile)
|
||||
ret = true
|
||||
break
|
||||
}
|
||||
// The file exist
|
||||
ret = configFile
|
||||
break
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func loadConfigFile() bool {
|
||||
ret := false
|
||||
configFile := loadConfigurationFile(configurationFilePath)
|
||||
if configFile != "" && cfg.Load(configFile, mapConfig) == nil {
|
||||
// And has been loaded succesfully
|
||||
log.Println("Find configuration file at " + configFile)
|
||||
ret = true
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func loadLangFile() bool {
|
||||
ret := false
|
||||
envVariable := os.Getenv(PathConfEnvVariable)
|
||||
if envVariable == "" {
|
||||
envVariable = DefaultXdgConfigDirs
|
||||
}
|
||||
for _, path := range strings.Split(envVariable, ":") {
|
||||
log.Println("Try to find messages lang file into " + path)
|
||||
langFile := path + "/" + langFilePath
|
||||
if _, err := os.Stat(langFile); err == nil {
|
||||
// The config file exist
|
||||
if cfg.Load(langFile, xmpp.MapLangs) == nil {
|
||||
// And has been loaded succesfully
|
||||
log.Println("Find messages lang file at " + langFile)
|
||||
ret = true
|
||||
break
|
||||
}
|
||||
}
|
||||
langFile := loadConfigurationFile(langFilePath)
|
||||
if cfg.Load(langFile, xmpp.MapLangs) == nil {
|
||||
// And has been loaded succesfully
|
||||
log.Println("Find messages lang file at " + langFile)
|
||||
ret = true
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func loadOauthClientStore() {
|
||||
clientStore := loadConfigurationFile(oauthClientStoreFilePath)
|
||||
err := http.LoadConfigClient(clientStore)
|
||||
if err == nil {
|
||||
log.Printf("Find OAuth client store file at " + clientStore)
|
||||
} else {
|
||||
log.Printf("Failed to load OAuth client store: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
go http.Run()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>HTTP authentication over XMPP</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>HTTP authentication over XMPP</h1>
|
||||
<form action="/login" method="POST">
|
||||
<label for="username">Jabber ID</label>
|
||||
<input type="text" class="form-control" name="jid" placeholder="Please enter your JID">
|
||||
<button type="submit" class="btn btn-success">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue