admin: Handle team password
This commit is contained in:
parent
ed69dc6ba4
commit
5eeb1a6297
11 changed files with 299 additions and 40 deletions
|
|
@ -254,7 +254,7 @@ func generateClientCert(_ httprouter.Params, _ []byte) (interface{}, error) {
|
|||
serial := serial_b.Uint64()
|
||||
|
||||
// Let's pick a random password
|
||||
password, err := pki.GeneratePassword()
|
||||
password, err := fic.GeneratePassword()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
195
admin/api/password.go
Normal file
195
admin/api/password.go
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"text/template"
|
||||
|
||||
"srs.epita.fr/fic-server/admin/pki"
|
||||
"srs.epita.fr/fic-server/libfic"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
var OidcSecret = ""
|
||||
|
||||
func init() {
|
||||
router.POST("/api/password", apiHandler(
|
||||
func(httprouter.Params, []byte) (interface{}, error) {
|
||||
if passwd, err := fic.GeneratePassword(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return map[string]string{"password": passwd}, nil
|
||||
}
|
||||
}))
|
||||
router.GET("/api/teams/:tid/password", apiHandler(teamHandler(
|
||||
func(team fic.Team, _ []byte) (interface{}, error) {
|
||||
return team.Password, nil
|
||||
})))
|
||||
router.POST("/api/teams/:tid/password", apiHandler(teamHandler(
|
||||
func(team fic.Team, _ []byte) (interface{}, error) {
|
||||
if passwd, err := fic.GeneratePassword(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
team.Password = &passwd
|
||||
return team.Update()
|
||||
}
|
||||
})))
|
||||
router.GET("/api/dex.yaml", apiHandler(
|
||||
func(httprouter.Params, []byte) (interface{}, error) {
|
||||
return genDexConfig()
|
||||
}))
|
||||
router.POST("/api/dex.yaml", apiHandler(
|
||||
func(httprouter.Params, []byte) (interface{}, error) {
|
||||
if dexcfg, err := genDexConfig(); err != nil {
|
||||
return nil, err
|
||||
} else if err := ioutil.WriteFile(path.Join(pki.PKIDir, "shared", "dex-config.yaml"), []byte(dexcfg), 0644); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}))
|
||||
router.GET("/api/dex-password.tpl", apiHandler(
|
||||
func(httprouter.Params, []byte) (interface{}, error) {
|
||||
return genDexPasswordTpl()
|
||||
}))
|
||||
router.POST("/api/dex-password.tpl", apiHandler(
|
||||
func(httprouter.Params, []byte) (interface{}, error) {
|
||||
if dexcfg, err := genDexPasswordTpl(); err != nil {
|
||||
return nil, err
|
||||
} else if err := ioutil.WriteFile(path.Join(pki.PKIDir, "shared", "dex-password.tpl"), []byte(dexcfg), 0644); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
const dexcfgtpl = `issuer: https://fic.srs.epita.fr
|
||||
storage:
|
||||
type: sqlite3
|
||||
config:
|
||||
file: /var/dex/dex.db
|
||||
web:
|
||||
http: 0.0.0.0:5556
|
||||
frontend:
|
||||
issuer: Challenge forensic
|
||||
logoURL: img/fic.png
|
||||
dir: /srv/dex/web/
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
{{ range $c := .Clients }}
|
||||
- id: {{ $c.Id }}
|
||||
name: {{ $c.Name }}
|
||||
redirectURIs: [{{ range $u := $c.RedirectURIs }}'{{ $u }}'{{ end }}]
|
||||
secret: {{ $c.Secret }}
|
||||
{{ end }}
|
||||
enablePasswordDB: true
|
||||
staticPasswords:
|
||||
{{ range $t := .Teams }}
|
||||
- email: "team{{ printf "%02d" $t.Id }}"
|
||||
hash: "{{with $t }}{{ .HashedPassword }}{{end}}"
|
||||
{{ end }}
|
||||
`
|
||||
|
||||
const dexpasswdtpl = `{{ "{{" }} template "header.html" . {{ "}}" }}
|
||||
|
||||
<div class="theme-panel">
|
||||
<h2 class="theme-heading">
|
||||
Bienvenue au challenge Forensic !
|
||||
</h2>
|
||||
<form method="post" action="{{ "{{" }} .PostURL {{ "}}" }}">
|
||||
<div class="theme-form-row">
|
||||
<div class="theme-form-label">
|
||||
<label for="userid">Votre équipe</label>
|
||||
</div>
|
||||
<select tabindex="1" required id="login" name="login" class="theme-form-input" autofocus>
|
||||
{{ range $t := .Teams }} <option value="team{{ printf "%02d" $t.Id }}">{{ $t.Name }}</option>
|
||||
{{ end }} </select>
|
||||
</div>
|
||||
<div class="theme-form-row">
|
||||
<div class="theme-form-label">
|
||||
<label for="password">Mot de passe</label>
|
||||
</div>
|
||||
<input tabindex="2" required id="password" name="password" type="password" class="theme-form-input" placeholder="mot de passe" {{ "{{" }} if .Invalid {{ "}}" }} autofocus {{ "{{" }} end {{ "}}" }}/>
|
||||
</div>
|
||||
|
||||
{{ "{{" }} if .Invalid {{ "}}" }}
|
||||
<div id="login-error" class="dex-error-box">
|
||||
Identifiants incorrects.
|
||||
</div>
|
||||
{{ "{{" }} end {{ "}}" }}
|
||||
|
||||
<button tabindex="3" id="submit-login" type="submit" class="dex-btn theme-btn--primary">C'est parti !</button>
|
||||
|
||||
</form>
|
||||
{{ "{{" }} if .BackLink {{ "}}" }}
|
||||
<div class="theme-link-back">
|
||||
<a class="dex-subtle-text" href="{{ "{{" }} .BackLink {{ "}}" }}">Sélectionner une autre méthode d'authentification.</a>
|
||||
</div>
|
||||
{{ "{{" }} end {{ "}}" }}
|
||||
</div>
|
||||
|
||||
{{ "{{" }} template "footer.html" . {{ "}}" }}
|
||||
`
|
||||
|
||||
type dexConfigClient struct {
|
||||
Id string
|
||||
Name string
|
||||
RedirectURIs []string
|
||||
Secret string
|
||||
}
|
||||
|
||||
type dexConfig struct {
|
||||
Clients []dexConfigClient
|
||||
Teams []fic.Team
|
||||
}
|
||||
|
||||
func genDexConfig() ([]byte, error) {
|
||||
if teams, err := fic.GetTeams(); err != nil {
|
||||
return nil, err
|
||||
} else if OidcSecret == "" {
|
||||
return nil, fmt.Errorf("Unable to generate dex configuration: OIDC Secret not defined. Please define FICOIDC_SECRET in your environment.")
|
||||
} else {
|
||||
b := bytes.NewBufferString("")
|
||||
|
||||
if dexTmpl, err := template.New("dexcfg").Parse(dexcfgtpl); err != nil {
|
||||
return nil, fmt.Errorf("Cannot create template: %w", err)
|
||||
} else if err = dexTmpl.Execute(b, dexConfig{
|
||||
Clients: []dexConfigClient{
|
||||
dexConfigClient{
|
||||
Id: "epita-challenge",
|
||||
Name: "Challenge Forensic",
|
||||
RedirectURIs: []string{"https://fic.srs.epita.fr/challenge_access/auth"},
|
||||
Secret: OidcSecret,
|
||||
},
|
||||
},
|
||||
Teams: teams,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("An error occurs during template execution: %w", err)
|
||||
} else {
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func genDexPasswordTpl() ([]byte, error) {
|
||||
if teams, err := fic.GetTeams(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
b := bytes.NewBufferString("")
|
||||
|
||||
if dexTmpl, err := template.New("dexpasswd").Parse(dexpasswdtpl); err != nil {
|
||||
return nil, fmt.Errorf("Cannot create template: %w", err)
|
||||
} else if err = dexTmpl.Execute(b, dexConfig{
|
||||
Teams: teams,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("An error occurs during template execution: %w", err)
|
||||
} else {
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -171,6 +171,10 @@ func updateTeam(team fic.Team, body []byte) (interface{}, error) {
|
|||
|
||||
ut.Id = team.Id
|
||||
|
||||
if *ut.Password == "" {
|
||||
ut.Password = nil
|
||||
}
|
||||
|
||||
if _, err := ut.Update(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue