token-handler: handle authorization through Epita CRI LDAP
This commit is contained in:
parent
58e541d6ad
commit
38902bee8d
77
token-validator/auth.go
Normal file
77
token-validator/auth.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.GET("/auth", authHandler(apiHandler(validateAuthToken, printStudent)))
|
||||||
|
router.POST("/auth", apiHandler(checkAuth))
|
||||||
|
}
|
||||||
|
|
||||||
|
func printStudent(std *Student, r *http.Request) error {
|
||||||
|
if std != nil {
|
||||||
|
return errors.New(fmt.Sprintf("%s", *std))
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateAuthToken(_ httprouter.Params, _ []byte) (interface{}, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type loginForm struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkAuth(_ httprouter.Params, body []byte) (interface{}, error) {
|
||||||
|
var lf loginForm
|
||||||
|
if err := json.Unmarshal(body, &lf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r, err := http.NewRequest("GET", "https://owncloud.srs.epita.fr/remote.php/webdav/", nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
r.SetBasicAuth(lf.Username, lf.Password)
|
||||||
|
|
||||||
|
if resp, err := http.DefaultClient.Do(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
var std Student
|
||||||
|
if !studentExists(lf.Username) {
|
||||||
|
if std, err = NewStudent(lf.Username); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else if std, err = getStudentByLogin(lf.Username); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := std.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := map[string]interface{}{}
|
||||||
|
res["status"] = "OK"
|
||||||
|
res["id_session"] = session.Id
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(`{"status": "Invalid username or password"}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
@ -102,6 +102,16 @@ CREATE TABLE IF NOT EXISTS student_pong(
|
|||||||
time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY(id_student) REFERENCES students(id_student)
|
FOREIGN KEY(id_student) REFERENCES students(id_student)
|
||||||
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS student_sessions(
|
||||||
|
id_session BLOB(255) NOT NULL,
|
||||||
|
id_student INTEGER NOT NULL,
|
||||||
|
time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY(id_student) REFERENCES students(id_student)
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
@ -38,6 +39,20 @@ func remoteValidatorHandler(f func(http.ResponseWriter, *http.Request, httproute
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func authHandler(f func(http.ResponseWriter, *http.Request, httprouter.Params)) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
if flds := strings.Fields(r.Header.Get("Authorization")); len(flds) != 2 || flds[0] != "Bearer" {
|
||||||
|
http.Error(w, `{"errmsg": "Authorization required"}`, http.StatusUnauthorized)
|
||||||
|
} else if sessionid, err := base64.StdEncoding.DecodeString(flds[1]); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf(`{"errmsg": %q}`, err), http.StatusNotAcceptable)
|
||||||
|
} else if _, err := getSession(sessionid); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf(`{"errmsg": %q}`, err), http.StatusUnauthorized)
|
||||||
|
} else {
|
||||||
|
f(w, r, ps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func rawHandler(f func(*http.Request, httprouter.Params, []byte) (interface{}, error), access ...func(*Student, *http.Request) error) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
func rawHandler(f func(*http.Request, httprouter.Params, []byte) (interface{}, error), access ...func(*Student, *http.Request) error) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
||||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
||||||
@ -50,10 +65,26 @@ func rawHandler(f func(*http.Request, httprouter.Params, []byte) (interface{}, e
|
|||||||
var ret interface{}
|
var ret interface{}
|
||||||
var err error = nil
|
var err error = nil
|
||||||
|
|
||||||
|
// Read Authorization header
|
||||||
|
var student *Student = nil
|
||||||
|
if flds := strings.Fields(r.Header.Get("Authorization")); len(flds) == 2 && flds[0] == "Bearer" {
|
||||||
|
if sessionid, err := base64.StdEncoding.DecodeString(flds[1]); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf(`{"errmsg": %q}`, err), http.StatusNotAcceptable)
|
||||||
|
} else if session, err := getSession(sessionid); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf(`{"errmsg": %q}`, err), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
} else if std, err := getStudent(int(session.IdStudent)); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf(`{"errmsg": %q}`, err), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
student = &std
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check access limitation
|
// Check access limitation
|
||||||
for _, a := range access {
|
for _, a := range access {
|
||||||
if err := a(nil, r); err != nil {
|
if err := a(student, r); err != nil {
|
||||||
http.Error(w, fmt.Sprintf("{errmsg:\"You're not allowed to access this page this way!\"}", err), http.StatusForbidden)
|
http.Error(w, fmt.Sprintf(`{"errmsg":%q}`, err), http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,11 @@ func showIPs(_ httprouter.Params, body []byte) (interface{}, error) {
|
|||||||
|
|
||||||
r[sid] = make(map[string]string)
|
r[sid] = make(map[string]string)
|
||||||
|
|
||||||
r[sid]["mac"] = std.MAC
|
if std.MAC == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r[sid]["mac"] = *std.MAC
|
||||||
r[sid]["vlan0"] = fmt.Sprintf("172.23.0.%d", std.IPSuffix())
|
r[sid]["vlan0"] = fmt.Sprintf("172.23.0.%d", std.IPSuffix())
|
||||||
r[sid]["vlan7"] = fmt.Sprintf("172.23.142.%d", std.IPSuffix())
|
r[sid]["vlan7"] = fmt.Sprintf("172.23.142.%d", std.IPSuffix())
|
||||||
}
|
}
|
||||||
|
58
token-validator/session.go
Normal file
58
token-validator/session.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
Id []byte `json:"id"`
|
||||||
|
IdStudent int64 `json:"login"`
|
||||||
|
Time time.Time `json:"time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSession(id []byte) (s Session, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_session, id_student, time FROM student_sessions WHERE id_session=?", id).Scan(&s.Id, &s.IdStudent, &s.Time)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (student Student) NewSession() (Session, error) {
|
||||||
|
session_id := make([]byte, 255)
|
||||||
|
if _, err := rand.Read(session_id); err != nil {
|
||||||
|
return Session{}, err
|
||||||
|
} else if _, err := DBExec("INSERT INTO student_sessions (id_session, id_student, time) VALUES (?, ?, ?)", session_id, student.Id, time.Now()); err != nil {
|
||||||
|
return Session{}, err
|
||||||
|
} else {
|
||||||
|
return Session{session_id, student.Id, time.Now()}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Session) Update() (int64, error) {
|
||||||
|
if res, err := DBExec("UPDATE student_sessions SET id_student = ?, time = ? WHERE id_session = ?", s.IdStudent, s.Time, s.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Session) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM student_sessions WHERE id_session = ?", s.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearSession() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM student_sessions"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
@ -59,11 +59,11 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Student struct {
|
type Student struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Login string `json:"login"`
|
Login string `json:"login"`
|
||||||
Time time.Time `json:"time"`
|
Time *time.Time `json:"time"`
|
||||||
IP string `json:"ip"`
|
IP *string `json:"ip"`
|
||||||
MAC string `json:"mac"`
|
MAC *string `json:"mac"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type uploadedStudent struct {
|
type uploadedStudent struct {
|
||||||
@ -106,16 +106,17 @@ func getStudentByLogin(login string) (s Student, err error) {
|
|||||||
func studentExists(login string) bool {
|
func studentExists(login string) bool {
|
||||||
var z int
|
var z int
|
||||||
err := DBQueryRow("SELECT 1 FROM students WHERE login=?", login).Scan(&z)
|
err := DBQueryRow("SELECT 1 FROM students WHERE login=?", login).Scan(&z)
|
||||||
return err != nil && z == 1
|
return err == nil && z == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStudent(login string) (Student, error) {
|
func NewStudent(login string) (Student, error) {
|
||||||
if res, err := DBExec("INSERT INTO students (login, time) VALUES (?, ?)", login, time.Now()); err != nil {
|
t := time.Now()
|
||||||
|
if res, err := DBExec("INSERT INTO students (login, time) VALUES (?, ?)", login, t); err != nil {
|
||||||
return Student{}, err
|
return Student{}, err
|
||||||
} else if sid, err := res.LastInsertId(); err != nil {
|
} else if sid, err := res.LastInsertId(); err != nil {
|
||||||
return Student{}, err
|
return Student{}, err
|
||||||
} else {
|
} else {
|
||||||
return Student{sid, login, time.Now(), "", ""}, nil
|
return Student{sid, login, &t, nil, nil}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +169,8 @@ func createStudent(_ httprouter.Params, body []byte) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
exist.registerAccess(std.IP, std.MAC)
|
exist.registerAccess(std.IP, std.MAC)
|
||||||
|
|
||||||
exist.IP = fmt.Sprintf("172.23.0.%d", exist.IPSuffix())
|
ip := fmt.Sprintf("172.23.0.%d", exist.IPSuffix())
|
||||||
|
exist.IP = &ip
|
||||||
|
|
||||||
return exist, nil
|
return exist, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user