diff --git a/migration/iD10/oracle/202209221920_IDEMPIERE-5408.sql b/migration/iD10/oracle/202209221920_IDEMPIERE-5408.sql
new file mode 100644
index 0000000000..c41dc603f6
--- /dev/null
+++ b/migration/iD10/oracle/202209221920_IDEMPIERE-5408.sql
@@ -0,0 +1,126 @@
+-- IDEMPIERE-5408 Allow or enforce login with specific tenant (FHCA-3823)
+SELECT register_migration_script('202209221920_IDEMPIERE-5408.sql') FROM dual;
+
+SET SQLBLANKLINES ON
+SET DEFINE OFF
+
+-- Sep 22, 2022, 7:20:41 PM CEST
+INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203679,0,0,'Y',TO_TIMESTAMP('2022-09-22 19:20:28','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-22 19:20:28','YYYY-MM-DD HH24:MI:SS'),100,'LoginPrefix','Login Prefix',NULL,NULL,'Login Prefix','D','2b343447-35fc-4aeb-865d-035d3e9dd74f')
+;
+
+-- Sep 22, 2022, 7:21:50 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml,AD_InfoWindow_ID) VALUES (215385,0,'Login Prefix',112,'LoginPrefix',40,'N','N','N','N','N',0,'N',10,0,0,'Y',TO_TIMESTAMP('2022-09-22 19:21:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-22 19:21:49','YYYY-MM-DD HH24:MI:SS'),100,203679,'Y','N','D','N','N','N','Y','813befa6-0922-4583-b673-c965dbc925f8','Y',0,'N','N','N','N',200000)
+;
+
+-- Sep 22, 2022, 7:22:04 PM CEST
+ALTER TABLE AD_Client ADD LoginPrefix VARCHAR2(40 CHAR) DEFAULT NULL
+;
+
+-- Sep 22, 2022, 7:22:50 PM CEST
+INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,IsKey) VALUES (0,0,201131,'3c2eaaa6-51d6-4f44-8652-bd904f70d1a8',TO_TIMESTAMP('2022-09-22 19:22:50','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','ad_client_loginprefix',TO_TIMESTAMP('2022-09-22 19:22:50','YYYY-MM-DD HH24:MI:SS'),100,112,'N','Y','N','N')
+;
+
+-- Sep 22, 2022, 7:23:03 PM CEST
+INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201516,'5f8ecb6c-5116-40ec-bdc8-e1d9d9df5fbb',TO_TIMESTAMP('2022-09-22 19:23:03','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2022-09-22 19:23:03','YYYY-MM-DD HH24:MI:SS'),100,215385,201131,10)
+;
+
+-- Sep 22, 2022, 7:23:14 PM CEST
+CREATE UNIQUE INDEX ad_client_loginprefix ON AD_Client (LoginPrefix)
+;
+
+-- Sep 22, 2022, 7:23:31 PM CEST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (207264,'Login Prefix',145,215385,'Y',40,240,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-09-22 19:23:31','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-22 19:23:31','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','79f147fc-77ac-4a37-bd49-ed05ea6461c4','Y',270,2)
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=20, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=4, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207264
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=30,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=317
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=40,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=318
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=50,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=319
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=60,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10318
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=70,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5160
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=80,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5759
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=90,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=11025
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=100,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=11205
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=110,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=3813
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5887
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=130,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=200594
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=140,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=200595
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=150,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5161
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=160,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5162
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=170,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5163
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5164
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204476
+;
+
+-- Sep 23, 2022, 9:40:32 PM CEST
+INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200207,0,0,TO_TIMESTAMP('2022-09-23 21:40:32','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-09-23 21:40:32','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','LOGIN_PREFIX_SEPARATOR','/','Define the separator between tenant and user when using login prefix','D','S','401baee7-ed2b-4c46-89f9-93ba324411b7')
+;
+
+-- Sep 23, 2022, 9:41:35 PM CEST
+INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200208,0,0,TO_TIMESTAMP('2022-09-23 21:41:35','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-09-23 21:41:35','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','LOGIN_WITH_TENANT_PREFIX','N','Accepted values are (N)o | (A)llow | (F)orce. WARNING: Before setting Force you must fill properly the login prefixes on all tenants.','D','S','9e5af823-d8c6-4019-8f0e-a6d894f3a9cb')
+;
+
+-- Sep 23, 2022, 9:42:25 PM CEST
+INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Tenant not specified at login',0,0,'Y',TO_TIMESTAMP('2022-09-23 21:42:24','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-23 21:42:24','YYYY-MM-DD HH24:MI:SS'),100,200786,'MissingLoginTenant','D','073cb962-7666-4fa3-b471-ca9af693eb3a')
+;
+
+-- Sep 23, 2022, 9:42:38 PM CEST
+INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','User not specified at login',0,0,'Y',TO_TIMESTAMP('2022-09-23 21:42:37','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-23 21:42:37','YYYY-MM-DD HH24:MI:SS'),100,200787,'MissingLoginUser','D','0ec843b3-1082-4fac-8dac-a75d0e2f0673')
+;
+
+-- Sep 23, 2022, 9:42:46 PM CEST
+INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Tenant {0} not found',0,0,'Y',TO_TIMESTAMP('2022-09-23 21:42:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-23 21:42:46','YYYY-MM-DD HH24:MI:SS'),100,200788,'TenantNotFound','D','b806368b-55e7-4d5f-af17-5317c8eefd6c')
+;
+
diff --git a/migration/iD10/postgresql/202209221920_IDEMPIERE-5408.sql b/migration/iD10/postgresql/202209221920_IDEMPIERE-5408.sql
new file mode 100644
index 0000000000..bbd19952f3
--- /dev/null
+++ b/migration/iD10/postgresql/202209221920_IDEMPIERE-5408.sql
@@ -0,0 +1,123 @@
+-- IDEMPIERE-5408 Allow or enforce login with specific tenant (FHCA-3823)
+SELECT register_migration_script('202209221920_IDEMPIERE-5408.sql') FROM dual;
+
+-- Sep 22, 2022, 7:20:41 PM CEST
+INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203679,0,0,'Y',TO_TIMESTAMP('2022-09-22 19:20:28','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-22 19:20:28','YYYY-MM-DD HH24:MI:SS'),100,'LoginPrefix','Login Prefix',NULL,NULL,'Login Prefix','D','2b343447-35fc-4aeb-865d-035d3e9dd74f')
+;
+
+-- Sep 22, 2022, 7:21:50 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml,AD_InfoWindow_ID) VALUES (215385,0,'Login Prefix',112,'LoginPrefix',40,'N','N','N','N','N',0,'N',10,0,0,'Y',TO_TIMESTAMP('2022-09-22 19:21:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-22 19:21:49','YYYY-MM-DD HH24:MI:SS'),100,203679,'Y','N','D','N','N','N','Y','813befa6-0922-4583-b673-c965dbc925f8','Y',0,'N','N','N','N',200000)
+;
+
+-- Sep 22, 2022, 7:22:04 PM CEST
+ALTER TABLE AD_Client ADD COLUMN LoginPrefix VARCHAR(40) DEFAULT NULL
+;
+
+-- Sep 22, 2022, 7:22:50 PM CEST
+INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,IsKey) VALUES (0,0,201131,'3c2eaaa6-51d6-4f44-8652-bd904f70d1a8',TO_TIMESTAMP('2022-09-22 19:22:50','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','ad_client_loginprefix',TO_TIMESTAMP('2022-09-22 19:22:50','YYYY-MM-DD HH24:MI:SS'),100,112,'N','Y','N','N')
+;
+
+-- Sep 22, 2022, 7:23:03 PM CEST
+INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201516,'5f8ecb6c-5116-40ec-bdc8-e1d9d9df5fbb',TO_TIMESTAMP('2022-09-22 19:23:03','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2022-09-22 19:23:03','YYYY-MM-DD HH24:MI:SS'),100,215385,201131,10)
+;
+
+-- Sep 22, 2022, 7:23:14 PM CEST
+CREATE UNIQUE INDEX ad_client_loginprefix ON AD_Client (LoginPrefix)
+;
+
+-- Sep 22, 2022, 7:23:31 PM CEST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (207264,'Login Prefix',145,215385,'Y',40,240,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2022-09-22 19:23:31','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-22 19:23:31','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','79f147fc-77ac-4a37-bd49-ed05ea6461c4','Y',270,2)
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=20, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=4, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207264
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=30,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=317
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=40,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=318
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=50,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=319
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=60,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10318
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=70,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5160
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=80,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5759
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=90,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=11025
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=100,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=11205
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=110,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=3813
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5887
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=130,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=200594
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=140,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=200595
+;
+
+-- Sep 22, 2022, 7:24:07 PM CEST
+UPDATE AD_Field SET SeqNo=150,Updated=TO_TIMESTAMP('2022-09-22 19:24:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5161
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=160,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5162
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=170,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5163
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=180,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=5164
+;
+
+-- Sep 22, 2022, 7:24:08 PM CEST
+UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2022-09-22 19:24:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204476
+;
+
+-- Sep 23, 2022, 9:40:32 PM CEST
+INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200207,0,0,TO_TIMESTAMP('2022-09-23 21:40:32','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-09-23 21:40:32','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','LOGIN_PREFIX_SEPARATOR','/','Define the separator between tenant and user when using login prefix','D','S','401baee7-ed2b-4c46-89f9-93ba324411b7')
+;
+
+-- Sep 23, 2022, 9:41:35 PM CEST
+INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200208,0,0,TO_TIMESTAMP('2022-09-23 21:41:35','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-09-23 21:41:35','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','LOGIN_WITH_TENANT_PREFIX','N','Accepted values are (N)o | (A)llow | (F)orce. WARNING: Before setting Force you must fill properly the login prefixes on all tenants.','D','S','9e5af823-d8c6-4019-8f0e-a6d894f3a9cb')
+;
+
+-- Sep 23, 2022, 9:42:25 PM CEST
+INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Tenant not specified at login',0,0,'Y',TO_TIMESTAMP('2022-09-23 21:42:24','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-23 21:42:24','YYYY-MM-DD HH24:MI:SS'),100,200786,'MissingLoginTenant','D','073cb962-7666-4fa3-b471-ca9af693eb3a')
+;
+
+-- Sep 23, 2022, 9:42:38 PM CEST
+INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','User not specified at login',0,0,'Y',TO_TIMESTAMP('2022-09-23 21:42:37','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-23 21:42:37','YYYY-MM-DD HH24:MI:SS'),100,200787,'MissingLoginUser','D','0ec843b3-1082-4fac-8dac-a75d0e2f0673')
+;
+
+-- Sep 23, 2022, 9:42:46 PM CEST
+INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Tenant {0} not found',0,0,'Y',TO_TIMESTAMP('2022-09-23 21:42:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-09-23 21:42:46','YYYY-MM-DD HH24:MI:SS'),100,200788,'TenantNotFound','D','b806368b-55e7-4d5f-af17-5317c8eefd6c')
+;
+
diff --git a/org.adempiere.base.process/src/org/adempiere/process/InitialClientSetup.java b/org.adempiere.base.process/src/org/adempiere/process/InitialClientSetup.java
index 318aac7502..2288959bcf 100644
--- a/org.adempiere.base.process/src/org/adempiere/process/InitialClientSetup.java
+++ b/org.adempiere.base.process/src/org/adempiere/process/InitialClientSetup.java
@@ -216,13 +216,19 @@ public class InitialClientSetup extends SvrProcess
// Validate Uniqueness of client and users name
// Unique Client Name
- if (DB.executeUpdate("UPDATE AD_Client SET CreatedBy=0 WHERE Name=?", new Object[] {p_ClientName}, false, null) != 0)
+ if (DB.getSQLValueEx(null, "SELECT COUNT(*) FROM AD_Client WHERE Name=?", p_ClientName) != 0)
throw new AdempiereException(Msg.parseTranslation(getCtx(), "@NotUnique@ @ClientName@ = " + p_ClientName));
+ if (DB.getSQLValueEx(null, "SELECT COUNT(*) FROM AD_Client WHERE Value=?", p_ClientName) != 0)
+ throw new AdempiereException(Msg.parseTranslation(getCtx(), "@NotUnique@ @ClientValue@ = " + p_ClientName));
+
+ if (DB.getSQLValueEx(null, "SELECT COUNT(*) FROM AD_Client WHERE LoginPrefix=?", p_ClientName) != 0)
+ throw new AdempiereException(Msg.parseTranslation(getCtx(), "@NotUnique@ @LoginPrefix@ = " + p_ClientName));
+
// Unique User Names
- if (DB.executeUpdate("UPDATE AD_User SET CreatedBy=0 WHERE Name=?", new Object[] {p_AdminUserName}, false, null) != 0)
+ if (DB.getSQLValueEx(null, "SELECT COUNT(*) FROM AD_User WHERE Name=?", p_AdminUserName) != 0)
throw new AdempiereException(Msg.parseTranslation(getCtx(), "@NotUnique@ @AdminUserName@ = " + p_AdminUserName));
- if (DB.executeUpdate("UPDATE AD_User SET CreatedBy=0 WHERE Name=?", new Object[] {p_NormalUserName}, false, null) != 0)
+ if (DB.getSQLValueEx(null, "SELECT COUNT(*) FROM AD_User WHERE Name=?", p_NormalUserName) != 0)
throw new AdempiereException(Msg.parseTranslation(getCtx(), "@NotUnique@ @NormalUserName@ = " + p_NormalUserName));
// City_ID overrides CityName if both used
diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_Client.java b/org.adempiere.base/src/org/compiere/model/I_AD_Client.java
index d33df27637..07346734ff 100644
--- a/org.adempiere.base/src/org/compiere/model/I_AD_Client.java
+++ b/org.adempiere.base/src/org/compiere/model/I_AD_Client.java
@@ -22,7 +22,7 @@ import org.compiere.util.KeyNamePair;
/** Generated Interface for AD_Client
* @author iDempiere (generated)
- * @version Release 9
+ * @version Release 10
*/
public interface I_AD_Client
{
@@ -44,8 +44,8 @@ public interface I_AD_Client
/** Column name AD_Client_ID */
public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID";
- /** Get Client.
- * Client/Tenant for this installation.
+ /** Get Tenant.
+ * Tenant for this installation.
*/
public int getAD_Client_ID();
@@ -75,12 +75,12 @@ public interface I_AD_Client
public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID";
/** Set Organization.
- * Organizational entity within client
+ * Organizational entity within tenant
*/
public void setAD_Org_ID (int AD_Org_ID);
/** Get Organization.
- * Organizational entity within client
+ * Organizational entity within tenant
*/
public int getAD_Org_ID();
@@ -246,10 +246,10 @@ public interface I_AD_Client
/** Column name IsUseASP */
public static final String COLUMNNAME_IsUseASP = "IsUseASP";
- /** Set IsUseASP */
+ /** Set Is Use ASP */
public void setIsUseASP (boolean IsUseASP);
- /** Get IsUseASP */
+ /** Get Is Use ASP */
public boolean isUseASP();
/** Column name IsUseBetaFunctions */
@@ -265,6 +265,15 @@ public interface I_AD_Client
*/
public boolean isUseBetaFunctions();
+ /** Column name LoginPrefix */
+ public static final String COLUMNNAME_LoginPrefix = "LoginPrefix";
+
+ /** Set Login Prefix */
+ public void setLoginPrefix (String LoginPrefix);
+
+ /** Get Login Prefix */
+ public String getLoginPrefix();
+
/** Column name MMPolicy */
public static final String COLUMNNAME_MMPolicy = "MMPolicy";
diff --git a/org.adempiere.base/src/org/compiere/model/MClient.java b/org.adempiere.base/src/org/compiere/model/MClient.java
index 70baee8b09..77257c3fe4 100644
--- a/org.adempiere.base/src/org/compiere/model/MClient.java
+++ b/org.adempiere.base/src/org/compiere/model/MClient.java
@@ -53,11 +53,11 @@ import org.idempiere.cache.ImmutablePOSupport;
*
BF [ 1886480 ] Print Format Item Trl not updated even if not multilingual
*/
public class MClient extends X_AD_Client implements ImmutablePOSupport
-{
+{
/**
*
*/
- private static final long serialVersionUID = 1820358079361924020L;
+ private static final long serialVersionUID = 2479547777642328967L;
/**
* Get client from cache (immutable)
@@ -121,6 +121,30 @@ public class MClient extends X_AD_Client implements ImmutablePOSupport
return retValue;
} // getAll
+ /**
+ * Get a MClient object based on LoginPrefix
+ * @param loginPrefix
+ * @return MClient
+ */
+ public static MClient getByLoginPrefix(String loginPrefix) {
+ MClient client = null;
+ try {
+ PO.setCrossTenantSafe();
+ client = new Query(Env.getCtx(), Table_Name, "LoginPrefix=?", (String)null)
+ .setOnlyActiveRecords(true)
+ .setParameters(loginPrefix)
+ .first();
+ } finally {
+ PO.clearCrossTenantSafe();
+ }
+ if (client != null ) {
+ Integer key = Integer.valueOf(client.getAD_Client_ID());
+ if (! s_cache.containsKey(key))
+ s_cache.put (Integer.valueOf(client.getAD_Client_ID()), client, e -> new MClient(Env.getCtx(), e));
+ }
+ return client;
+ }
+
/**
* Get optionally cached client
* @param ctx context
diff --git a/org.adempiere.base/src/org/compiere/model/MSetup.java b/org.adempiere.base/src/org/compiere/model/MSetup.java
index 22dfaefbc8..0ac731d5a9 100644
--- a/org.adempiere.base/src/org/compiere/model/MSetup.java
+++ b/org.adempiere.base/src/org/compiere/model/MSetup.java
@@ -146,6 +146,8 @@ public final class MSetup
m_clientName = name;
m_client = new MClient(m_ctx, 0, true, m_trx.getTrxName());
m_client.setValue(m_clientName);
+ if (MSystem.isUseLoginPrefix())
+ m_client.setLoginPrefix(m_clientName);
m_client.setName(m_clientName);
if (!m_client.save())
{
diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java
index 73267ad944..4e029b5b65 100644
--- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java
+++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java
@@ -44,7 +44,7 @@ public class MSysConfig extends X_AD_SysConfig
/**
*
*/
- private static final long serialVersionUID = 4367630918820342645L;
+ private static final long serialVersionUID = -5704354666566021353L;
public static final String ADDRESS_VALIDATION = "ADDRESS_VALIDATION";
public static final String ALERT_SEND_ATTACHMENT_AS_XLS = "ALERT_SEND_ATTACHMENT_AS_XLS";
@@ -122,7 +122,9 @@ public class MSysConfig extends X_AD_SysConfig
public static final String LOCATION_MAPS_URL_PREFIX = "LOCATION_MAPS_URL_PREFIX";
public static final String LOCATION_MAX_CITY_ROWS = "LOCATION_MAX_CITY_ROWS";
public static final String LOGIN_HELP_URL = "LOGIN_HELP_URL";
+ public static final String LOGIN_PREFIX_SEPARATOR = "LOGIN_PREFIX_SEPARATOR";
public static final String LOGIN_SHOW_RESETPASSWORD = "LOGIN_SHOW_RESETPASSWORD";
+ public static final String LOGIN_WITH_TENANT_PREFIX = "LOGIN_WITH_TENANT_PREFIX";
public static final String MAIL_DONT_SEND_TO_ADDRESS = "MAIL_DONT_SEND_TO_ADDRESS";
public static final String MAIL_SEND_BCC_TO_ADDRESS = "MAIL_SEND_BCC_TO_ADDRESS";
public static final String MAIL_SEND_BCC_TO_FROM = "MAIL_SEND_BCC_TO_FROM";
diff --git a/org.adempiere.base/src/org/compiere/model/MSystem.java b/org.adempiere.base/src/org/compiere/model/MSystem.java
index f09d535cac..ade566dd9e 100644
--- a/org.adempiere.base/src/org/compiere/model/MSystem.java
+++ b/org.adempiere.base/src/org/compiere/model/MSystem.java
@@ -56,7 +56,7 @@ public class MSystem extends X_AD_System
/**
*
*/
- private static final long serialVersionUID = 3090872841676580202L;
+ private static final long serialVersionUID = -1917493005917422880L;
/**
* Load System Record
@@ -521,4 +521,22 @@ public class MSystem extends X_AD_System
return true;
}
+ /**
+ * The system allows to use login prefix for tenant
+ * @return
+ */
+ public static boolean isUseLoginPrefix() {
+ String loginWithTenantPrefix = MSysConfig.getValue(MSysConfig.LOGIN_WITH_TENANT_PREFIX, "N");
+ return "F".equals(loginWithTenantPrefix) || "A".equals(loginWithTenantPrefix);
+ }
+
+ /**
+ * The system forces to use login prefix for tenant
+ * @return
+ */
+ public static boolean isLoginPrefixMandatory() {
+ String loginWithTenantPrefix = MSysConfig.getValue(MSysConfig.LOGIN_WITH_TENANT_PREFIX, "N");
+ return "F".equals(loginWithTenantPrefix);
+ }
+
} // MSystem
diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_Client.java b/org.adempiere.base/src/org/compiere/model/X_AD_Client.java
index aba218ab3d..5a6a9e7d8a 100644
--- a/org.adempiere.base/src/org/compiere/model/X_AD_Client.java
+++ b/org.adempiere.base/src/org/compiere/model/X_AD_Client.java
@@ -23,7 +23,7 @@ import org.compiere.util.KeyNamePair;
/** Generated Model for AD_Client
* @author iDempiere (generated)
- * @version Release 9 - $Id$ */
+ * @version Release 10 - $Id$ */
@org.adempiere.base.Model(table="AD_Client")
public class X_AD_Client extends PO implements I_AD_Client, I_Persistent
{
@@ -31,7 +31,7 @@ public class X_AD_Client extends PO implements I_AD_Client, I_Persistent
/**
*
*/
- private static final long serialVersionUID = 20220116L;
+ private static final long serialVersionUID = 20220922L;
/** Standard Constructor */
public X_AD_Client (Properties ctx, int AD_Client_ID, String trxName)
@@ -369,16 +369,16 @@ public class X_AD_Client extends PO implements I_AD_Client, I_Persistent
return false;
}
- /** Set IsUseASP.
- @param IsUseASP IsUseASP
+ /** Set Is Use ASP.
+ @param IsUseASP Is Use ASP
*/
public void setIsUseASP (boolean IsUseASP)
{
set_Value (COLUMNNAME_IsUseASP, Boolean.valueOf(IsUseASP));
}
- /** Get IsUseASP.
- @return IsUseASP */
+ /** Get Is Use ASP.
+ @return Is Use ASP */
public boolean isUseASP()
{
Object oo = get_Value(COLUMNNAME_IsUseASP);
@@ -414,6 +414,21 @@ public class X_AD_Client extends PO implements I_AD_Client, I_Persistent
return false;
}
+ /** Set Login Prefix.
+ @param LoginPrefix Login Prefix
+ */
+ public void setLoginPrefix (String LoginPrefix)
+ {
+ set_Value (COLUMNNAME_LoginPrefix, LoginPrefix);
+ }
+
+ /** Get Login Prefix.
+ @return Login Prefix */
+ public String getLoginPrefix()
+ {
+ return (String)get_Value(COLUMNNAME_LoginPrefix);
+ }
+
/** MMPolicy AD_Reference_ID=335 */
public static final int MMPOLICY_AD_Reference_ID=335;
/** FiFo = F */
diff --git a/org.adempiere.base/src/org/compiere/util/Login.java b/org.adempiere.base/src/org/compiere/util/Login.java
index a42fa0619d..ce43e6517e 100644
--- a/org.adempiere.base/src/org/compiere/util/Login.java
+++ b/org.adempiere.base/src/org/compiere/util/Login.java
@@ -36,6 +36,7 @@ import org.compiere.Adempiere;
import org.compiere.db.CConnection;
import org.compiere.model.I_M_Warehouse;
import org.compiere.model.MAcctSchema;
+import org.compiere.model.MClient;
import org.compiere.model.MClientInfo;
import org.compiere.model.MCountry;
import org.compiere.model.MMFARegisteredDevice;
@@ -176,6 +177,7 @@ public class Login
* The error (NoDatabase, UserPwdError, DBLogin) is saved in the log
* @deprecated
*/
+ @Deprecated(since = "2", forRemoval = true)
protected KeyNamePair[] getRoles (CConnection cc,
String app_user, String app_pwd, boolean force)
{
@@ -210,8 +212,9 @@ public class Login
* @param app_user Principal
* @return role array or null if in error.
* The error (NoDatabase, UserPwdError, DBLogin) is saved in the log
- * @deprecated use public KeyNamePair[] getRoles(String app_user, KeyNamePair client)
+ * @deprecated use {@link #getRoles(String, KeyNamePair)}
*/
+ @Deprecated(since = "2", forRemoval = true)
public KeyNamePair[] getRoles (Principal app_user)
{
if (app_user == null)
@@ -230,8 +233,9 @@ public class Login
* @param app_pwd password
* @return role array or null if in error.
* The error (NoDatabase, UserPwdError, DBLogin) is saved in the log
- * @deprecated use public KeyNamePair[] getRoles(String app_user, KeyNamePair client)
+ * @deprecated use use {@link #getRoles(String, KeyNamePair)}
*/
+ @Deprecated(since = "2", forRemoval = true)
public KeyNamePair[] getRoles (String app_user, String app_pwd)
{
return getRoles (app_user, app_pwd, false);
@@ -244,8 +248,9 @@ public class Login
* @param force ignore pwd
* @return role array or null if in error.
* The error (NoDatabase, UserPwdError, DBLogin) is saved in the log
- * @deprecated use public KeyNamePair[] getRoles(String app_user, KeyNamePair client)
+ * @deprecated use {@link #getRoles(String, KeyNamePair)}
*/
+ @Deprecated(since = "2", forRemoval = true)
private KeyNamePair[] getRoles (String app_user, String app_pwd, boolean force)
{
if (log.isLoggable(Level.INFO)) log.info("User=" + app_user);
@@ -1288,6 +1293,28 @@ public class Login
// if not authenticated, use AD_User as backup (just for non-LDAP users)
}
+ MClient client = null;
+ if (MSystem.isUseLoginPrefix()) {
+ String app_tenant = Login.getAppTenant(app_user);
+ app_user = Login.getAppUser(app_user);
+ boolean hasTenant = ! Util.isEmpty(app_tenant, true);
+ if (MSystem.isLoginPrefixMandatory() && ! hasTenant) {
+ loginErrMsg = Msg.getMsg(m_ctx, "MissingLoginTenant");
+ return null;
+ }
+ if (Util.isEmpty(app_user, true)) {
+ loginErrMsg = Msg.getMsg(m_ctx, "MissingLoginUser");
+ return null;
+ }
+ if (hasTenant) {
+ client = MClient.getByLoginPrefix(app_tenant);
+ if (client == null) {
+ loginErrMsg = Msg.getMsg(m_ctx, "TenantNotFound", new Object[] {app_tenant});
+ return null;
+ }
+ }
+ }
+
boolean hash_password = MSysConfig.getBooleanValue(MSysConfig.USER_PASSWORD_HASH, false);
boolean email_login = MSysConfig.getBooleanValue(MSysConfig.USE_EMAIL_FOR_LOGIN, false);
KeyNamePair[] retValue = null;
@@ -1312,7 +1339,8 @@ public class Login
.append(" WHERE c.AD_Client_ID=AD_User.AD_Client_ID")
.append(" AND c.IsActive='Y') AND ")
.append(" AD_User.IsActive='Y'");
-
+ if (client != null)
+ where.append(" AND AD_Client_ID IN (0,").append(client.getAD_Client_ID()).append(")");
List users = null;
try {
PO.setCrossTenantSafe();
@@ -1428,6 +1456,8 @@ public class Login
.append(" WHERE ur.IsActive='Y'")
.append(" AND u.IsActive='Y'")
.append(" AND cli.IsActive='Y'");
+ if (client != null)
+ sql.append(" AND r.AD_Client_ID=").append(client.getAD_Client_ID());
if (! Util.isEmpty(whereRoleType)) {
sql.append(" AND ").append(whereRoleType);
}
@@ -1543,6 +1573,38 @@ public class Login
return retValue;
}
+ /**
+ * Get the tenant from the login text when using login prefix
+ * @param app_user
+ * @return
+ */
+ private static String getAppTenant(String app_user) {
+ String appTenant = null;
+ if (MSystem.isUseLoginPrefix()) {
+ String separator = MSysConfig.getValue(MSysConfig.LOGIN_PREFIX_SEPARATOR, "/");
+ int idxSep = app_user.indexOf(separator);
+ if (idxSep >= 0)
+ appTenant = app_user.substring(0, idxSep);
+ }
+ return appTenant;
+ }
+
+ /**
+ * Get the user from the login text
+ * @param app_user
+ * @return
+ */
+ public static String getAppUser(String app_user) {
+ String appUser = app_user;
+ if (MSystem.isUseLoginPrefix()) {
+ String separator = MSysConfig.getValue(MSysConfig.LOGIN_PREFIX_SEPARATOR, "/");
+ int idxSep = app_user.indexOf(separator);
+ if (idxSep >= 0)
+ appUser = app_user.substring(idxSep + 1);
+ }
+ return appUser;
+ }
+
public KeyNamePair[] getRoles(String app_user, KeyNamePair client) {
return getRoles(app_user, client, null);
}
@@ -1593,7 +1655,7 @@ public class Login
{
pstmt = DB.prepareStatement(sql.toString(), null);
pstmt.setInt(1, client.getKey());
- pstmt.setString(2, app_user);
+ pstmt.setString(2, getAppUser(app_user));
rs = pstmt.executeQuery();
if (!rs.next())
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ChangePasswordPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ChangePasswordPanel.java
index e1d77e4a42..5d46ff37b5 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ChangePasswordPanel.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ChangePasswordPanel.java
@@ -41,6 +41,7 @@ import org.compiere.model.PO;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
+import org.compiere.util.Login;
import org.compiere.util.Msg;
import org.compiere.util.Trx;
import org.compiere.util.Util;
@@ -284,7 +285,7 @@ public class ChangePasswordPanel extends Window implements EventListener
MPasswordRule pwdrule = MPasswordRule.getRules(Env.getCtx(), null);
if (pwdrule != null) {
try {
- pwdrule.validate(m_userName, txtNewPassword.getValue(), new ArrayList());
+ pwdrule.validate(Login.getAppUser(m_userName), txtNewPassword.getValue(), new ArrayList());
}
catch (Exception e) {
throw new WrongValueException(txtNewPassword, e.getMessage());
@@ -346,7 +347,7 @@ public class ChangePasswordPanel extends Window implements EventListener
{
int clientId = clientKNPair.getKey();
Env.setContext(m_ctx, Env.AD_CLIENT_ID, clientId);
- MUser user = MUser.get(m_ctx, m_userName);
+ MUser user = MUser.get(m_ctx, Login.getAppUser(m_userName));
if (user == null)
{
trx.rollback();
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/LoginPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/LoginPanel.java
index dc790c2af3..aad1f6c0c4 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/LoginPanel.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/LoginPanel.java
@@ -102,7 +102,7 @@ public class LoginPanel extends Window implements EventListener
/**
*
*/
- private static final long serialVersionUID = -6130436148212949636L;
+ private static final long serialVersionUID = -7859522563172088496L;
public static final String ROLE_TYPES_WEBUI = "NULL,ZK,SS"; //webui,support+null
@@ -173,15 +173,24 @@ public class LoginPanel extends Window implements EventListener
{
onUserIdChange(AD_User_ID);
if (MSystem.isZKRememberUserAllowed()) {
+ String fillUser = null;
if (email_login) {
- txtUserId.setValue(user.getEMail());
+ fillUser = user.getEMail();
} else {
if (user.getLDAPUser() != null && user.getLDAPUser().length() > 0) {
- txtUserId.setValue(user.getLDAPUser());
+ fillUser = user.getLDAPUser();
} else {
- txtUserId.setValue(user.getName());
+ fillUser = user.getName();
}
}
+ if (MSystem.isUseLoginPrefix()) {
+ MClient client = MClient.get(session.getAD_Client_ID());
+ if (! Util.isEmpty(client.getLoginPrefix())) {
+ String separator = MSysConfig.getValue(MSysConfig.LOGIN_PREFIX_SEPARATOR, "/");
+ fillUser = client.getLoginPrefix() + separator + fillUser;
+ }
+ }
+ txtUserId.setValue(fillUser);
chkRememberMe.setChecked(true);
}
if (MSystem.isZKRememberPasswordAllowed()) {
@@ -606,6 +615,13 @@ public class LoginPanel extends Window implements EventListener
}
else
{
+ if (clientsKNPairs.length == 1) {
+ Env.setContext(Env.getCtx(), Env.AD_CLIENT_ID, (String) clientsKNPairs[0].getID());
+ MUser user = MUser.get(Env.getCtx(), Login.getAppUser(userId));
+ if (user != null)
+ Env.setContext(Env.getCtx(), Env.AD_USER_ID, user.getAD_User_ID() );
+ }
+
String langName = null;
if ( lstLanguage.getSelectedItem() != null )
langName = (String) lstLanguage.getSelectedItem().getLabel();
@@ -667,7 +683,7 @@ public class LoginPanel extends Window implements EventListener
private void btnResetPasswordClicked()
{
- String userId = txtUserId.getValue();
+ String userId = Login.getAppUser(txtUserId.getValue());
if (Util.isEmpty(userId))
throw new IllegalArgumentException(Msg.getMsg(ctx, "FillMandatory") + " " + lblUserId.getValue());
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/RolePanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/RolePanel.java
index cf9464cf90..c674d4dee7 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/RolePanel.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/RolePanel.java
@@ -80,7 +80,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
/**
*
*/
- private static final long serialVersionUID = -618446343598384819L;
+ private static final long serialVersionUID = -1159253307008488232L;
protected LoginWindow wndLogin;
protected Login login;
@@ -98,12 +98,14 @@ public class RolePanel extends Window implements EventListener, Deferrabl
protected UserPreference m_userpreference=null;
- protected boolean m_show = true;
+ protected boolean m_showRolePanel = true;
private RolePanel component;
private boolean isChangeRole = false;
+ private boolean m_isClientDefined;
+
public boolean isChangeRole() {
return isChangeRole;
}
@@ -117,17 +119,18 @@ public class RolePanel extends Window implements EventListener, Deferrabl
private static final String ON_DEFER_LOGOUT = "onDeferLogout";
- public RolePanel(Properties ctx, LoginWindow loginWindow, String userName, boolean show, KeyNamePair[] clientsKNPairs) {
+ public RolePanel(Properties ctx, LoginWindow loginWindow, String userName, boolean show, KeyNamePair[] clientsKNPairs, boolean isClientDefined) {
this.wndLogin = loginWindow;
m_ctx = ctx;
m_userName = userName;
login = new Login(ctx);
- m_show = show;
+ m_showRolePanel = show;
+ m_isClientDefined = isClientDefined;
m_clientKNPairs = clientsKNPairs;
- if( m_clientKNPairs.length == 1 && !m_show ){
+ if( m_clientKNPairs.length == 1 && !m_showRolePanel ){
Env.setContext(m_ctx, Env.AD_CLIENT_ID, (String) m_clientKNPairs[0].getID());
- MUser user = MUser.get (m_ctx, m_userName);
+ MUser user = MUser.get (m_ctx, Login.getAppUser(m_userName));
m_userpreference=new UserPreference();
m_userpreference.loadPreference(user.get_ID());
}
@@ -138,15 +141,15 @@ public class RolePanel extends Window implements EventListener, Deferrabl
this.setId("rolePanel");
this.setSclass("login-box");
- if (! m_show) {
+ if (! m_showRolePanel) {
// check if all mandatory fields are ok to not show
if ( lstRole.getSelectedItem() == null || lstRole.getSelectedItem().getValue() == null
|| lstClient.getSelectedItem() == null || lstClient.getSelectedItem().getValue() == null
|| lstOrganisation.getSelectedItem() == null || lstOrganisation.getSelectedItem().getValue() == null) {
- m_show = true;
+ m_showRolePanel = true;
}
}
- if (m_show) {
+ if (m_showRolePanel) {
AuFocus auf = null;
if (lstClient.getItemCount() > 1) {
auf = new AuFocus(lstClient);
@@ -156,8 +159,6 @@ public class RolePanel extends Window implements EventListener, Deferrabl
auf = new AuFocus(lstOrganisation);
}
Clients.response(auf);
- } else {
- validateRoles();
}
}
@@ -348,7 +349,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
// initial client - Elaine 2009/02/06
UserPreference userPreference = SessionManager.getSessionApplication().getUserPreference();
String initDefault = userPreference.getProperty(UserPreference.P_CLIENT);
- if( initDefault.length() == 0 && !m_show && m_userpreference != null )
+ if( initDefault.length() == 0 && !m_showRolePanel && m_userpreference != null )
{
initDefault=m_userpreference.getProperty( UserPreference.P_CLIENT );
}
@@ -365,7 +366,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
lstClient.setSelectedItem(ci);
}
if (lstClient.getSelectedIndex() == -1 && lstClient.getItemCount() > 0) {
- m_show = true; // didn't find default client
+ m_showRolePanel = true; // didn't find default client
lstClient.setSelectedIndex(0);
}
}
@@ -402,7 +403,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
// initial role
UserPreference userPreference = SessionManager.getSessionApplication().getUserPreference();
String initDefault = userPreference.getProperty(UserPreference.P_ROLE);
- if( initDefault.length() == 0 && !m_show && m_userpreference != null )
+ if( initDefault.length() == 0 && !m_showRolePanel && m_userpreference != null )
{
initDefault=m_userpreference.getProperty( UserPreference.P_ROLE );
}
@@ -422,7 +423,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
lstRole.setSelectedItem(ci);
}
if (lstRole.getSelectedIndex() == -1 && lstRole.getItemCount() > 0) {
- m_show = true; // didn't find default role
+ m_showRolePanel = true; // didn't find default role
lstRole.setSelectedIndex(0);
}
}
@@ -451,7 +452,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
// initial organisation - Elaine 2009/02/06
UserPreference userPreference = SessionManager.getSessionApplication().getUserPreference();
String initDefault = userPreference.getProperty(UserPreference.P_ORG);
- if( initDefault.length() == 0 && !m_show && m_userpreference != null )
+ if( initDefault.length() == 0 && !m_showRolePanel && m_userpreference != null )
{
initDefault=m_userpreference.getProperty( UserPreference.P_ORG );
}
@@ -471,7 +472,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
}
if (lstOrganisation.getSelectedIndex() == -1 && lstOrganisation.getItemCount() > 0) {
- m_show = true; // didn't find default organisation
+ m_showRolePanel = true; // didn't find default organisation
lstOrganisation.setSelectedIndex(0);
}
}
@@ -499,7 +500,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
// initial warehouse - Elaine 2009/02/06
UserPreference userPreference = SessionManager.getSessionApplication().getUserPreference();
String initDefault = userPreference.getProperty(UserPreference.P_WAREHOUSE);
- if( initDefault.length() == 0 && !m_show && m_userpreference != null )
+ if( initDefault.length() == 0 && !m_showRolePanel && m_userpreference != null )
{
initDefault=m_userpreference.getProperty( UserPreference.P_WAREHOUSE );
}
@@ -516,7 +517,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
lstWarehouse.setSelectedItem(ci);
}
if (lstWarehouse.getSelectedIndex() == -1 && lstWarehouse.getItemCount() > 0) {
- m_show = true; // didn't find default warehouse
+ m_showRolePanel = true; // didn't find default warehouse
lstWarehouse.setSelectedIndex(0);
}
}
@@ -542,13 +543,13 @@ public class RolePanel extends Window implements EventListener, Deferrabl
}
if (event.getTarget().getId().equals(ConfirmPanel.A_OK))
{
- validateRoles();
+ validateRoles(false);
}
else if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL))
{
if (isChangeRole()) {
changeRole(ctxBeforeChangeRole);
- validateRoles();
+ validateRoles(false);
} else {
ctxBeforeChangeRole = null;
SessionManager.logoutSession();
@@ -568,7 +569,7 @@ public class RolePanel extends Window implements EventListener, Deferrabl
} else {
Env.setContext(m_ctx, Env.AD_CLIENT_ID, (String) null);
}
- MUser user = MUser.get (m_ctx, m_userName);
+ MUser user = MUser.get (m_ctx, Login.getAppUser(m_userName));
if (user != null) {
Env.setContext(m_ctx, Env.AD_USER_ID, user.getAD_User_ID() );
Env.setContext(m_ctx, Env.AD_USER_NAME, user.getName() );
@@ -598,9 +599,10 @@ public class RolePanel extends Window implements EventListener, Deferrabl
/**
* validate Roles
+ * @param isMFAValidated
*
**/
- public void validateRoles()
+ public void validateRoles(boolean isMFAValidated)
{
Clients.clearBusy();
Comboitem lstItemRole = lstRole.getSelectedItem();
@@ -660,7 +662,10 @@ public class RolePanel extends Window implements EventListener, Deferrabl
MRole.getDefault(m_ctx, true);
//
- wndLogin.validateMFA(orgKNPair);
+ if (m_isClientDefined || isMFAValidated)
+ wndLogin.loginCompleted(login, orgKNPair, this);
+ else
+ wndLogin.validateMFA(orgKNPair, m_isClientDefined, m_userName, m_showRolePanel, m_clientKNPairs);
}
public boolean isDeferrable() {
@@ -668,6 +673,6 @@ public class RolePanel extends Window implements EventListener, Deferrabl
}
public boolean show() {
- return m_show;
+ return m_showRolePanel;
}
}
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ValidateMFAPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ValidateMFAPanel.java
index 47a34992f5..7614299e3d 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ValidateMFAPanel.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ValidateMFAPanel.java
@@ -34,9 +34,7 @@ import java.util.logging.Level;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import org.adempiere.util.Callback;
import org.adempiere.util.LogAuthFailure;
import org.adempiere.webui.AdempiereIdGenerator;
import org.adempiere.webui.LayoutUtils;
@@ -50,7 +48,6 @@ import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ITheme;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.ZKUpdateUtil;
-import org.adempiere.webui.window.Dialog;
import org.adempiere.webui.window.LoginWindow;
import org.compiere.model.MMFAMethod;
import org.compiere.model.MMFARegisteredDevice;
@@ -63,7 +60,6 @@ import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Login;
import org.compiere.util.Msg;
-import org.compiere.util.TimeUtil;
import org.compiere.util.Util;
import org.zkoss.zhtml.Div;
import org.zkoss.zhtml.Table;
@@ -71,11 +67,9 @@ import org.zkoss.zhtml.Td;
import org.zkoss.zhtml.Tr;
import org.zkoss.zk.au.out.AuFocus;
import org.zkoss.zk.ui.Executions;
-import org.zkoss.zk.ui.Session;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
-import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Image;
@@ -84,21 +78,16 @@ public class ValidateMFAPanel extends Window implements EventListener {
/**
*
*/
- private static final long serialVersionUID = -2347409338340527333L;
+ private static final long serialVersionUID = 4777197666886479162L;
private static final CLogger logger = CLogger.getCLogger(ValidateMFAPanel.class);
- private static final String ON_DEFER_LOGOUT = "onDeferLogout";
-
protected LoginWindow wndLogin;
protected Login login;
- private ValidateMFAPanel component;
/** Context */
protected Properties m_ctx;
- protected boolean m_show = true;
-
protected Label lblMFAMechanism;
protected Combobox lstMFAMechanism;
protected Label lblMFAMsg;
@@ -108,6 +97,12 @@ public class ValidateMFAPanel extends Window implements EventListener {
protected Checkbox chkRegisterDevice = null;
private KeyNamePair m_orgKNPair;
+ private KeyNamePair[] m_clientsKNPairs;
+
+ private boolean m_isClientDefined;
+ private String m_userName;
+ private boolean m_showRolePanel = true;
+ private boolean m_showMFAPanel = false;
/* Push the first OK automatically - when the first record is TOTP */
private boolean m_autoCall = false;
@@ -117,15 +112,17 @@ public class ValidateMFAPanel extends Window implements EventListener {
/* Number of failures to calculate an incremental delay on every trial */
private int failures = 0;
- public ValidateMFAPanel(Properties ctx, LoginWindow loginWindow, KeyNamePair orgKNPair) {
+ public ValidateMFAPanel(Properties ctx, LoginWindow loginWindow, KeyNamePair orgKNPair, boolean isClientDefined, String userName, boolean showRolePanel, KeyNamePair[] clientsKNPairs) {
this.wndLogin = loginWindow;
m_ctx = ctx;
this.m_orgKNPair = orgKNPair;
- this.component = this;
+ m_isClientDefined = isClientDefined;
+ m_userName = userName;
+ m_showRolePanel = showRolePanel;
+ m_clientsKNPairs = clientsKNPairs;
String registerCookie = getCookie(getCookieName());
login = new Login(ctx);
- this.addEventListener(ON_DEFER_LOGOUT, this);
if (login.isMFARequired(registerCookie)) {
initComponents(registerCookie != null);
init();
@@ -301,8 +298,6 @@ public class ValidateMFAPanel extends Window implements EventListener {
validateMFAComplete(true);
} else if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL)) {
SessionManager.logoutSession();
- } else if (ON_DEFER_LOGOUT.equals(event.getName())) {
- SessionManager.logoutSession();
}
}
@@ -315,6 +310,7 @@ public class ValidateMFAPanel extends Window implements EventListener {
boolean enablePreferred = (lstMFAMechanism.getChildren().size() > 1 && lstMFAMechanism.getSelectedIndex() > 0);
chkSetPreferred.setVisible(enablePreferred);
MMFARegistration reg = new MMFARegistration(Env.getCtx(), registrationId, null);
+ m_showMFAPanel = true;
if (txtValidationCode.isDisabled()) {
String msg = reg.generateValidationCode(reg);
lblMFAMsg.setValue(msg);
@@ -375,42 +371,16 @@ public class ValidateMFAPanel extends Window implements EventListener {
PO.clearCrossTenantSafe();
}
}
-
- Session currSess = Executions.getCurrent().getDesktop().getSession();
- HttpSession httpSess = (HttpSession) currSess.getNativeSession();
- int timeout = MSysConfig.getIntValue(MSysConfig.ZK_SESSION_TIMEOUT_IN_SECONDS, -2,
- Env.getAD_Client_ID(Env.getCtx()), Env.getAD_Org_ID(Env.getCtx()));
- if (timeout != -2) // default to -2 meaning not set
- httpSess.setMaxInactiveInterval(timeout);
-
- String msg = login.validateLogin(m_orgKNPair);
- if (!Util.isEmpty(msg)) {
- Env.getCtx().clear();
- Dialog.error(0, "Error", msg, new Callback() {
- @Override
- public void onCallback(Integer result) {
- Events.echoEvent(new Event(ON_DEFER_LOGOUT, component));
- }
- });
- return;
- }
- // See if a popup should encourage user to change its password
- if (!MUser.get(Env.getCtx()).isNoPasswordReset()) {
- int notifyDay = MSysConfig.getIntValue(MSysConfig.USER_LOCKING_PASSWORD_NOTIFY_DAY, 0);
- int pwdAgeDay = MSysConfig.getIntValue(MSysConfig.USER_LOCKING_MAX_PASSWORD_AGE_DAY, 0);
- if (notifyDay > 0 && pwdAgeDay > 0) {
- Timestamp limit = TimeUtil.addDays(MUser.get(Env.getCtx()).getDatePasswordChanged(), pwdAgeDay);
- Timestamp notifyAfter = TimeUtil.addDays(limit, -notifyDay);
- Timestamp now = TimeUtil.getDay(null);
-
- if (now.after(notifyAfter))
- Dialog.warn(0, "", Msg.getMsg(m_ctx, "YourPasswordWillExpireInDays",
- new Object[] { TimeUtil.getDaysBetween(now, limit) }));
- }
- }
-
Env.setContext(m_ctx, "#MFA_Registration_ID", registrationId);
- wndLogin.loginCompleted();
+
+ if (m_isClientDefined) {
+ wndLogin.showRolePanel(m_userName, m_showRolePanel, m_clientsKNPairs, m_isClientDefined, true);
+ } else {
+ if (m_orgKNPair == null)
+ wndLogin.showRolePanel(m_userName, m_showRolePanel, m_clientsKNPairs, m_isClientDefined, true);
+ else
+ wndLogin.loginCompleted(login, m_orgKNPair, this);
+ }
}
/**
@@ -451,4 +421,8 @@ public class ValidateMFAPanel extends Window implements EventListener {
return null;
}
+ public boolean show() {
+ return m_showMFAPanel;
+ }
+
}
diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/LoginWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/LoginWindow.java
index 477fc8bb90..3c3adf4516 100644
--- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/LoginWindow.java
+++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/LoginWindow.java
@@ -23,26 +23,36 @@
package org.adempiere.webui.window;
+import java.sql.Timestamp;
import java.util.Locale;
import java.util.Properties;
+import javax.servlet.http.HttpSession;
+
+import org.adempiere.util.Callback;
import org.adempiere.webui.IWebClient;
import org.adempiere.webui.component.FWindow;
+import org.adempiere.webui.component.Window;
import org.adempiere.webui.panel.ChangePasswordPanel;
import org.adempiere.webui.panel.LoginPanel;
import org.adempiere.webui.panel.ResetPasswordPanel;
import org.adempiere.webui.panel.RolePanel;
import org.adempiere.webui.panel.ValidateMFAPanel;
import org.adempiere.webui.session.SessionContextListener;
+import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager;
import org.compiere.model.MSysConfig;
import org.compiere.model.MUser;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Login;
+import org.compiere.util.Msg;
+import org.compiere.util.TimeUtil;
+import org.compiere.util.Util;
import org.zkoss.util.Locales;
import org.zkoss.web.Attributes;
import org.zkoss.zk.ui.Executions;
+import org.zkoss.zk.ui.Session;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
@@ -62,7 +72,7 @@ public class LoginWindow extends FWindow implements EventListener
/**
*
*/
- private static final long serialVersionUID = 2783026164782754864L;
+ private static final long serialVersionUID = 8570332386555237381L;
protected IWebClient app;
protected Properties ctx;
@@ -72,6 +82,8 @@ public class LoginWindow extends FWindow implements EventListener
protected ValidateMFAPanel pnlValidateMFA = null;
protected RolePanel pnlRole;
+ private static final String ON_DEFER_LOGOUT = "onDeferLogout";
+
public LoginWindow() {}
public void init(IWebClient app)
@@ -83,6 +95,7 @@ public class LoginWindow extends FWindow implements EventListener
this.setStyle("background-color: transparent");
// add listener on 'ENTER' key for the login window
addEventListener(Events.ON_OK,this);
+ this.addEventListener(ON_DEFER_LOGOUT, this);
setWidgetListener("onOK", "zAu.cmd0.showBusy(null)");
}
@@ -97,17 +110,31 @@ public class LoginWindow extends FWindow implements EventListener
public void loginOk(String userName, boolean show, KeyNamePair[] clientsKNPairs)
{
- createRolePanel(userName, show, clientsKNPairs);
- this.getChildren().clear();
- if (pnlRole.show())
- this.appendChild(pnlRole);
- else
- this.appendChild(pnlValidateMFA);
+ boolean isClientDefined = (clientsKNPairs.length == 1);
+ if (pnlRole == null)
+ pnlRole = new RolePanel(ctx, this, userName, show, clientsKNPairs, isClientDefined);
+ if (isClientDefined) {
+ createValidateMFAPanel(null, isClientDefined, userName, show, clientsKNPairs);
+ } else {
+ showRolePanel(userName, show, clientsKNPairs, isClientDefined, false);
+ if (! pnlRole.show())
+ createValidateMFAPanel(null, isClientDefined, userName, show, clientsKNPairs);
+ }
}
- protected void createRolePanel(String userName, boolean show,
- KeyNamePair[] clientsKNPairs) {
- pnlRole = new RolePanel(ctx, this, userName, show, clientsKNPairs);
+ public void showRolePanel(String userName, boolean show, KeyNamePair[] clientsKNPairs, boolean isClientDefined, boolean isMFAValidated) {
+ this.getChildren().clear();
+ if (pnlRole.show()) {
+ this.appendChild(pnlRole);
+ } else if (isMFAValidated) {
+ pnlRole.validateRoles(isMFAValidated);
+ } else {
+ if (!isClientDefined)
+ if (pnlValidateMFA == null)
+ createValidateMFAPanel(null, isClientDefined, userName, show, clientsKNPairs);
+ else
+ this.appendChild(pnlValidateMFA);
+ }
}
public void changePassword(String userName, String userPassword, boolean show, KeyNamePair[] clientsKNPairs)
@@ -135,20 +162,55 @@ public class LoginWindow extends FWindow implements EventListener
pnlResetPassword = new ResetPasswordPanel(ctx, this, userName, noSecurityQuestion);
}
- public void validateMFA(KeyNamePair orgKNPair) {
+ public void validateMFA(KeyNamePair orgKNPair, boolean isClientDefined, String userName, boolean show, KeyNamePair[] clientsKNPairs) {
Clients.clearBusy();
- createValidateMFAPanel(orgKNPair);
- this.getChildren().clear();
- this.appendChild(pnlValidateMFA);
+ createValidateMFAPanel(orgKNPair, isClientDefined, userName, show, clientsKNPairs);
}
- private void createValidateMFAPanel(KeyNamePair orgKNPair) {
+ private void createValidateMFAPanel(KeyNamePair orgKNPair, boolean isClientDefined, String userName, boolean show, KeyNamePair[] clientsKNPairs) {
if (pnlValidateMFA == null)
- pnlValidateMFA = new ValidateMFAPanel(ctx, this, orgKNPair);
+ pnlValidateMFA = new ValidateMFAPanel(ctx, this, orgKNPair, isClientDefined, userName, show, clientsKNPairs);
+ if (pnlValidateMFA.show()) {
+ this.getChildren().clear();
+ this.appendChild(pnlValidateMFA);
+ }
}
- public void loginCompleted()
+ public void loginCompleted(Login login, KeyNamePair m_orgKNPair, Window component)
{
+ Session currSess = Executions.getCurrent().getDesktop().getSession();
+ HttpSession httpSess = (HttpSession) currSess.getNativeSession();
+ int timeout = MSysConfig.getIntValue(MSysConfig.ZK_SESSION_TIMEOUT_IN_SECONDS, -2,
+ Env.getAD_Client_ID(Env.getCtx()), Env.getAD_Org_ID(Env.getCtx()));
+ if (timeout != -2) // default to -2 meaning not set
+ httpSess.setMaxInactiveInterval(timeout);
+
+ String msg = login.validateLogin(m_orgKNPair);
+ if (!Util.isEmpty(msg)) {
+ Env.getCtx().clear();
+ Dialog.error(0, "Error", msg, new Callback() {
+ @Override
+ public void onCallback(Integer result) {
+ Events.echoEvent(new Event(ON_DEFER_LOGOUT, component));
+ }
+ });
+ return;
+ }
+ // See if a popup should encourage user to change its password
+ if (!MUser.get(Env.getCtx()).isNoPasswordReset()) {
+ int notifyDay = MSysConfig.getIntValue(MSysConfig.USER_LOCKING_PASSWORD_NOTIFY_DAY, 0);
+ int pwdAgeDay = MSysConfig.getIntValue(MSysConfig.USER_LOCKING_MAX_PASSWORD_AGE_DAY, 0);
+ if (notifyDay > 0 && pwdAgeDay > 0) {
+ Timestamp limit = TimeUtil.addDays(MUser.get(Env.getCtx()).getDatePasswordChanged(), pwdAgeDay);
+ Timestamp notifyAfter = TimeUtil.addDays(limit, -notifyDay);
+ Timestamp now = TimeUtil.getDay(null);
+
+ if (now.after(notifyAfter))
+ Dialog.warn(0, "", Msg.getMsg(Env.getCtx(), "YourPasswordWillExpireInDays",
+ new Object[] { TimeUtil.getDaysBetween(now, limit) }));
+ }
+ }
+
app.loginCompleted();
}
@@ -173,7 +235,7 @@ public class LoginWindow extends FWindow implements EventListener
RolePanel rolePanel = (RolePanel)this.getFellowIfAny("rolePanel");
if (rolePanel != null)
{
- rolePanel.validateRoles();
+ rolePanel.validateRoles(false);
return;
}
@@ -201,6 +263,8 @@ public class LoginWindow extends FWindow implements EventListener
validateMFAPanel.validateMFAComplete(true);
return;
}
+ } else if (ON_DEFER_LOGOUT.equals(event.getName())) {
+ SessionManager.logoutSession();
}
}