2020-07-10 18:07:41 +02:00
|
|
|
package route
|
|
|
|
|
|
|
|
import (
|
2020-08-13 10:29:52 +02:00
|
|
|
"fmt"
|
2020-07-10 18:07:41 +02:00
|
|
|
"net/http"
|
|
|
|
|
2020-08-13 10:29:52 +02:00
|
|
|
"forge.cadoles.com/Cadoles/daddy/internal/auth"
|
|
|
|
|
2020-07-16 09:28:27 +02:00
|
|
|
"forge.cadoles.com/Cadoles/daddy/internal/model"
|
|
|
|
"forge.cadoles.com/Cadoles/daddy/internal/orm"
|
2020-07-13 14:44:05 +02:00
|
|
|
|
|
|
|
"forge.cadoles.com/Cadoles/daddy/internal/session"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
2020-07-10 18:07:41 +02:00
|
|
|
"forge.cadoles.com/Cadoles/daddy/internal/config"
|
|
|
|
oidc "forge.cadoles.com/wpetit/goweb-oidc"
|
|
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
|
|
"gitlab.com/wpetit/goweb/middleware/container"
|
|
|
|
)
|
|
|
|
|
|
|
|
func handleLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctn := container.Must(r.Context())
|
|
|
|
client := oidc.Must(ctn)
|
|
|
|
client.Login(w, r)
|
|
|
|
}
|
|
|
|
|
2020-07-13 14:44:05 +02:00
|
|
|
type emailClaims struct {
|
|
|
|
Email string `json:"email"`
|
|
|
|
EmailVerified bool `json:"email_verified"`
|
|
|
|
}
|
|
|
|
|
2020-07-10 18:07:41 +02:00
|
|
|
func handleLoginCallback(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
ctn := container.Must(ctx)
|
|
|
|
conf := config.Must(ctn)
|
2020-08-13 10:29:52 +02:00
|
|
|
auth := auth.Must(ctn)
|
2020-07-10 18:07:41 +02:00
|
|
|
|
|
|
|
idToken, err := oidc.IDToken(w, r)
|
|
|
|
if err != nil {
|
|
|
|
logger.Error(ctx, "could not retrieve idToken", logger.E(err))
|
|
|
|
|
|
|
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.Info(ctx, "user logged in", logger.F("sub", idToken.Subject))
|
|
|
|
|
2020-07-13 14:44:05 +02:00
|
|
|
claims := &emailClaims{}
|
|
|
|
if err := idToken.Claims(claims); err != nil {
|
|
|
|
panic(errors.WithStack(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO implements better UX in case of errors
|
|
|
|
|
|
|
|
if claims.Email == "" {
|
|
|
|
http.Error(w, "an email is expected to access this app", http.StatusForbidden)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !claims.EmailVerified {
|
|
|
|
http.Error(w, "your email must be verified to access this app", http.StatusForbidden)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-07-16 09:28:27 +02:00
|
|
|
db := orm.Must(ctn).DB()
|
|
|
|
repo := model.NewUserRepository(db)
|
2020-07-13 14:44:05 +02:00
|
|
|
|
2020-08-13 10:29:52 +02:00
|
|
|
user, err := repo.CreateOrConnectUser(ctx, claims.Email)
|
|
|
|
if err != nil {
|
2020-07-16 09:28:27 +02:00
|
|
|
panic(errors.Wrap(err, "could not upsert user"))
|
2020-07-13 14:44:05 +02:00
|
|
|
}
|
|
|
|
|
2020-08-13 10:29:52 +02:00
|
|
|
authorized, err := auth.Authorize(user)
|
|
|
|
if err != nil {
|
|
|
|
panic(errors.WithStack(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
if !authorized {
|
|
|
|
message := fmt.Sprintf(
|
|
|
|
"You are not authorized to access this application. Disconnect by navigating to %s.",
|
|
|
|
"http://"+r.Host+"/logout",
|
|
|
|
)
|
|
|
|
http.Error(w, message, http.StatusForbidden)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-07-13 14:44:05 +02:00
|
|
|
if err := session.SaveUserEmail(w, r, claims.Email); err != nil {
|
|
|
|
panic(errors.WithStack(err))
|
|
|
|
}
|
|
|
|
|
2020-07-10 18:07:41 +02:00
|
|
|
http.Redirect(w, r, conf.HTTP.FrontendURL, http.StatusSeeOther)
|
|
|
|
}
|