mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-15 01:57:41 +00:00
feat: add domain verification notification (#649)
* fix: dont (re)generate client secret with auth type none * fix(cors): allow Origin from request * feat: add origin allow list and fix some core issues * rename migration * fix UserIDsByDomain * feat: send email to users after domain claim * username * check origin on userinfo * update oidc pkg * fix: add migration 1.6 * change username * change username * remove unique email aggregate * change username in mgmt * search global user by login name * fix test * change user search in angular * fix tests * merge * userview in angular * fix merge * Update pkg/grpc/management/proto/management.proto Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update internal/notification/static/i18n/de.yaml Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * fix Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/api/http/middleware"
|
||||
auth_repository "github.com/caos/zitadel/internal/auth/repository"
|
||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/form"
|
||||
@@ -23,7 +24,7 @@ type Login struct {
|
||||
router http.Handler
|
||||
renderer *Renderer
|
||||
parser *form.Parser
|
||||
authRepo *eventsourcing.EsRepository
|
||||
authRepo auth_repository.Repository
|
||||
zitadelURL string
|
||||
oidcAuthCallbackURL string
|
||||
}
|
||||
|
@@ -53,6 +53,8 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
|
||||
tmplRegister: "register.html",
|
||||
tmplLogoutDone: "logout_done.html",
|
||||
tmplRegisterOrg: "register_org.html",
|
||||
tmplChangeUsername: "change_username.html",
|
||||
tmplChangeUsernameDone: "change_username_done.html",
|
||||
}
|
||||
funcs := map[string]interface{}{
|
||||
"resourceUrl": func(file string) string {
|
||||
@@ -112,6 +114,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
|
||||
"orgRegistrationUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointRegisterOrg)
|
||||
},
|
||||
"changeUsernameUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointChangeUsername)
|
||||
},
|
||||
"selectedLanguage": func(l string) bool {
|
||||
return false
|
||||
},
|
||||
@@ -179,6 +184,8 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
|
||||
l.renderMfaPrompt(w, r, authReq, step, err)
|
||||
case *model.InitUserStep:
|
||||
l.renderInitUser(w, r, authReq, "", "", step.PasswordSet, nil)
|
||||
case *model.ChangeUsernameStep:
|
||||
l.renderChangeUsername(w, r, authReq, nil)
|
||||
default:
|
||||
l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-ds3QF", "step no possible"))
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ const (
|
||||
EndpointLogin = "/login"
|
||||
EndpointLoginName = "/loginname"
|
||||
EndpointUserSelection = "/userselection"
|
||||
EndpointChangeUsername = "/username/change"
|
||||
EndpointPassword = "/password"
|
||||
EndpointInitPassword = "/password/init"
|
||||
EndpointChangePassword = "/password/change"
|
||||
@@ -40,6 +41,7 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
|
||||
router.HandleFunc(EndpointLoginName, login.handleLoginName).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointLoginName, login.handleLoginNameCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointChangeUsername, login.handleChangeUsername).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointPassword, login.handlePasswordCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointInitPassword, login.handleInitPasswordCheck).Methods(http.MethodPost)
|
||||
|
46
internal/ui/login/handler/username_change_handler.go
Normal file
46
internal/ui/login/handler/username_change_handler.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
)
|
||||
|
||||
const (
|
||||
tmplChangeUsername = "changeusername"
|
||||
tmplChangeUsernameDone = "changeusernamedone"
|
||||
)
|
||||
|
||||
type changeUsernameData struct {
|
||||
Username string `schema:"username"`
|
||||
}
|
||||
|
||||
func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
|
||||
var errType, errMessage string
|
||||
if err != nil {
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := l.getUserData(r, authReq, "Change Username", errType, errMessage)
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsername], data, nil)
|
||||
}
|
||||
|
||||
func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(changeUsernameData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
err = l.authRepo.ChangeUsername(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Username)
|
||||
if err != nil {
|
||||
l.renderChangeUsername(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
l.renderChangeUsernameDone(w, r, authReq)
|
||||
}
|
||||
|
||||
func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
|
||||
var errType, errMessage string
|
||||
data := l.getUserData(r, authReq, "Username Change Done", errType, errMessage)
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsernameDone], data, nil)
|
||||
}
|
@@ -21,6 +21,15 @@ UserSelection:
|
||||
SessionState0: aktiv
|
||||
SessionState1: inaktiv
|
||||
|
||||
UsernameChange:
|
||||
Title: Usernamen ändern
|
||||
Description: Wähle deinen neuen Benutzernamen
|
||||
Username: Benutzernamen
|
||||
|
||||
UsernameChangeDone:
|
||||
Title: Username geändert
|
||||
Description: Der Username wurde erfolgreich geändert.
|
||||
|
||||
MfaVerify:
|
||||
Title: Multifaktor verifizieren
|
||||
Description: Verifiziere deinen Multifaktor
|
||||
@@ -153,6 +162,7 @@ Errors:
|
||||
NotMatchingUserID: User stimm nicht mit User in Auth Request überein
|
||||
UserIDMissing: UserID ist leer
|
||||
Invalid: Userdaten sind ungültig
|
||||
DomainNotAllowedAsUsername: Domäne ist bereits reserviert und kann nicht verwendet werden
|
||||
Password:
|
||||
ConfirmationWrong: Passwort Bestätigung stimmt nicht überein
|
||||
Empty: Passwort ist leer
|
||||
|
@@ -21,6 +21,15 @@ Password:
|
||||
HasNumber: Number
|
||||
HasSymbol: Symbol
|
||||
|
||||
UsernameChange:
|
||||
Title: Change Username
|
||||
Description: Set your new username
|
||||
Username: Username
|
||||
|
||||
UsernameChangeDone:
|
||||
Title: Username changed
|
||||
Description: Your username was changed successfully.
|
||||
|
||||
MfaVerify:
|
||||
Title: Verify Multificator
|
||||
Description: Verify your multifactor
|
||||
@@ -155,6 +164,7 @@ Errors:
|
||||
NotMatchingUserID: User and user in authrequest don't match
|
||||
UserIDMissing: UserID is empty
|
||||
Invalid: Invalid userdata
|
||||
DomainNotAllowedAsUsername: Domain is already reserved and cannot be used
|
||||
Password:
|
||||
ConfirmationWrong: Passwordconfirmation is wrong
|
||||
Empty: Password is empty
|
||||
|
@@ -2,6 +2,7 @@ function disableSubmit(checks, button) {
|
||||
let form = document.getElementsByTagName('form')[0];
|
||||
let inputs = form.getElementsByTagName('input');
|
||||
for (i = 0; i < inputs.length; i++) {
|
||||
button.disabled = true;
|
||||
inputs[i].addEventListener('input', function () {
|
||||
if (checks != undefined) {
|
||||
if (checks() === false) {
|
||||
|
@@ -41,7 +41,7 @@
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" id="change-password-button" name="resend" value="false" class="primary right" disabled>{{t "Actions.Next"}}</buttontype="submit">
|
||||
<button type="submit" id="change-password-button" name="resend" value="false" class="primary right">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ loginUrl }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
|
||||
</a>
|
||||
|
35
internal/ui/login/static/templates/change_username.html
Normal file
35
internal/ui/login/static/templates/change_username.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
{{ template "user-profile" . }}
|
||||
|
||||
<p>{{t "UsernameChange.Description"}}</p>
|
||||
|
||||
<form action="{{ changeUsernameUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label class="label" for="username">{{t "UsernameChange.Username"}}</label>
|
||||
<input class="input" type="text" id="username" name="username" autocomplete="username" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" id="submit-button" value="false" class="primary right">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ loginUrl }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
|
||||
|
||||
{{template "main-bottom" .}}
|
||||
|
21
internal/ui/login/static/templates/change_username_done.html
Normal file
21
internal/ui/login/static/templates/change_username_done.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
{{ template "user-profile" . }}
|
||||
|
||||
<p>{{t "UsernameChangeDone.Description"}}</p>
|
||||
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" type="submit">{{t "Actions.Next"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
{{template "main-bottom" .}}
|
||||
|
@@ -47,8 +47,7 @@
|
||||
id="init-button"
|
||||
name="resend"
|
||||
value="false"
|
||||
class="primary right"
|
||||
{{ if not .PasswordSet }} disabled {{ end }}>{{t "Actions.Next"}}</button>
|
||||
class="primary right">{{t "Actions.Next"}}</button>
|
||||
<button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend" }}</button>
|
||||
<a href="{{ loginUrl }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" id="submit-button" type="submit" disabled>{{t "Actions.Next"}}</button>
|
||||
<button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
|
||||
<button class="secondary right" name="register" value="true" formnovalidate>{{t "Actions.Register"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" id="submit-button" name="resend" value="false" class="primary right" disabled>{{t "Actions.Next"}}</button>
|
||||
<button type="submit" id="submit-button" name="resend" value="false" class="primary right">{{t "Actions.Next"}}</button>
|
||||
{{ if .UserID }}
|
||||
<button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend"}}</button>
|
||||
{{ end }}
|
||||
|
@@ -34,7 +34,7 @@
|
||||
{{end}}
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" id="submit-button" type="submit" disabled>{{t "Actions.Next"}}</button>
|
||||
<button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ mfaPromptChangeUrl .AuthReqID .MfaType }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
|
||||
</a>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" id="submit-button" type="submit" disabled>{{t "Actions.Next"}}</button>
|
||||
<button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ loginUrl }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
|
||||
</a>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button id="submit-button" class="primary right" type="submit" disabled>{{t "Actions.Next"}}</button>
|
||||
<button id="submit-button" class="primary right" type="submit">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ loginNameChangeUrl .AuthReqID }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
|
||||
</a>
|
||||
|
@@ -61,7 +61,7 @@
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" id="register-button" type="submit" disabled>{{t "Actions.Next"}}</button>
|
||||
<button class="primary right" id="register-button" type="submit">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ loginNameChangeUrl .AuthReqID }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
|
||||
</a>
|
||||
|
@@ -59,7 +59,7 @@
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" id="register-button" type="submit" disabled>{{t "Actions.Save"}}</button>
|
||||
<button class="primary right" id="register-button" type="submit">{{t "Actions.Save"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
Reference in New Issue
Block a user