mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 23:07:22 +00:00
fix: idps (#777)
* fix: update client secret, skip passwordsteps only if login not if linking * fix: global policy for register * fix: scope handling * fix: back after error * fix: change org id scope to primary domain * fix: check if primarydomain empty * fix: local sh * fix: disable buttons on org login policy
This commit is contained in:
parent
3e1204524e
commit
83b0ac1fdb
@ -2,18 +2,19 @@
|
|||||||
[timestamp]="idpResult?.viewTimestamp" [selection]="selection">
|
[timestamp]="idpResult?.viewTimestamp" [selection]="selection">
|
||||||
<ng-template appHasRole [appHasRole]="['iam.write']" actions>
|
<ng-template appHasRole [appHasRole]="['iam.write']" actions>
|
||||||
<button (click)="deactivateSelectedIdps()" matTooltip="{{'IDP.DEACTIVATE' | translate}}" class="icon-button"
|
<button (click)="deactivateSelectedIdps()" matTooltip="{{'IDP.DEACTIVATE' | translate}}" class="icon-button"
|
||||||
mat-icon-button *ngIf="selection.hasValue()" [disabled]="disabled">
|
mat-icon-button *ngIf="selection.hasValue() && serviceType!=PolicyComponentServiceType.MGMT" [disabled]="disabled">
|
||||||
<mat-icon svgIcon="mdi_account_cancel"></mat-icon>
|
<mat-icon svgIcon="mdi_account_cancel"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button (click)="reactivateSelectedIdps()" matTooltip="{{'IDP.ACTIVATE' | translate}}" class="icon-button"
|
<button (click)="reactivateSelectedIdps()" matTooltip="{{'IDP.ACTIVATE' | translate}}" class="icon-button"
|
||||||
mat-icon-button *ngIf="selection.hasValue()" [disabled]="disabled">
|
mat-icon-button *ngIf="selection.hasValue() && serviceType!=PolicyComponentServiceType.MGMT" [disabled]="disabled">
|
||||||
<mat-icon svgIcon="mdi_account_check_outline"></mat-icon>
|
<mat-icon svgIcon="mdi_account_check_outline"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button color="warn" (click)="removeSelectedIdps()" matTooltip="{{'IDP.DELETE' | translate}}"
|
<button color="warn" (click)="removeSelectedIdps()" matTooltip="{{'IDP.DELETE' | translate}}"
|
||||||
class="icon-button" mat-icon-button *ngIf="selection.hasValue()" [disabled]="disabled">
|
class="icon-button" mat-icon-button *ngIf="selection.hasValue() && serviceType!=PolicyComponentServiceType.MGMT" [disabled]="disabled">
|
||||||
<i class="las la-trash"></i>
|
<i class="las la-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
<a class="add-button" [routerLink]="createRouterLink" color="primary" mat-raised-button [disabled]="disabled">
|
<a class="add-button" [routerLink]="createRouterLink" color="primary" mat-raised-button [disabled]="disabled"
|
||||||
|
*ngIf="serviceType!=PolicyComponentServiceType.MGMT">
|
||||||
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
|
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
|
||||||
</a>
|
</a>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -82,4 +83,4 @@
|
|||||||
<mat-paginator #paginator class="paginator" [length]="idpResult?.totalResult || 0" [pageSize]="10"
|
<mat-paginator #paginator class="paginator" [length]="idpResult?.totalResult || 0" [pageSize]="10"
|
||||||
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
[pageSizeOptions]="[5, 10, 20]" (page)="changePage($event)"></mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
</app-refresh-table>
|
</app-refresh-table>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<app-detail-layout [backRouterLink]="backroutes" [title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
|
<app-detail-layout [backRouterLink]="backroutes" [title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
|
||||||
[description]="'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATE' | translate">
|
[description]="'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATE' | translate">
|
||||||
<ng-container *ngIf="(['policy.delete'] | hasRole | async) && serviceType == PolicyComponentServiceType.MGMT">
|
<ng-container *ngIf="(['policy.delete'] | hasRole | async) && serviceType == PolicyComponentServiceType.MGMT">
|
||||||
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
<!--<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
||||||
mat-stroked-button>
|
mat-stroked-button>
|
||||||
{{'ORG.POLICY.DELETE' | translate}}
|
{{'ORG.POLICY.DELETE' | translate}}
|
||||||
</button>
|
</button>-->
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<div class="content" *ngIf="loginData">
|
<div class="content" *ngIf="loginData">
|
||||||
@ -12,19 +12,20 @@
|
|||||||
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWUSERNAMEPASSWORD' | translate}}</span>
|
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWUSERNAMEPASSWORD' | translate}}</span>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
||||||
[(ngModel)]="loginData.allowUsernamePassword">
|
[(ngModel)]="loginData.allowUsernamePassword" [disabled]="serviceType==PolicyComponentServiceType.MGMT">
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWREGISTER' | translate}}</span>
|
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWREGISTER' | translate}}</span>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="loginData.allowRegister">
|
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="loginData.allowRegister"
|
||||||
|
[disabled]="serviceType==PolicyComponentServiceType.MGMT">
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWEXTERNALIDP' | translate}}</span>
|
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWEXTERNALIDP' | translate}}</span>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
|
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [disabled]="serviceType==PolicyComponentServiceType.MGMT"
|
||||||
[(ngModel)]="loginData.allowExternalIdp">
|
[(ngModel)]="loginData.allowExternalIdp">
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
</div>
|
</div>
|
||||||
@ -34,18 +35,18 @@
|
|||||||
|
|
||||||
<div class="idps">
|
<div class="idps">
|
||||||
<div class="idp" *ngFor="let idp of idps">
|
<div class="idp" *ngFor="let idp of idps">
|
||||||
<mat-icon (click)="removeIdp(idp)" class="rm">remove_circle</mat-icon>
|
<mat-icon *ngIf="serviceType!=PolicyComponentServiceType.MGMT" (click)="removeIdp(idp)" class="rm">remove_circle</mat-icon>
|
||||||
<span>{{idp.name}}</span>
|
<span>{{idp.name}}</span>
|
||||||
<span class="meta">{{ 'IDP.TYPE' | translate }}: {{ 'IDP.TYPES.'+idp.type | translate }}</span>
|
<span class="meta">{{ 'IDP.TYPE' | translate }}: {{ 'IDP.TYPES.'+idp.type | translate }}</span>
|
||||||
<span class="meta">{{ 'IDP.ID' | translate }}: {{idp.idpConfigId}}</span>
|
<span class="meta">{{ 'IDP.ID' | translate }}: {{idp.idpConfigId}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="new-idp" (click)="openDialog()">
|
<div *ngIf="serviceType!=PolicyComponentServiceType.MGMT" class="new-idp" (click)="openDialog()">
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>add</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-container">
|
<div class="btn-container">
|
||||||
<button (click)="savePolicy()" color="primary" type="submit"
|
<button (click)="savePolicy()" color="primary" type="submit" [disabled]="serviceType==PolicyComponentServiceType.MGMT"
|
||||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -23,4 +23,6 @@ type AuthRequestRepository interface {
|
|||||||
VerifyMfaOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error
|
VerifyMfaOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error
|
||||||
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string) error
|
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string) error
|
||||||
AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string) error
|
AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string) error
|
||||||
|
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
|
||||||
|
GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error)
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ type userEventProvider interface {
|
|||||||
|
|
||||||
type orgViewProvider interface {
|
type orgViewProvider interface {
|
||||||
OrgByID(string) (*org_view_model.OrgView, error)
|
OrgByID(string) (*org_view_model.OrgView, error)
|
||||||
|
OrgByPrimaryDomain(string) (*org_view_model.OrgView, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) Health(ctx context.Context) error {
|
func (repo *AuthRequestRepo) Health(ctx context.Context) error {
|
||||||
@ -231,6 +232,16 @@ func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, u
|
|||||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *AuthRequestRepo) ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error {
|
||||||
|
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
request.LinkingUsers = nil
|
||||||
|
request.SelectedIDPConfigID = ""
|
||||||
|
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *user_model.User, externalIDP *user_model.ExternalIDP, orgMember *org_model.OrgMember, authReqID, userAgentID, resourceOwner string) error {
|
func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *user_model.User, externalIDP *user_model.ExternalIDP, orgMember *org_model.OrgMember, authReqID, userAgentID, resourceOwner string) error {
|
||||||
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -317,7 +328,14 @@ func (repo *AuthRequestRepo) getLoginPolicyAndIDPProviders(ctx context.Context,
|
|||||||
func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model.AuthRequest) error {
|
func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model.AuthRequest) error {
|
||||||
orgID := request.UserOrgID
|
orgID := request.UserOrgID
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
orgID = request.GetScopeOrgID()
|
primaryDomain := request.GetScopeOrgPrimaryDomain()
|
||||||
|
if primaryDomain != "" {
|
||||||
|
org, err := repo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
orgID = org.ID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
orgID = repo.IAMID
|
orgID = repo.IAMID
|
||||||
@ -335,7 +353,16 @@ func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.AuthRequest, loginName string) (err error) {
|
func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.AuthRequest, loginName string) (err error) {
|
||||||
orgID := request.GetScopeOrgID()
|
primaryDomain := request.GetScopeOrgPrimaryDomain()
|
||||||
|
orgID := ""
|
||||||
|
if primaryDomain != "" {
|
||||||
|
org, err := repo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
orgID = org.ID
|
||||||
|
}
|
||||||
|
|
||||||
user := new(user_view_model.UserView)
|
user := new(user_view_model.UserView)
|
||||||
if orgID != "" {
|
if orgID != "" {
|
||||||
user, err = repo.View.UserByLoginNameAndResourceOwner(loginName, orgID)
|
user, err = repo.View.UserByLoginNameAndResourceOwner(loginName, orgID)
|
||||||
@ -356,6 +383,14 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo AuthRequestRepo) GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error) {
|
||||||
|
org, err := repo.OrgViewProvider.OrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return org_view_model.OrgToModel(org), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (repo AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *model.AuthRequest, user *user_view_model.UserView) error {
|
func (repo AuthRequestRepo) checkLoginPolicyWithResourceOwner(ctx context.Context, request *model.AuthRequest, user *user_view_model.UserView) error {
|
||||||
loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, user.ResourceOwner)
|
loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, user.ResourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -386,10 +421,15 @@ func (repo *AuthRequestRepo) checkSelectedExternalIDP(request *model.AuthRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) checkExternalUserLogin(request *model.AuthRequest, idpConfigID, externalUserID string) (err error) {
|
func (repo *AuthRequestRepo) checkExternalUserLogin(request *model.AuthRequest, idpConfigID, externalUserID string) (err error) {
|
||||||
orgID := request.GetScopeOrgID()
|
primaryDomain := request.GetScopeOrgPrimaryDomain()
|
||||||
externalIDP := new(user_view_model.ExternalIDPView)
|
externalIDP := new(user_view_model.ExternalIDPView)
|
||||||
if orgID != "" {
|
org := new(org_model.OrgView)
|
||||||
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, orgID)
|
if primaryDomain != "" {
|
||||||
|
org, err = repo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, org.ID)
|
||||||
} else {
|
} else {
|
||||||
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID)
|
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID)
|
||||||
}
|
}
|
||||||
@ -435,7 +475,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.SelectedIDPConfigID == "" {
|
if request.SelectedIDPConfigID == "" || (request.SelectedIDPConfigID != "" && request.LinkingUsers != nil && len(request.LinkingUsers) > 0) {
|
||||||
if user.InitRequired {
|
if user.InitRequired {
|
||||||
return append(steps, &model.InitUserStep{PasswordSet: user.PasswordSet}), nil
|
return append(steps, &model.InitUserStep{PasswordSet: user.PasswordSet}), nil
|
||||||
}
|
}
|
||||||
|
@ -139,12 +139,22 @@ func (m *mockViewOrg) OrgByID(string) (*org_view_model.OrgView, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockViewOrg) OrgByPrimaryDomain(string) (*org_view_model.OrgView, error) {
|
||||||
|
return &org_view_model.OrgView{
|
||||||
|
State: int32(m.State),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type mockViewErrOrg struct{}
|
type mockViewErrOrg struct{}
|
||||||
|
|
||||||
func (m *mockViewErrOrg) OrgByID(string) (*org_view_model.OrgView, error) {
|
func (m *mockViewErrOrg) OrgByID(string) (*org_view_model.OrgView, error) {
|
||||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockViewErrOrg) OrgByPrimaryDomain(string) (*org_view_model.OrgView, error) {
|
||||||
|
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
UserEvents *user_event.UserEventstore
|
UserEvents *user_event.UserEventstore
|
||||||
@ -582,7 +592,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"linking users, link users step",
|
"linking users, password step",
|
||||||
fields{
|
fields{
|
||||||
userSessionViewProvider: &mockViewUserSession{
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
|
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
@ -596,6 +606,32 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
|||||||
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
},
|
},
|
||||||
|
args{
|
||||||
|
&model.AuthRequest{
|
||||||
|
UserID: "UserID",
|
||||||
|
SelectedIDPConfigID: "IDPConfigID",
|
||||||
|
LinkingUsers: []*model.ExternalUser{{IDPConfigID: "IDPConfigID", ExternalUserID: "UserID", DisplayName: "DisplayName"}},
|
||||||
|
}, false},
|
||||||
|
[]model.NextStep{&model.PasswordStep{}},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"linking users, linking step",
|
||||||
|
fields{
|
||||||
|
userSessionViewProvider: &mockViewUserSession{
|
||||||
|
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
|
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
|
||||||
|
},
|
||||||
|
userViewProvider: &mockViewUser{
|
||||||
|
PasswordSet: true,
|
||||||
|
IsEmailVerified: true,
|
||||||
|
MfaMaxSetUp: int32(model.MfaLevelSoftware),
|
||||||
|
},
|
||||||
|
userEventProvider: &mockEventUser{},
|
||||||
|
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
|
||||||
|
MfaSoftwareCheckLifeTime: 18 * time.Hour,
|
||||||
|
PasswordCheckLifeTime: 10 * 24 * time.Hour,
|
||||||
|
},
|
||||||
args{
|
args{
|
||||||
&model.AuthRequest{
|
&model.AuthRequest{
|
||||||
UserID: "UserID",
|
UserID: "UserID",
|
||||||
|
@ -46,6 +46,17 @@ func (o *Org) Reduce(event *es_models.Event) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = org.AppendEvent(event)
|
err = org.AppendEvent(event)
|
||||||
|
case model.OrgDomainPrimarySet:
|
||||||
|
domain := new(org_model.OrgDomainView)
|
||||||
|
err = domain.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
org, err = o.view.OrgByID(event.AggregateID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
org.Domain = domain.Domain
|
||||||
default:
|
default:
|
||||||
return o.view.ProcessedOrgSequence(event.Sequence)
|
return o.view.ProcessedOrgSequence(event.Sequence)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,10 @@ func (v *View) OrgByID(orgID string) (*org_model.OrgView, error) {
|
|||||||
return org_view.OrgByID(v.Db, orgTable, orgID)
|
return org_view.OrgByID(v.Db, orgTable, orgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) OrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error) {
|
||||||
|
return org_view.OrgByPrimaryDomain(v.Db, orgTable, primaryDomain)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, uint64, error) {
|
func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, uint64, error) {
|
||||||
return org_view.SearchOrgs(v.Db, orgTable, req)
|
return org_view.SearchOrgs(v.Db, orgTable, req)
|
||||||
}
|
}
|
||||||
|
@ -126,12 +126,12 @@ func (a *AuthRequest) SetUserInfo(userID, loginName, displayName, userOrgID stri
|
|||||||
a.UserOrgID = userOrgID
|
a.UserOrgID = userOrgID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AuthRequest) GetScopeOrgID() string {
|
func (a *AuthRequest) GetScopeOrgPrimaryDomain() string {
|
||||||
switch request := a.Request.(type) {
|
switch request := a.Request.(type) {
|
||||||
case *AuthRequestOIDC:
|
case *AuthRequestOIDC:
|
||||||
for _, scope := range request.Scopes {
|
for _, scope := range request.Scopes {
|
||||||
if strings.HasPrefix(scope, OrgIDScope) {
|
if strings.HasPrefix(scope, OrgDomainPrimaryScope) {
|
||||||
strings.TrimPrefix(scope, OrgIDScope)
|
return strings.TrimPrefix(scope, OrgDomainPrimaryScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OrgIDScope = "urn:zitadel:organisation:id:"
|
OrgDomainPrimaryScope = "urn:zitadel:org:domain:primary:"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthRequestOIDC struct {
|
type AuthRequestOIDC struct {
|
||||||
|
@ -27,7 +27,7 @@ func (c *OIDCIDPConfig) Changes(changed *OIDCIDPConfig) map[string]interface{} {
|
|||||||
if c.ClientID != changed.ClientID {
|
if c.ClientID != changed.ClientID {
|
||||||
changes["clientId"] = changed.ClientID
|
changes["clientId"] = changed.ClientID
|
||||||
}
|
}
|
||||||
if c.ClientSecret != nil && c.ClientSecret != changed.ClientSecret {
|
if changed.ClientSecret != nil && c.ClientSecret != changed.ClientSecret {
|
||||||
changes["clientSecret"] = changed.ClientSecret
|
changes["clientSecret"] = changed.ClientSecret
|
||||||
}
|
}
|
||||||
if c.Issuer != changed.Issuer {
|
if c.Issuer != changed.Issuer {
|
||||||
|
@ -18,6 +18,16 @@ func OrgByID(db *gorm.DB, table, orgID string) (*model.OrgView, error) {
|
|||||||
return org, err
|
return org, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func OrgByPrimaryDomain(db *gorm.DB, table, primaryDomain string) (*model.OrgView, error) {
|
||||||
|
org := new(model.OrgView)
|
||||||
|
query := repository.PrepareGetByKey(table, model.OrgSearchKey(org_model.OrgSearchKeyOrgDomain), primaryDomain)
|
||||||
|
err := query(db, org)
|
||||||
|
if caos_errs.IsNotFound(err) {
|
||||||
|
return nil, caos_errs.ThrowNotFound(nil, "VIEW-GEwea", "Errors.Org.NotFound")
|
||||||
|
}
|
||||||
|
return org, err
|
||||||
|
}
|
||||||
|
|
||||||
func SearchOrgs(db *gorm.DB, table string, req *org_model.OrgSearchRequest) ([]*model.OrgView, uint64, error) {
|
func SearchOrgs(db *gorm.DB, table string, req *org_model.OrgSearchRequest) ([]*model.OrgView, uint64, error) {
|
||||||
orgs := make([]*model.OrgView, 0)
|
orgs := make([]*model.OrgView, 0)
|
||||||
query := repository.PrepareSearchQuery(table, model.OrgSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
query := repository.PrepareSearchQuery(table, model.OrgSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||||
|
@ -33,6 +33,7 @@ type externalIDPCallbackData struct {
|
|||||||
type externalNotFoundOptionFormData struct {
|
type externalNotFoundOptionFormData struct {
|
||||||
Link bool `schema:"link"`
|
Link bool `schema:"link"`
|
||||||
AutoRegister bool `schema:"autoregister"`
|
AutoRegister bool `schema:"autoregister"`
|
||||||
|
ResetLinking bool `schema:"resetlinking"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type externalNotFoundOptionData struct {
|
type externalNotFoundOptionData struct {
|
||||||
@ -139,35 +140,52 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http
|
|||||||
data := new(externalNotFoundOptionFormData)
|
data := new(externalNotFoundOptionFormData)
|
||||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.renderError(w, r, authReq, err)
|
l.renderExternalNotFoundOption(w, r, authReq, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if data.Link {
|
if data.Link {
|
||||||
l.renderLogin(w, r, authReq, nil)
|
l.renderLogin(w, r, authReq, nil)
|
||||||
return
|
return
|
||||||
|
} else if data.ResetLinking {
|
||||||
|
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||||
|
err = l.authRepo.ResetLinkingUsers(r.Context(), authReq.ID, userAgentID)
|
||||||
|
if err != nil {
|
||||||
|
l.renderExternalNotFoundOption(w, r, authReq, err)
|
||||||
|
}
|
||||||
|
l.handleLogin(w, r)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
l.handleAutoRegister(w, r, authReq)
|
l.handleAutoRegister(w, r, authReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
|
func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
|
||||||
orgIamPolicy, err := l.getOrgIamPolicy(r, authReq.GetScopeOrgID())
|
|
||||||
if err != nil {
|
|
||||||
l.renderExternalNotFoundOption(w, r, authReq, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
iam, err := l.authRepo.GetIAM(r.Context())
|
iam, err := l.authRepo.GetIAM(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.renderExternalNotFoundOption(w, r, authReq, err)
|
l.renderExternalNotFoundOption(w, r, authReq, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceOwner := iam.GlobalOrgID
|
resourceOwner := iam.GlobalOrgID
|
||||||
member := &org_model.OrgMember{
|
member := &org_model.OrgMember{
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
|
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
|
||||||
Roles: []string{orgProjectCreatorRole},
|
Roles: []string{orgProjectCreatorRole},
|
||||||
}
|
}
|
||||||
if authReq.GetScopeOrgID() != iam.GlobalOrgID && authReq.GetScopeOrgID() != "" {
|
if authReq.GetScopeOrgPrimaryDomain() != "" {
|
||||||
member = nil
|
primaryDomain := authReq.GetScopeOrgPrimaryDomain()
|
||||||
resourceOwner = authReq.GetScopeOrgID()
|
org, err := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
l.renderExternalNotFoundOption(w, r, authReq, err)
|
||||||
|
}
|
||||||
|
if org.ID != iam.GlobalOrgID {
|
||||||
|
member = nil
|
||||||
|
resourceOwner = org.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner)
|
||||||
|
if err != nil {
|
||||||
|
l.renderExternalNotFoundOption(w, r, authReq, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
idpConfig, err := l.authRepo.GetIDPConfigByID(r.Context(), authReq.SelectedIDPConfigID)
|
idpConfig, err := l.authRepo.GetIDPConfigByID(r.Context(), authReq.SelectedIDPConfigID)
|
||||||
@ -216,7 +234,6 @@ func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.ID
|
|||||||
}
|
}
|
||||||
return externalUser
|
return externalUser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *org_model.OrgIAMPolicy, linkingUser *model.ExternalUser, idpConfig *iam_model.IDPConfigView) (*usr_model.User, *usr_model.ExternalIDP) {
|
func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *org_model.OrgIAMPolicy, linkingUser *model.ExternalUser, idpConfig *iam_model.IDPConfigView) (*usr_model.User, *usr_model.ExternalIDP) {
|
||||||
username := linkingUser.PreferredUsername
|
username := linkingUser.PreferredUsername
|
||||||
switch idpConfig.OIDCUsernameMapping {
|
switch idpConfig.OIDCUsernameMapping {
|
||||||
|
@ -71,11 +71,6 @@ func (l *Login) handleExternalRegisterCallback(w http.ResponseWriter, r *http.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) {
|
func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) {
|
||||||
orgIamPolicy, err := l.getOrgIamPolicy(r, authReq.GetScopeOrgID())
|
|
||||||
if err != nil {
|
|
||||||
l.renderRegisterOption(w, r, authReq, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
iam, err := l.authRepo.GetIAM(r.Context())
|
iam, err := l.authRepo.GetIAM(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.renderRegisterOption(w, r, authReq, err)
|
l.renderRegisterOption(w, r, authReq, err)
|
||||||
@ -86,11 +81,24 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
|
|||||||
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
|
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
|
||||||
Roles: []string{orgProjectCreatorRole},
|
Roles: []string{orgProjectCreatorRole},
|
||||||
}
|
}
|
||||||
if authReq.GetScopeOrgID() != iam.GlobalOrgID && authReq.GetScopeOrgID() != "" {
|
|
||||||
member = nil
|
|
||||||
resourceOwner = authReq.GetScopeOrgID()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if authReq.GetScopeOrgPrimaryDomain() != "" {
|
||||||
|
primaryDomain := authReq.GetScopeOrgPrimaryDomain()
|
||||||
|
org, err := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
l.renderRegisterOption(w, r, authReq, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if org.ID != iam.GlobalOrgID {
|
||||||
|
member = nil
|
||||||
|
resourceOwner = org.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner)
|
||||||
|
if err != nil {
|
||||||
|
l.renderRegisterOption(w, r, authReq, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
user, externalIDP := l.mapTokenToLoginUserAndExternalIDP(orgIamPolicy, tokens, idpConfig)
|
user, externalIDP := l.mapTokenToLoginUserAndExternalIDP(orgIamPolicy, tokens, idpConfig)
|
||||||
_, err = l.authRepo.RegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, member, resourceOwner)
|
_, err = l.authRepo.RegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, member, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -71,9 +71,17 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
|
|||||||
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
|
ObjectRoot: models.ObjectRoot{AggregateID: iam.GlobalOrgID},
|
||||||
Roles: []string{orgProjectCreatorRole},
|
Roles: []string{orgProjectCreatorRole},
|
||||||
}
|
}
|
||||||
if authRequest.GetScopeOrgID() != "" && authRequest.GetScopeOrgID() != iam.GlobalOrgID {
|
if authRequest.GetScopeOrgPrimaryDomain() != "" {
|
||||||
member = nil
|
primaryDomain := authRequest.GetScopeOrgPrimaryDomain()
|
||||||
resourceOwner = authRequest.GetScopeOrgID()
|
org, err := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if err != nil {
|
||||||
|
l.renderRegisterOption(w, r, authRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if org.ID != iam.GlobalOrgID {
|
||||||
|
member = nil
|
||||||
|
resourceOwner = org.ID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
user, err := l.authRepo.Register(setContext(r.Context(), resourceOwner), data.toUserModel(), member, resourceOwner)
|
user, err := l.authRepo.Register(setContext(r.Context(), resourceOwner), data.toUserModel(), member, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -292,7 +292,14 @@ func (l *Login) getOrgID(authReq *model.AuthRequest) string {
|
|||||||
if authReq.Request == nil {
|
if authReq.Request == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return authReq.GetScopeOrgID()
|
primaryDomain := authReq.GetScopeOrgPrimaryDomain()
|
||||||
|
if primaryDomain != "" {
|
||||||
|
org, _ := l.authRepo.GetOrgByPrimaryDomain(primaryDomain)
|
||||||
|
if org != nil {
|
||||||
|
return org.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRequestID(authReq *model.AuthRequest, r *http.Request) string {
|
func getRequestID(authReq *model.AuthRequest, r *http.Request) string {
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
{{ define "error-message" }}
|
{{ define "error-message" }}
|
||||||
{{if .ErrMessage }}
|
{{if .ErrMessage }}
|
||||||
<div class="field">
|
<div class="error">
|
||||||
<div class="error">
|
{{ if .ErrType }}{{ .ErrType }} - {{end}}{{ .ErrMessage }}
|
||||||
{{ if .ErrType }}{{ .ErrType }} - {{end}}{{ .ErrMessage }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ end }}
|
{{ end }}
|
@ -15,9 +15,7 @@
|
|||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="secondary right" name="link" value="true" formnovalidate>{{t "ExternalNotFoundOption.Link"}}</button>
|
<button class="secondary right" name="link" value="true" formnovalidate>{{t "ExternalNotFoundOption.Link"}}</button>
|
||||||
<button class="secondary right" name="autoregister" value="true" formnovalidate>{{t "ExternalNotFoundOption.AutoRegister"}}</button>
|
<button class="secondary right" name="autoregister" value="true" formnovalidate>{{t "ExternalNotFoundOption.AutoRegister"}}</button>
|
||||||
<a class="button secondary" href="{{ loginUrl .AuthReqID }}">
|
<button class="secondary right" name="resetlinking" value="true" formnovalidate>{{t "Actions.Back"}}</button>
|
||||||
{{t "Actions.Back"}}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{template "error-message" .}}
|
{{template "error-message" .}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user