From ff9c6bacdf5e2e48647976ab596959368f819e61 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 26 Feb 2019 16:48:55 +0100 Subject: [PATCH] token-validator: fix ssh part and add support for ssh-piperd --- token-validator/main.go | 3 +- token-validator/ssh.go | 81 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/token-validator/main.go b/token-validator/main.go index 58d2c85..777ef40 100644 --- a/token-validator/main.go +++ b/token-validator/main.go @@ -58,7 +58,8 @@ func main() { var dsn = flag.String("dsn", DSNGenerator(), "DSN to connect to the MySQL server") var baseURL = flag.String("baseurl", "/", "URL prepended to each URL") flag.StringVar(&sharedSecret, "sharedsecret", "adelina", "secret used to communicate with remote validator") - flag.StringVar(&AuthorizedKeyLocation, "authorizedkeyslocation", Authorizedkeyslocation, "File for allowing user to SSH to the machine") + flag.StringVar(&AuthorizedKeysLocation, "authorizedkeyslocation", AuthorizedKeysLocation, "File for allowing user to SSH to the machine") + flag.StringVar(&SshPiperLocation, "sshPiperLocation", SshPiperLocation, "Directory containing directories for sshpiperd") flag.Parse() // Sanitize options diff --git a/token-validator/ssh.go b/token-validator/ssh.go index fac00a9..e8d9448 100644 --- a/token-validator/ssh.go +++ b/token-validator/ssh.go @@ -10,12 +10,15 @@ import ( "log" "net/http" "os" + "path" + "strconv" "time" "github.com/julienschmidt/httprouter" ) -var AuthorizedKeyLocation = "/var/lib/adlin/.ssh/authorized_keys" +var AuthorizedKeysLocation = "/var/lib/adlin/.ssh/authorized_keys" +var SshPiperLocation = "/var/sshpiper/" func init() { router.GET("/sshkeys/", apiHandler( @@ -23,9 +26,23 @@ func init() { return getStudentKeys() })) router.POST("/sshkeys/", rawHandler(receiveKey)) - router.GET("/sshkeys/authorizedkey", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + router.GET("/sshkeys/authorizedkeys", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { dumpAuthorizedKeysFile(w) }) + router.GET("/api/students/:sid/authorizedkeys", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + if sid, err := strconv.Atoi(string(ps.ByName("sid"))); err != nil { + if student, err := getStudentByLogin(ps.ByName("sid")); err != nil { + http.Error(w, "Student doesn't exist.", http.StatusNotFound) + } else { + student.dumpAuthorizedKeysFile(w) + } + } else if student, err := getStudent(sid); err != nil { + http.Error(w, "Student doesn't exist.", http.StatusNotFound) + } else { + student.dumpAuthorizedKeysFile(w) + } + + }) } type StudentKey struct { @@ -56,6 +73,27 @@ func getStudentKeys() (keys []StudentKey, err error) { } } +func (s Student) getKeys() (keys []StudentKey, err error) { + if rows, errr := DBQuery("SELECT id_key, id_student, sshkey, time FROM student_keys WHERE id_student = ?", s.Id); errr != nil { + return nil, errr + } else { + defer rows.Close() + + for rows.Next() { + var k StudentKey + if err = rows.Scan(&k.Id, &k.IdStudent, &k.Key, &k.Time); err != nil { + return + } + keys = append(keys, k) + } + if err = rows.Err(); err != nil { + return + } + + return + } +} + func getStudentKey(id int) (k StudentKey, err error) { err = DBQueryRow("SELECT id_key, id_student, sshkey, time FROM student_keys WHERE id_key=?", id).Scan(&k.Id, &k.IdStudent, &k.Key, &k.Time) return @@ -130,16 +168,34 @@ func receiveKey(r *http.Request, ps httprouter.Params, body []byte) (interface{} log.Printf("%s just pushed sshkey\n", std.Login) - if len(AuthorizedKeyLocation) > 0 { - file, err := os.Create(AuthorizedKeyLocation) + if len(AuthorizedKeysLocation) > 0 { + file, err := os.Create(AuthorizedKeysLocation) if err != nil { log.Fatal("Cannot create file", err) + goto sshpiperimport } defer file.Close() dumpAuthorizedKeysFile(file) } + sshpiperimport: + if len(SshPiperLocation) > 0 { + if err := os.MkdirAll(path.Join(SshPiperLocation, std.Login), 0777); err != nil { + log.Fatal("Cannot create sshpiper directory:", err) + } else { + file, err := os.Create(path.Join(SshPiperLocation, std.Login, "authorized_keys")) + if err != nil { + log.Fatal("Cannot create sshpiperd file", err) + goto onerr + } + defer file.Close() + + std.dumpAuthorizedKeysFile(file) + } + } + + onerr: return "Key imported", nil } } @@ -160,3 +216,20 @@ func dumpAuthorizedKeysFile(w io.Writer) { } } } + +func (s Student) dumpAuthorizedKeysFile(w io.Writer) { + seen := map[string]interface{}{} + + if keys, _ := s.getKeys(); keys != nil { + for _, k := range keys { + if _, exists := seen[k.Key]; exists { + continue + } else { + seen[k.Key] = true + } + + s, _ := k.GetStudent() + w.Write([]byte("ssh-ed25519 " + k.Key + fmt.Sprintf(" Student#%d-%q\n", k.IdStudent, s.Login))) + } + } +}