authentification OpenID Connect (Keycloak) : flux authorization code, state signé, validation du token ID via JWKS, provisioning automatique des utilisateurs
This commit is contained in:
1 parent
51bbb45b32
commit
bedb6c98e7
15 files changed
+1057
-23
No files matched your search
@@ -17,6 +17,8 @@ func NewAuthGroup(prefix string, e *echo.Group, service *auth.Service) *echo.Gro
|
||||
}
|
||||
auth := e.Group(prefix)
|
||||
auth.POST("/login", authHandler.Login)
|
||||
auth.GET("/oidc/providers", authHandler.OIDCProviders)
|
||||
auth.GET("/oidc/login", authHandler.OIDCLogin)
|
||||
auth.GET("/oidc/callback", authHandler.OIDCCallback)
|
||||
auth.POST("/register", authHandler.Register)
|
||||
return auth
|
||||
@@ -69,8 +71,77 @@ func (h AuthHandler) Login(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// oidcRedirectURI reconstruit l'URL de callback du serveur à partir de la
|
||||
// requête. Elle doit être identique entre /oidc/login et /oidc/callback.
|
||||
func oidcRedirectURI(c *echo.Context) string {
|
||||
scheme := "http"
|
||||
if proto := c.Request().Header.Get("X-Forwarded-Proto"); proto != "" {
|
||||
scheme = proto
|
||||
} else if c.Request().TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
host := c.Request().Header.Get("X-Forwarded-Host")
|
||||
if host == "" {
|
||||
host = c.Request().Host
|
||||
}
|
||||
return scheme + "://" + host + "/api/auth/oidc/callback"
|
||||
}
|
||||
|
||||
func (h AuthHandler) OIDCProviders(c *echo.Context) error {
|
||||
providers, err := h.authService.ListOIDCProviders()
|
||||
if err != nil {
|
||||
c.Logger().Error(fmt.Sprintf("error listing oidc providers: %s", err))
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "error listing oidc providers")
|
||||
}
|
||||
return c.JSON(http.StatusOK, providers)
|
||||
}
|
||||
|
||||
func (h AuthHandler) OIDCLogin(c *echo.Context) error {
|
||||
providerID := c.QueryParam("provider")
|
||||
if providerID == "" {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "provider query parameter is required")
|
||||
}
|
||||
|
||||
authorizeURL, err := h.authService.OIDCAuthorizeURL(context.Background(), providerID, oidcRedirectURI(c))
|
||||
if err != nil {
|
||||
c.Logger().Error(fmt.Sprintf("error building oidc authorize url: %s", err))
|
||||
return c.Redirect(http.StatusFound, "/login?error=oidc")
|
||||
}
|
||||
return c.Redirect(http.StatusFound, authorizeURL)
|
||||
}
|
||||
|
||||
func (h AuthHandler) OIDCCallback(c *echo.Context) error {
|
||||
return nil
|
||||
if errParam := c.QueryParam("error"); errParam != "" {
|
||||
c.Logger().Error(fmt.Sprintf("oidc provider returned an error: %s", errParam))
|
||||
return c.Redirect(http.StatusFound, "/login?error=oidc")
|
||||
}
|
||||
code := c.QueryParam("code")
|
||||
state := c.QueryParam("state")
|
||||
if code == "" || state == "" {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "code and state are required")
|
||||
}
|
||||
|
||||
session, err := h.authService.OIDCCallback(context.Background(), state, code, oidcRedirectURI(c))
|
||||
if err != nil {
|
||||
c.Logger().Error(fmt.Sprintf("error while oidc callback: %s", err))
|
||||
return c.Redirect(http.StatusFound, "/login?error=oidc")
|
||||
}
|
||||
|
||||
// L'application SPA est servie par ce même serveur (même origine) et lit
|
||||
// ses tokens dans localStorage: on les dépose ici puis on redirige vers
|
||||
// l'application, sans jamais les faire transiter dans une URL.
|
||||
page := fmt.Sprintf(`<!doctype html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"><title>Connexion en cours...</title></head>
|
||||
<body>
|
||||
<script>
|
||||
localStorage.setItem("accessToken", %q);
|
||||
localStorage.setItem("refreshToken", %q);
|
||||
location.replace("/");
|
||||
</script>
|
||||
</body>
|
||||
</html>`, session.AccessToken, session.RefreshToken)
|
||||
return c.Blob(http.StatusOK, "text/html; charset=utf-8", []byte(page))
|
||||
}
|
||||
|
||||
func (h AuthHandler) Register(c *echo.Context) error {
|
||||
|
||||
Reference in new issue
Block a user