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
@@ -9,10 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type Credentials struct {
|
||||
Method string // "password" ou "oidc"
|
||||
Email string
|
||||
Password string
|
||||
OIDCCode string
|
||||
Method string // "password" ou "oidc"
|
||||
Email string
|
||||
Password string
|
||||
OIDCCode string
|
||||
OIDCState string
|
||||
RedirectURI string
|
||||
}
|
||||
|
||||
type Registration struct {
|
||||
@@ -45,6 +47,15 @@ type Authenticator interface {
|
||||
type TokenManager interface {
|
||||
GenerateAccessToken(user *domain.User) (string, time.Time, error)
|
||||
GenerateRefreshToken(userID string) (string, time.Time, error)
|
||||
GenerateStateToken(data string) (string, error)
|
||||
ParseStateToken(state string) (string, error)
|
||||
ParseAndValidate(tokenString string) (*domain.User, error)
|
||||
TokenMiddleware(next echo.HandlerFunc) echo.HandlerFunc
|
||||
}
|
||||
|
||||
// OIDCManager est le port implémenté par l'adaptateur OpenID Connect.
|
||||
// Il gère la redirection vers le fournisseur et l'échange du code d'autorisation.
|
||||
type OIDCManager interface {
|
||||
AuthorizeURL(ctx context.Context, provider *domain.OIDCProvider, redirectURI string, state string) (string, error)
|
||||
ExchangeCode(ctx context.Context, provider *domain.OIDCProvider, code string, redirectURI string) (*Session, error)
|
||||
}
|
||||
@@ -17,20 +17,31 @@ var (
|
||||
|
||||
type Service struct {
|
||||
authenticators map[string]Authenticator // "password" -> ..., "oidc" -> ...
|
||||
oidcManager OIDCManager
|
||||
tokenManager TokenManager
|
||||
userRepository domain.UserRepository
|
||||
oidcRepository domain.OIDCProviderRepository
|
||||
settingsRepository domain.SettingsRepository
|
||||
}
|
||||
|
||||
func NewService(
|
||||
settingsRepository domain.SettingsRepository,
|
||||
userRepository domain.UserRepository,
|
||||
oidcRepository domain.OIDCProviderRepository,
|
||||
tokenManager TokenManager,
|
||||
authenticators map[string]Authenticator,
|
||||
) *Service {
|
||||
return &Service{
|
||||
service := &Service{
|
||||
authenticators: authenticators,
|
||||
tokenManager: tokenManager,
|
||||
userRepository: userRepository,
|
||||
oidcRepository: oidcRepository,
|
||||
settingsRepository: settingsRepository,
|
||||
}
|
||||
if manager, ok := authenticators["oidc"].(OIDCManager); ok {
|
||||
service.oidcManager = manager
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
func (s *Service) Login(ctx context.Context, creds Credentials) (*Session, error) {
|
||||
@@ -72,3 +83,37 @@ func (s *Service) Register(registration Registration) (*Session, error) {
|
||||
func (s *Service) Status(session *Session) (*domain.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ListOIDCProviders retourne les fournisseurs OpenID Connect enregistrés,
|
||||
// sans exposer le secret client (champ marqué json:"-").
|
||||
func (s *Service) ListOIDCProviders() ([]*domain.OIDCProvider, error) {
|
||||
return s.oidcRepository.ListOIDCProviders()
|
||||
}
|
||||
|
||||
// OIDCAuthorizeURL construit l'URL d'autorisation du fournisseur, avec un
|
||||
// state signé transportant l'id du fournisseur.
|
||||
func (s *Service) OIDCAuthorizeURL(ctx context.Context, providerID string, redirectURI string) (string, error) {
|
||||
provider, err := s.oidcRepository.FindOIDCProvider(providerID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unknown oidc provider: %s", providerID)
|
||||
}
|
||||
state, err := s.tokenManager.GenerateStateToken(providerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s.oidcManager.AuthorizeURL(ctx, provider, redirectURI, state)
|
||||
}
|
||||
|
||||
// OIDCCallback traite le retour du fournisseur: vérifie le state, échange le
|
||||
// code d'autorisation et délivre une session applicative.
|
||||
func (s *Service) OIDCCallback(ctx context.Context, state string, code string, redirectURI string) (*Session, error) {
|
||||
providerID, err := s.tokenManager.ParseStateToken(state)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid oidc state: %s", err)
|
||||
}
|
||||
provider, err := s.oidcRepository.FindOIDCProvider(providerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unknown oidc provider: %s", providerID)
|
||||
}
|
||||
return s.oidcManager.ExchangeCode(ctx, provider, code, redirectURI)
|
||||
}
|
||||
Reference in new issue
Block a user