feat: encryption keys in database (#3265)

* enable overwrite of adminUser fields in defaults.yaml

* create schema and table

* cli: create keys

* cli: create keys

* read encryptionkey from db

* merge v2

* file names

* cleanup defaults.yaml

* remove custom errors

* load encryptionKeys on start

* cleanup

* fix merge

* update system defaults

* fix error message
This commit is contained in:
Livio Amstutz
2022-03-14 07:55:09 +01:00
committed by GitHub
parent 7899a0b851
commit 5463244376
57 changed files with 1618 additions and 471 deletions

View File

@@ -74,7 +74,7 @@ func (l *Login) handleExternalLogin(w http.ResponseWriter, r *http.Request) {
return
}
if authReq == nil {
http.Redirect(w, r, l.zitadelURL, http.StatusFound)
http.Redirect(w, r, l.consolePath, http.StatusFound)
return
}
l.handleIDP(w, r, authReq, data.IDPConfigID)
@@ -121,7 +121,7 @@ func (l *Login) handleJWTAuthorize(w http.ResponseWriter, r *http.Request, authR
l.renderLogin(w, r, authReq, caos_errors.ThrowPreconditionFailed(nil, "LOGIN-dsgg3", "Errors.AuthRequest.UserAgentNotFound"))
return
}
nonce, err := l.IDPConfigAesCrypto.Encrypt([]byte(userAgentID))
nonce, err := l.idpConfigAlg.Encrypt([]byte(userAgentID))
if err != nil {
l.renderLogin(w, r, authReq, err)
return
@@ -167,7 +167,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
}
func (l *Login) getRPConfig(idpConfig *iam_model.IDPConfigView, callbackEndpoint string) (rp.RelyingParty, error) {
oidcClientSecret, err := crypto.DecryptString(idpConfig.OIDCClientSecret, l.IDPConfigAesCrypto)
oidcClientSecret, err := crypto.DecryptString(idpConfig.OIDCClientSecret, l.idpConfigAlg)
if err != nil {
return nil, err
}

View File

@@ -58,7 +58,7 @@ func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) {
return
}
if authReq == nil {
http.Redirect(w, r, l.zitadelURL, http.StatusFound)
http.Redirect(w, r, l.consolePath, http.StatusFound)
return
}
idpConfig, err := l.getIDPConfigByID(r, data.IDPConfigID)
@@ -145,12 +145,12 @@ func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, aut
memberRoles = nil
resourceOwner = authReq.RequestedOrgID
}
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.UserCodeAlg)
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.UserCodeAlg)
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
@@ -226,12 +226,12 @@ func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Reque
l.renderRegisterOption(w, r, authReq, err)
return
}
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.UserCodeAlg)
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.UserCodeAlg)
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return

View File

@@ -70,7 +70,7 @@ func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *dom
userOrg = authReq.UserOrgID
}
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
passwordCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordResetCode, l.UserCodeAlg)
passwordCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordResetCode, l.userCodeAlg)
if err != nil {
l.renderInitPassword(w, r, authReq, data.UserID, "", err)
return
@@ -97,7 +97,7 @@ func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authRe
l.renderInitPassword(w, r, authReq, authReq.UserID, "", err)
return
}
passwordCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordResetCode, l.UserCodeAlg)
passwordCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordResetCode, l.userCodeAlg)
if err != nil {
l.renderInitPassword(w, r, authReq, authReq.UserID, "", err)
return

View File

@@ -73,7 +73,7 @@ func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authRe
if authReq != nil {
userOrgID = authReq.UserOrgID
}
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.UserCodeAlg)
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg)
if err != nil {
l.renderInitUser(w, r, authReq, data.UserID, "", data.PasswordSet, err)
return
@@ -91,7 +91,7 @@ func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *
if authReq != nil {
userOrgID = authReq.UserOrgID
}
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.UserCodeAlg)
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg)
if err != nil {
l.renderInitUser(w, r, authReq, userID, "", showPassword, err)
return

View File

@@ -39,7 +39,7 @@ func (l *Login) handleJWTRequest(w http.ResponseWriter, r *http.Request) {
l.renderError(w, r, nil, err)
return
}
userAgentID, err := l.IDPConfigAesCrypto.DecryptString(id, l.IDPConfigAesCrypto.EncryptionKeyID())
userAgentID, err := l.idpConfigAlg.DecryptString(id, l.idpConfigAlg.EncryptionKeyID())
if err != nil {
l.renderError(w, r, nil, err)
return
@@ -181,7 +181,7 @@ func (l *Login) redirectToJWTCallback(authReq *domain.AuthRequest) (string, erro
}
q := redirect.Query()
q.Set(QueryAuthRequestID, authReq.ID)
nonce, err := l.IDPConfigAesCrypto.Encrypt([]byte(authReq.AgentID))
nonce, err := l.idpConfigAlg.Encrypt([]byte(authReq.AgentID))
if err != nil {
return "", err
}
@@ -202,7 +202,7 @@ func (l *Login) handleJWTCallback(w http.ResponseWriter, r *http.Request) {
l.renderError(w, r, nil, err)
return
}
userAgentID, err := l.IDPConfigAesCrypto.DecryptString(id, l.IDPConfigAesCrypto.EncryptionKeyID())
userAgentID, err := l.idpConfigAlg.DecryptString(id, l.idpConfigAlg.EncryptionKeyID())
if err != nil {
l.renderError(w, r, nil, err)
return

View File

@@ -35,47 +35,54 @@ type Login struct {
//staticCache cache.Cache //TODO: enable when storage is implemented again
authRepo auth_repository.Repository
baseURL string
zitadelURL string
consolePath string
oidcAuthCallbackURL string
IDPConfigAesCrypto crypto.EncryptionAlgorithm
UserCodeAlg crypto.EncryptionAlgorithm
idpConfigAlg crypto.EncryptionAlgorithm
userCodeAlg crypto.EncryptionAlgorithm
iamDomain string
}
type Config struct {
LanguageCookieName string
CSRF CSRF
CSRFCookieName string
Cache middleware.CacheConfig
//StaticCache cache_config.CacheConfig //TODO: enable when storage is implemented again
}
type CSRF struct {
CookieName string
Key *crypto.KeyConfig
}
const (
login = "LOGIN"
HandlerPrefix = "/ui/login"
DefaultLoggedOutPath = HandlerPrefix + EndpointLogoutDone
)
func CreateLogin(config Config, command *command.Commands, query *query.Queries, authRepo *eventsourcing.EsRepository, staticStorage static.Storage, systemDefaults systemdefaults.SystemDefaults, zitadelURL, domain, oidcAuthCallbackURL string, externalSecure bool, userAgentCookie mux.MiddlewareFunc, userCrypto *crypto.AESCrypto) (*Login, error) {
aesCrypto, err := crypto.NewAESCrypto(systemDefaults.IDPConfigVerificationKey)
if err != nil {
return nil, fmt.Errorf("error create new aes crypto: %w", err)
}
func CreateLogin(config Config,
command *command.Commands,
query *query.Queries,
authRepo *eventsourcing.EsRepository,
staticStorage static.Storage,
systemDefaults systemdefaults.SystemDefaults,
consolePath,
domain,
baseURL,
oidcAuthCallbackURL string,
externalSecure bool,
userAgentCookie mux.MiddlewareFunc,
userCodeAlg crypto.EncryptionAlgorithm,
idpConfigAlg crypto.EncryptionAlgorithm,
csrfCookieKey []byte,
) (*Login, error) {
login := &Login{
oidcAuthCallbackURL: oidcAuthCallbackURL,
baseURL: HandlerPrefix,
zitadelURL: zitadelURL,
baseURL: baseURL + HandlerPrefix,
consolePath: consolePath,
command: command,
query: query,
staticStorage: staticStorage,
authRepo: authRepo,
IDPConfigAesCrypto: aesCrypto,
iamDomain: domain,
UserCodeAlg: userCrypto,
idpConfigAlg: idpConfigAlg,
userCodeAlg: userCodeAlg,
}
//TODO: enable when storage is implemented again
//login.staticCache, err = config.StaticCache.Config.NewCache()
@@ -88,7 +95,7 @@ func CreateLogin(config Config, command *command.Commands, query *query.Queries,
return nil, fmt.Errorf("unable to create filesystem: %w", err)
}
csrfInterceptor, err := createCSRFInterceptor(config.CSRF, externalSecure, login.csrfErrorHandler())
csrfInterceptor, err := createCSRFInterceptor(config.CSRFCookieName, csrfCookieKey, externalSecure, login.csrfErrorHandler())
if err != nil {
return nil, fmt.Errorf("unable to create csrfInterceptor: %w", err)
}
@@ -111,15 +118,11 @@ func csp() *middleware.CSP {
return &csp
}
func createCSRFInterceptor(config CSRF, externalSecure bool, errorHandler http.Handler) (func(http.Handler) http.Handler, error) {
csrfKey, err := crypto.LoadKey(config.Key, config.Key.EncryptionKeyID)
if err != nil {
return nil, err
}
func createCSRFInterceptor(cookieName string, csrfCookieKey []byte, externalSecure bool, errorHandler http.Handler) (func(http.Handler) http.Handler, error) {
path := "/"
return csrf.Protect([]byte(csrfKey),
return csrf.Protect(csrfCookieKey,
csrf.Secure(externalSecure),
csrf.CookieName(http_utils.SetCookiePrefix(config.CookieName, "", path, externalSecure)),
csrf.CookieName(http_utils.SetCookiePrefix(cookieName, "", path, externalSecure)),
csrf.Path(path),
csrf.ErrorHandler(errorHandler),
), nil

View File

@@ -24,7 +24,7 @@ func (l *Login) handleLogin(w http.ResponseWriter, r *http.Request) {
return
}
if authReq == nil {
http.Redirect(w, r, l.zitadelURL, http.StatusFound)
http.Redirect(w, r, l.consolePath, http.StatusFound)
return
}
l.renderNextStep(w, r, authReq)

View File

@@ -51,7 +51,7 @@ func (l *Login) handleMailVerificationCheck(w http.ResponseWriter, r *http.Reque
if authReq != nil {
userOrg = authReq.UserOrgID
}
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.UserCodeAlg)
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg)
if err != nil {
l.checkMailCode(w, r, authReq, data.UserID, data.Code)
return
@@ -66,7 +66,7 @@ func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *d
userID = authReq.UserID
userOrg = authReq.UserOrgID
}
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.UserCodeAlg)
emailCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyEmailCode, l.userCodeAlg)
if err != nil {
l.renderMailVerification(w, r, authReq, userID, err)
return

View File

@@ -27,7 +27,7 @@ func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) {
l.renderPasswordResetDone(w, r, authReq, err)
return
}
passwordCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordResetCode, l.UserCodeAlg)
passwordCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordResetCode, l.userCodeAlg)
if err != nil {
l.renderPasswordResetDone(w, r, authReq, err)
return

View File

@@ -74,12 +74,12 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
memberRoles = nil
resourceOwner = authRequest.RequestedOrgID
}
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.UserCodeAlg)
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg)
if err != nil {
l.renderRegister(w, r, authRequest, data, err)
return
}
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.UserCodeAlg)
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
if err != nil {
l.renderRegister(w, r, authRequest, data, err)
return
@@ -90,7 +90,7 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
return
}
if authRequest == nil {
http.Redirect(w, r, l.zitadelURL, http.StatusFound)
http.Redirect(w, r, l.consolePath, http.StatusFound)
return
}
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())

View File

@@ -65,12 +65,12 @@ func (l *Login) handleRegisterOrgCheck(w http.ResponseWriter, r *http.Request) {
l.renderRegisterOrg(w, r, authRequest, data, err)
return
}
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordlessInitCode, l.UserCodeAlg)
initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypePasswordlessInitCode, l.userCodeAlg)
if err != nil {
l.renderRegisterOrg(w, r, authRequest, data, err)
return
}
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.UserCodeAlg)
phoneCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeVerifyPhoneCode, l.userCodeAlg)
if err != nil {
l.renderRegisterOrg(w, r, authRequest, data, err)
return
@@ -81,7 +81,7 @@ func (l *Login) handleRegisterOrgCheck(w http.ResponseWriter, r *http.Request) {
return
}
if authRequest == nil {
http.Redirect(w, r, l.zitadelURL, http.StatusFound)
http.Redirect(w, r, l.consolePath, http.StatusFound)
return
}
l.renderNextStep(w, r, authRequest)