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:
Livio Amstutz
2020-08-27 17:18:23 +02:00
committed by GitHub
parent 3f714679d1
commit 34ec2508d3
73 changed files with 19105 additions and 17845 deletions

View File

@@ -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
}

View File

@@ -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"))
}

View File

@@ -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)

View 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)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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>

View 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" .}}

View 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" .}}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 }}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>