From 4ddfe9e5c4281b9ace9fcc93d0511697e58f692d Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sun, 1 Mar 2020 18:21:46 +0100 Subject: [PATCH] token-validator: add OpenID connect with Epita CRI --- token-validator/auth_oidc.go | 118 +++++++++++++++++++++++++ token-validator/htdocs/views/auth.html | 38 +++++--- token-validator/main.go | 2 + 3 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 token-validator/auth_oidc.go diff --git a/token-validator/auth_oidc.go b/token-validator/auth_oidc.go new file mode 100644 index 0000000..18e7967 --- /dev/null +++ b/token-validator/auth_oidc.go @@ -0,0 +1,118 @@ +package main + +import ( + "context" + "encoding/hex" + "flag" + "fmt" + "log" + "net/http" + + "golang.org/x/oauth2" + + "github.com/coreos/go-oidc" + "github.com/julienschmidt/httprouter" +) + +var ( + oidcClientID = "" + oidcSecret = "" + oauth2Config oauth2.Config + oidcVerifier *oidc.IDTokenVerifier +) + +func init() { + flag.StringVar(&oidcClientID, "oidc-clientid", oidcClientID, "ClientID for OIDC") + flag.StringVar(&oidcSecret, "oidc-secret", oidcSecret, "Secret for OIDC") + + router.GET("/auth/CRI", redirectOIDC_CRI) + router.GET("/auth/complete", OIDC_CRI_complete) +} + +func initializeOIDC() { + if oidcClientID != "" && oidcSecret != "" { + provider, err := oidc.NewProvider(context.Background(), "https://cri.epita.fr/oidc") + if err != nil { + log.Fatal("Unable to setup oidc:", err) + } + + oauth2Config = oauth2.Config{ + ClientID: oidcClientID, + ClientSecret: oidcSecret, + RedirectURL: "https://adlin.nemunai.re" + baseURL + "/auth/complete", + + // Discovery returns the OAuth2 endpoints. + Endpoint: provider.Endpoint(), + + // "openid" is a required scope for OpenID Connect flows. + Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, + } + + oidcConfig := oidc.Config{ + ClientID: oidcClientID, + } + oidcVerifier = provider.Verifier(&oidcConfig) + } + +} + +func redirectOIDC_CRI(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + session, err := NewSession() + if err != nil { + http.Error(w, fmt.Sprintf("{'errmsg':%q}", err.Error()), http.StatusInternalServerError) + } else { + http.Redirect(w, r, oauth2Config.AuthCodeURL(hex.EncodeToString(session.Id)), http.StatusFound) + } +} + +func OIDC_CRI_complete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + idsession, err := hex.DecodeString(r.URL.Query().Get("state")) + if err != nil { + http.Error(w, fmt.Sprintf("{'errmsg':%q}", err.Error()), http.StatusBadRequest) + return + } + + session, err := getSession(idsession) + if err != nil { + http.Error(w, fmt.Sprintf("{'errmsg':%q}", err.Error()), http.StatusBadRequest) + return + } + + oauth2Token, err := oauth2Config.Exchange(context.Background(), r.URL.Query().Get("code")) + if err != nil { + http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError) + return + + } + rawIDToken, ok := oauth2Token.Extra("id_token").(string) + if !ok { + http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError) + return + + } + idToken, err := oidcVerifier.Verify(context.Background(), rawIDToken) + if err != nil { + http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError) + return + + } + + var claims struct { + Firstname string `json:"given_name"` + Lastname string `json:"family_name"` + Nickname string `json:"nickname"` + Username string `json:"preferred_username"` + Email string `json:"email"` + } + if err := idToken.Claims(&claims); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if err := completeAuth(w, claims.Username, &session); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + http.Redirect(w, r, "/", http.StatusFound) +} diff --git a/token-validator/htdocs/views/auth.html b/token-validator/htdocs/views/auth.html index 7312923..9096d68 100644 --- a/token-validator/htdocs/views/auth.html +++ b/token-validator/htdocs/views/auth.html @@ -1,16 +1,26 @@ -

Accès à votre compte

+
+
+

Accès à votre compte

+
+ + +
+
+ + +
+ +
-
-
- - + -
- - -
- - +
diff --git a/token-validator/main.go b/token-validator/main.go index 4f8093e..32e7af1 100644 --- a/token-validator/main.go +++ b/token-validator/main.go @@ -83,6 +83,8 @@ func main() { AuthFunc = dummyAuth } + initializeOIDC() + // Initialize contents log.Println("Opening database...") if err := DBInit(*dsn); err != nil {