feat: request registration process by prompt (#1798)

* feat: request registration process by prompt

* fix merge

* add prompt create to docs
This commit is contained in:
Livio Amstutz 2021-06-14 10:40:38 +02:00 committed by GitHub
parent 770994e143
commit ab78b34c6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 31 additions and 13 deletions

View File

@ -39,7 +39,7 @@ Optional parameters
| login_hint | A valid logon name of a user. Will be used for username inputs or preselecting a user on `select_account` | | login_hint | A valid logon name of a user. Will be used for username inputs or preselecting a user on `select_account` |
| max_age | Seconds since the last active successful authentication of the user | | max_age | Seconds since the last active successful authentication of the user |
| nonce | Random string value to associate the client session with the ID Token and for replay attacks mitigation. | | nonce | Random string value to associate the client session with the ID Token and for replay attacks mitigation. |
| prompt | If the Auth Server prompts the user for (re)authentication. <br />no prompt: the user will have to choose a session if more than one session exists<br />`none`: user must be authenticated without interaction, an error is returned otherwise <br />`login`: user must reauthenticate / provide a user name <br />`select_account`: user is prompted to select one of the existing sessions or create a new one | | prompt | If the Auth Server prompts the user for (re)authentication. <br />no prompt: the user will have to choose a session if more than one session exists<br />`none`: user must be authenticated without interaction, an error is returned otherwise <br />`login`: user must reauthenticate / provide a user name <br />`select_account`: user is prompted to select one of the existing sessions or create a new one <br />`create`: the registration form will be displayed to the user directly |
| state | Opaque value used to maintain state between the request and the callback. Used for Cross-Site Request Forgery (CSRF) mitigation as well. | | state | Opaque value used to maintain state between the request and the callback. Used for Cross-Site Request Forgery (CSRF) mitigation as well. |
Successful Code Response Successful Code Response

View File

@ -1794,7 +1794,7 @@ The Following Variables can be used:
> **rpc** ResetCustomPasswordResetMessageTextToDefault([ResetCustomPasswordResetMessageTextToDefaultRequest](#resetcustompasswordresetmessagetexttodefaultrequest)) > **rpc** ResetCustomPasswordResetMessageTextToDefault([ResetCustomPasswordResetMessageTextToDefaultRequest](#resetcustompasswordresetmessagetexttodefaultrequest))
[ResetCustomPasswordResetMessageTextToDefaultResponse](#resetcustompasswordresetmessagetexttodefaultresponse) [ResetCustomPasswordResetMessageTextToDefaultResponse](#resetcustompasswordresetmessagetexttodefaultresponse)
Removes the custom init message text of the organisation Removes the custom password reset message text of the organisation
The default text of the IAM will trigger after The default text of the IAM will trigger after
@ -1838,7 +1838,7 @@ The Following Variables can be used:
> **rpc** ResetCustomVerifyEmailMessageTextToDefault([ResetCustomVerifyEmailMessageTextToDefaultRequest](#resetcustomverifyemailmessagetexttodefaultrequest)) > **rpc** ResetCustomVerifyEmailMessageTextToDefault([ResetCustomVerifyEmailMessageTextToDefaultRequest](#resetcustomverifyemailmessagetexttodefaultrequest))
[ResetCustomVerifyEmailMessageTextToDefaultResponse](#resetcustomverifyemailmessagetexttodefaultresponse) [ResetCustomVerifyEmailMessageTextToDefaultResponse](#resetcustomverifyemailmessagetexttodefaultresponse)
Removes the custom init message text of the organisation Removes the custom verify email message text of the organisation
The default text of the IAM will trigger after The default text of the IAM will trigger after
@ -1882,7 +1882,7 @@ The Following Variables can be used:
> **rpc** ResetCustomVerifyPhoneMessageTextToDefault([ResetCustomVerifyPhoneMessageTextToDefaultRequest](#resetcustomverifyphonemessagetexttodefaultrequest)) > **rpc** ResetCustomVerifyPhoneMessageTextToDefault([ResetCustomVerifyPhoneMessageTextToDefaultRequest](#resetcustomverifyphonemessagetexttodefaultrequest))
[ResetCustomVerifyPhoneMessageTextToDefaultResponse](#resetcustomverifyphonemessagetexttodefaultresponse) [ResetCustomVerifyPhoneMessageTextToDefaultResponse](#resetcustomverifyphonemessagetexttodefaultresponse)
Removes the custom init message text of the organisation Removes the custom verify phone text of the organisation
The default text of the IAM will trigger after The default text of the IAM will trigger after

View File

@ -171,6 +171,8 @@ func PromptToBusiness(prompt oidc.Prompt) domain.Prompt {
return domain.PromptConsent return domain.PromptConsent
case oidc.PromptSelectAccount: case oidc.PromptSelectAccount:
return domain.PromptSelectAccount return domain.PromptSelectAccount
case "create": //this prompt is not final yet, so not implemented in oidc lib
return domain.PromptCreate
default: default:
return domain.PromptUnspecified return domain.PromptUnspecified
} }

View File

@ -532,6 +532,9 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
return steps, nil return steps, nil
} }
steps = append(steps, new(domain.LoginStep)) steps = append(steps, new(domain.LoginStep))
if request.Prompt == domain.PromptCreate {
return append(steps, &domain.RegistrationStep{}), nil
}
if request.Prompt == domain.PromptSelectAccount || request.Prompt == domain.PromptUnspecified { if request.Prompt == domain.PromptSelectAccount || request.Prompt == domain.PromptUnspecified {
users, err := repo.usersForUserSelection(request) users, err := repo.usersForUserSelection(request)
if err != nil { if err != nil {

View File

@ -72,6 +72,7 @@ const (
PromptLogin PromptLogin
PromptConsent PromptConsent
PromptSelectAccount PromptSelectAccount
PromptCreate
) )
type LevelOfAssurance int type LevelOfAssurance int

View File

@ -24,6 +24,7 @@ const (
NextStepExternalLogin NextStepExternalLogin
NextStepGrantRequired NextStepGrantRequired
NextStepPasswordless NextStepPasswordless
NextStepRegistration
) )
type LoginStep struct{} type LoginStep struct{}
@ -32,6 +33,12 @@ func (s *LoginStep) Type() NextStepType {
return NextStepLogin return NextStepLogin
} }
type RegistrationStep struct{}
func (s *RegistrationStep) Type() NextStepType {
return NextStepRegistration
}
type SelectUserStep struct { type SelectUserStep struct {
Users []UserSelection Users []UserSelection
} }

View File

@ -3,10 +3,10 @@ package handler
import ( import (
"net/http" "net/http"
"github.com/caos/zitadel/internal/domain"
"golang.org/x/text/language" "golang.org/x/text/language"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
) )
@ -82,7 +82,12 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, l.zitadelURL, http.StatusFound) http.Redirect(w, r, l.zitadelURL, http.StatusFound)
return return
} }
authRequest.LoginName = user.PreferredLoginName userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.SelectUser(r.Context(), authRequest.ID, user.AggregateID, userAgentID)
if err != nil {
l.renderRegister(w, r, authRequest, data, err)
return
}
l.renderNextStep(w, r, authRequest) l.renderNextStep(w, r, authRequest)
} }

View File

@ -8,18 +8,17 @@ import (
"path" "path"
"strings" "strings"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/static"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/gorilla/csrf" "github.com/gorilla/csrf"
"golang.org/x/text/language" "golang.org/x/text/language"
http_mw "github.com/caos/zitadel/internal/api/http/middleware" http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n" "github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/renderer" "github.com/caos/zitadel/internal/renderer"
"github.com/caos/zitadel/internal/static"
) )
const ( const (
@ -238,6 +237,8 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
return return
} }
l.renderLogin(w, r, authReq, err) l.renderLogin(w, r, authReq, err)
case *domain.RegistrationStep:
l.renderRegisterOption(w, r, authReq, nil)
case *domain.SelectUserStep: case *domain.SelectUserStep:
l.renderUserSelection(w, r, authReq, step) l.renderUserSelection(w, r, authReq, step)
case *domain.InitPasswordStep: case *domain.InitPasswordStep:

View File

@ -22,9 +22,8 @@
formnovalidate>{{t "RegisterOption.RegisterUsernamePassword"}}</button> formnovalidate>{{t "RegisterOption.RegisterUsernamePassword"}}</button>
{{end}} {{end}}
{{if hasExternalLogin}}
<p>{{t "Registration.ExternalLogin"}}</p> <p>{{t "Registration.ExternalLogin"}}</p>
{{if .LoginPolicy.AllowExternalIDP}}
{{ $reqid := .AuthReqID}} {{ $reqid := .AuthReqID}}
{{range $provider := .IDPProviders}} {{range $provider := .IDPProviders}}
<a href="{{ externalIDPRegisterURL $reqid $provider.IDPConfigID}}" <a href="{{ externalIDPRegisterURL $reqid $provider.IDPConfigID}}"