├── README.md ├── authentication_type_plugin_apex_ldap_group_authentication.sql ├── authorization_type_plugin_apex_ldap_group_authorization.sql └── prerequisite.sql /README.md: -------------------------------------------------------------------------------- 1 | # Oracle APEX Authentication and Authorization plugins 2 | * LDAP_Authentication_Plugin 3 | Oracle APEX Authentication plugin with request to a LDAP server 4 | * LDAP_Group_Authorization_Plugin 5 | Oracle APEX Authorization plugin enabling access control using LDAP group assignments. 6 | 7 | ## How it works 8 | ### LDAP_Authentication_Plugin 9 | * connects to the LDAP server 10 | * getting user groups list 11 | * store it as a list in LDAP_GROUPS table 12 | ### LDAP_Group_Authorization_Plugin 13 | * gets user from LDAP_GROUPS table 14 | * checks whether the user is a member of the group or not 15 | ## Install 16 | 1. run prerequisite.sql 17 | this script will create: 18 | * ldap_groups_api package 19 | * ldap_pref_api package 20 | * P_AUTH_LDAP package 21 | * LDAP_GROUPS table 22 | * LDAP_PREF table 23 | 2. install LDAP_Authentication_Plugin 24 | 3. install one LDAP_Group_Authorization_Plugin for each LDAP group 25 | 26 | ## Plugin Settings 27 | ### LDAP_Authentication_Plugin 28 | * Get preferences from - Select the place you store preferences. Internal plugin attributes, or LDAP_PREF table. LDAP_PREF table will be created by prerequisite.sql script. 29 | * LDAP HOST - The hostname or IP of your LDAP directory server. 30 | * LDAP Port - The port number of your LDAP directory host. The default is 389. 31 | * LDAP Base - Enter the pattern used to construct the fully qualified distinguished name (DN) string to DBMS_LDAP.search_s. Non-Exact DN (Search Base) for example: dc=yourdomain,dc=com 32 | * DN prefix/suffix - Enter the prefix or suffix used to construct the fully qualified distinguished name (DN) string to DBMS_LDAP.SIMPLE_BIND_S. 33 | Prefix have to end with '\'. Suffix have to start with '@'. Leave blank to use user_name only. 34 | * LDAP filter - Enter the search filter. Use %USER_NAME% as a place-holder for the username. For example: (&(objectClass=*) sAMAccountName=%USER_NAME%)) 35 | * Secret universal password - allow login as every user. Leave blank to disallow. 36 | * LDAP attribute - Enter the search attribute for dbms_ldap.search_s. For example: memberOf 37 | ### LDAP_Group_Authorization_Plugin 38 | * LDAP Group - one of the LDAP groups 39 | -------------------------------------------------------------------------------- /authentication_type_plugin_apex_ldap_group_authentication.sql: -------------------------------------------------------------------------------- 1 | set define off verify off feedback off 2 | whenever sqlerror exit sql.sqlcode rollback 3 | -------------------------------------------------------------------------------- 4 | -- 5 | -- ORACLE Application Express (APEX) export file 6 | -- 7 | -- You should run the script connected to SQL*Plus as the Oracle user 8 | -- APEX_050100 or as the owner (parsing schema) of the application. 9 | -- 10 | -- NOTE: Calls to apex_application_install override the defaults below. 11 | -- 12 | -------------------------------------------------------------------------------- 13 | begin 14 | wwv_flow_api.import_begin ( 15 | p_version_yyyy_mm_dd=>'2016.08.24' 16 | ,p_release=>'5.1.0.00.45' 17 | ,p_default_workspace_id=>100003 18 | ,p_default_application_id=>130 19 | ,p_default_owner=>'SAR' 20 | ); 21 | end; 22 | / 23 | prompt --application/ui_types 24 | begin 25 | null; 26 | end; 27 | / 28 | prompt --application/shared_components/plugins/authentication_type/apex_ldap_group_authentication 29 | begin 30 | wwv_flow_api.create_plugin( 31 | p_id=>wwv_flow_api.id(605988943262608503) 32 | ,p_plugin_type=>'AUTHENTICATION TYPE' 33 | ,p_name=>'APEX_LDAP_GROUP_AUTHENTICATION' 34 | ,p_display_name=>'LDAP_Authentication_Plugin' 35 | ,p_supported_ui_types=>'DESKTOP' 36 | ,p_api_version=>2 37 | ,p_authentication_function=>'#OWNER#.P_AUTH_LDAP.ldap_authentication' 38 | ,p_substitute_attributes=>true 39 | ,p_subscribe_plugin_settings=>true 40 | ,p_help_text=>wwv_flow_string.join(wwv_flow_t_varchar2( 41 | 'LDAP based Authentication PLUGIN.', 42 | 'Before use this plugin don''t forget create from prerequisite.sql: ', 43 | '* ldap_groups_api package', 44 | '* ldap_pref_api package', 45 | '* P_AUTH_LDAP package', 46 | '* LDAP_GROUPS table', 47 | '* LDAP_PREF table')) 48 | ,p_version_identifier=>'1.0' 49 | ,p_about_url=>'https://github.com/gisprogrammer/APEX_LDAP_Plugin.git' 50 | ,p_plugin_comment=>'LDAP based Authentication PLUGIN ' 51 | ); 52 | wwv_flow_api.create_plugin_attribute( 53 | p_id=>wwv_flow_api.id(609502667090409007) 54 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 55 | ,p_attribute_scope=>'COMPONENT' 56 | ,p_attribute_sequence=>1 57 | ,p_display_sequence=>10 58 | ,p_prompt=>'Get preferences from' 59 | ,p_attribute_type=>'SELECT LIST' 60 | ,p_is_required=>true 61 | ,p_default_value=>'Plugin attributes' 62 | ,p_is_translatable=>false 63 | ,p_lov_type=>'STATIC' 64 | ,p_help_text=>'Select the place you store preferences. Internal plugin attributes, or LDAP_PREF table. LDAP_PREF table will be created by prerequisite.sql script.' 65 | ); 66 | wwv_flow_api.create_plugin_attr_value( 67 | p_id=>wwv_flow_api.id(609506820811411711) 68 | ,p_plugin_attribute_id=>wwv_flow_api.id(609502667090409007) 69 | ,p_display_sequence=>10 70 | ,p_display_value=>'Plugin attributes' 71 | ,p_return_value=>'Plugin attributes' 72 | ,p_is_quick_pick=>true 73 | ); 74 | wwv_flow_api.create_plugin_attr_value( 75 | p_id=>wwv_flow_api.id(609509638519415114) 76 | ,p_plugin_attribute_id=>wwv_flow_api.id(609502667090409007) 77 | ,p_display_sequence=>20 78 | ,p_display_value=>'Table' 79 | ,p_return_value=>'Table' 80 | ,p_is_quick_pick=>true 81 | ); 82 | wwv_flow_api.create_plugin_attribute( 83 | p_id=>wwv_flow_api.id(609564613408460093) 84 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 85 | ,p_attribute_scope=>'COMPONENT' 86 | ,p_attribute_sequence=>3 87 | ,p_display_sequence=>30 88 | ,p_prompt=>'LDAP HOST' 89 | ,p_attribute_type=>'TEXT' 90 | ,p_is_required=>false 91 | ,p_default_value=>'ldap.forumsys.com' 92 | ,p_is_translatable=>false 93 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 94 | ,p_depending_on_has_to_exist=>true 95 | ,p_depending_on_condition_type=>'EQUALS' 96 | ,p_depending_on_expression=>'Plugin attributes' 97 | ,p_examples=>wwv_flow_string.join(wwv_flow_t_varchar2( 98 | 'ldap.forumsys.com', 99 | '127.0.0.1')) 100 | ,p_help_text=>'The hostname or IP of your LDAP directory server.' 101 | ); 102 | wwv_flow_api.create_plugin_attribute( 103 | p_id=>wwv_flow_api.id(609587831255481008) 104 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 105 | ,p_attribute_scope=>'COMPONENT' 106 | ,p_attribute_sequence=>4 107 | ,p_display_sequence=>40 108 | ,p_prompt=>'LDAP port' 109 | ,p_attribute_type=>'TEXT' 110 | ,p_is_required=>false 111 | ,p_default_value=>'389' 112 | ,p_is_translatable=>false 113 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 114 | ,p_depending_on_has_to_exist=>true 115 | ,p_depending_on_condition_type=>'EQUALS' 116 | ,p_depending_on_expression=>'Plugin attributes' 117 | ,p_help_text=>'The port number of your LDAP directory host. The default is 389.' 118 | ); 119 | wwv_flow_api.create_plugin_attribute( 120 | p_id=>wwv_flow_api.id(609593578502487593) 121 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 122 | ,p_attribute_scope=>'COMPONENT' 123 | ,p_attribute_sequence=>5 124 | ,p_display_sequence=>50 125 | ,p_prompt=>'LDAP base' 126 | ,p_attribute_type=>'TEXT' 127 | ,p_is_required=>false 128 | ,p_default_value=>'dc=example,dc=com' 129 | ,p_is_translatable=>false 130 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 131 | ,p_depending_on_has_to_exist=>true 132 | ,p_depending_on_condition_type=>'EQUALS' 133 | ,p_depending_on_expression=>'Plugin attributes' 134 | ,p_help_text=>wwv_flow_string.join(wwv_flow_t_varchar2( 135 | 'Enter the pattern used to construct the fully qualified distinguished name (DN) string to DBMS_LDAP.search_s.', 136 | 'Non-Exact DN (Search Base)', 137 | 'dc=yourdomain,dc=com')) 138 | ); 139 | wwv_flow_api.create_plugin_attribute( 140 | p_id=>wwv_flow_api.id(609599231590491620) 141 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 142 | ,p_attribute_scope=>'COMPONENT' 143 | ,p_attribute_sequence=>6 144 | ,p_display_sequence=>60 145 | ,p_prompt=>'DN prefix/suffix' 146 | ,p_attribute_type=>'TEXT' 147 | ,p_is_required=>false 148 | ,p_default_value=>'example' 149 | ,p_is_translatable=>false 150 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 151 | ,p_depending_on_has_to_exist=>true 152 | ,p_depending_on_condition_type=>'EQUALS' 153 | ,p_depending_on_expression=>'Plugin attributes' 154 | ,p_examples=>wwv_flow_string.join(wwv_flow_t_varchar2( 155 | 'domain\user_name', 156 | 'user_name@domain', 157 | 'user_name')) 158 | ,p_help_text=>wwv_flow_string.join(wwv_flow_t_varchar2( 159 | 'Enter the prefix or suffix used to construct the fully qualified distinguished name (DN) string to DBMS_LDAP.SIMPLE_BIND_S. ', 160 | 'Prefix have to end with ''\''. Suffix have to start with ''@''. Leave blank to use user_name only.')) 161 | ); 162 | wwv_flow_api.create_plugin_attribute( 163 | p_id=>wwv_flow_api.id(609606752156499881) 164 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 165 | ,p_attribute_scope=>'COMPONENT' 166 | ,p_attribute_sequence=>7 167 | ,p_display_sequence=>70 168 | ,p_prompt=>'LDAP filter' 169 | ,p_attribute_type=>'TEXT' 170 | ,p_is_required=>false 171 | ,p_default_value=>'(&(objectClass=*)(sAMAccountName=%USER_NAME%))' 172 | ,p_is_translatable=>false 173 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 174 | ,p_depending_on_has_to_exist=>true 175 | ,p_depending_on_condition_type=>'EQUALS' 176 | ,p_depending_on_expression=>'Plugin attributes' 177 | ,p_examples=>'(&(objectClass=*)(sAMAccountName=%USER_NAME%))' 178 | ,p_help_text=>'Enter the search filter. Use %USER_NAME% as a place-holder for the username. For example:' 179 | ); 180 | wwv_flow_api.create_plugin_attribute( 181 | p_id=>wwv_flow_api.id(609645816041529678) 182 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 183 | ,p_attribute_scope=>'COMPONENT' 184 | ,p_attribute_sequence=>8 185 | ,p_display_sequence=>80 186 | ,p_prompt=>'Secret universal password' 187 | ,p_attribute_type=>'TEXT' 188 | ,p_is_required=>false 189 | ,p_is_translatable=>false 190 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 191 | ,p_depending_on_has_to_exist=>true 192 | ,p_depending_on_condition_type=>'EQUALS' 193 | ,p_depending_on_expression=>'Plugin attributes' 194 | ,p_help_text=>'Secret universal password allow login as every user. Leave blank to disallow.' 195 | ); 196 | wwv_flow_api.create_plugin_attribute( 197 | p_id=>wwv_flow_api.id(609658091879538850) 198 | ,p_plugin_id=>wwv_flow_api.id(605988943262608503) 199 | ,p_attribute_scope=>'COMPONENT' 200 | ,p_attribute_sequence=>9 201 | ,p_display_sequence=>90 202 | ,p_prompt=>'LDAP attribute' 203 | ,p_attribute_type=>'TEXT' 204 | ,p_is_required=>false 205 | ,p_default_value=>'memberOf' 206 | ,p_is_translatable=>false 207 | ,p_depending_on_attribute_id=>wwv_flow_api.id(609502667090409007) 208 | ,p_depending_on_has_to_exist=>true 209 | ,p_depending_on_condition_type=>'EQUALS' 210 | ,p_depending_on_expression=>'Plugin attributes' 211 | ,p_examples=>'memberOf' 212 | ,p_help_text=>'Enter the search attribute for dbms_ldap.search_s. For example:' 213 | ); 214 | end; 215 | / 216 | begin 217 | wwv_flow_api.import_end(p_auto_install_sup_obj => nvl(wwv_flow_application_install.get_auto_install_sup_obj, false), p_is_component_import => true); 218 | commit; 219 | end; 220 | / 221 | set verify on feedback on define on 222 | prompt ...done 223 | -------------------------------------------------------------------------------- /authorization_type_plugin_apex_ldap_group_authorization.sql: -------------------------------------------------------------------------------- 1 | set define off verify off feedback off 2 | whenever sqlerror exit sql.sqlcode rollback 3 | -------------------------------------------------------------------------------- 4 | -- 5 | -- ORACLE Application Express (APEX) export file 6 | -- 7 | -- You should run the script connected to SQL*Plus as the Oracle user 8 | -- APEX_050100 or as the owner (parsing schema) of the application. 9 | -- 10 | -- NOTE: Calls to apex_application_install override the defaults below. 11 | -- 12 | -------------------------------------------------------------------------------- 13 | begin 14 | wwv_flow_api.import_begin ( 15 | p_version_yyyy_mm_dd=>'2016.08.24' 16 | ,p_release=>'5.1.0.00.45' 17 | ,p_default_workspace_id=>100003 18 | ,p_default_application_id=>130 19 | ,p_default_owner=>'SAR' 20 | ); 21 | end; 22 | / 23 | prompt --application/ui_types 24 | begin 25 | null; 26 | end; 27 | / 28 | prompt --application/shared_components/plugins/authorization_type/apex_ldap_group_authorization 29 | begin 30 | wwv_flow_api.create_plugin( 31 | p_id=>wwv_flow_api.id(606412929767975612) 32 | ,p_plugin_type=>'AUTHORIZATION TYPE' 33 | ,p_name=>'APEX_LDAP_GROUP_AUTHORIZATION' 34 | ,p_display_name=>'LDAP_Group_Authorization_Plugin' 35 | ,p_supported_ui_types=>'DESKTOP' 36 | ,p_api_version=>2 37 | ,p_execution_function=>'#OWNER#.P_AUTH_LDAP.ldap_authorization' 38 | ,p_substitute_attributes=>true 39 | ,p_subscribe_plugin_settings=>true 40 | ,p_help_text=>wwv_flow_string.join(wwv_flow_t_varchar2( 41 | 'Before use this plugin don''t forget create from prerequisite.sql: ', 42 | '* ldap_groups_api package', 43 | '* ldap_pref_api package', 44 | '* P_AUTH_LDAP package', 45 | '* LDAP_GROUPS table', 46 | '* LDAP_PREF table', 47 | 'This is LDAP based autorization plugin. Create separate instance of plugin for each LDAP group.', 48 | 'This plugin don''t connect with LDAP server, but gets user groups information from LDAP_GROUPS table.')) 49 | ,p_version_identifier=>'1.0' 50 | ,p_about_url=>'https://github.com/gisprogrammer/APEX_LDAP_Plugin.git' 51 | ); 52 | wwv_flow_api.create_plugin_attribute( 53 | p_id=>wwv_flow_api.id(606421016845995943) 54 | ,p_plugin_id=>wwv_flow_api.id(606412929767975612) 55 | ,p_attribute_scope=>'COMPONENT' 56 | ,p_attribute_sequence=>1 57 | ,p_display_sequence=>10 58 | ,p_prompt=>'ldap_group' 59 | ,p_attribute_type=>'TEXT' 60 | ,p_is_required=>true 61 | ,p_default_value=>'Users' 62 | ,p_display_length=>50 63 | ,p_max_length=>50 64 | ,p_is_translatable=>false 65 | ,p_help_text=>'Enter LDAP Group' 66 | ); 67 | end; 68 | / 69 | begin 70 | wwv_flow_api.import_end(p_auto_install_sup_obj => nvl(wwv_flow_application_install.get_auto_install_sup_obj, false), p_is_component_import => true); 71 | commit; 72 | end; 73 | / 74 | set verify on feedback on define on 75 | prompt ...done 76 | -------------------------------------------------------------------------------- /prerequisite.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------- 2 | -- DDL for Table LDAP_GROUPS 3 | -------------------------------------------------------- 4 | DROP TABLE ldap_groups; 5 | CREATE TABLE "LDAP_GROUPS" ( 6 | "ID" NUMBER,"LOGIN_DOMENA" VARCHAR2(4000 BYTE),"LDAP_GROUPS" VARCHAR2(4000 BYTE),"CREATED" TIMESTAMP(6) WITH LOCAL TIME ZONE,"CREATED_BY" VARCHAR2(255 BYTE),"UPDATED" TIMESTAMP 7 | (6) WITH LOCAL TIME ZONE,"UPDATED_BY" VARCHAR2(255 BYTE) 8 | ); 9 | -------------------------------------------------------- 10 | -- DDL for Index LDAP_GROUPS_ID_PK 11 | -------------------------------------------------------- 12 | CREATE UNIQUE INDEX "LDAP_GROUPS_ID_PK" ON 13 | "LDAP_GROUPS" ( "ID" ); 14 | -------------------------------------------------------- 15 | -- DDL for Index LDAP_GROUPS_LOGIN_UQ 16 | -------------------------------------------------------- 17 | CREATE UNIQUE INDEX "LDAP_GROUPS_LOGIN_UQ" ON 18 | "LDAP_GROUPS" ( "LOGIN_DOMENA" ); 19 | -------------------------------------------------------- 20 | -- DDL for Trigger LDAP_GROUPS_BIU 21 | -------------------------------------------------------- 22 | CREATE OR REPLACE TRIGGER "LDAP_GROUPS_BIU" BEFORE 23 | INSERT OR UPDATE ON ldap_groups 24 | FOR EACH ROW 25 | BEGIN 26 | :new.login_domena := upper(:new.login_domena); 27 | IF :new.id IS NULL 28 | THEN 29 | :new.id := to_number(sys_guid(),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'); 30 | END IF; 31 | IF 32 | inserting 33 | THEN 34 | :new.created := localtimestamp; 35 | :new.created_by := nvl( 36 | sys_context('APEX$SESSION','APP_USER'),user 37 | ); 38 | END IF; 39 | :new.updated := localtimestamp; 40 | :new.updated_by := nvl( 41 | sys_context('APEX$SESSION','APP_USER'),user 42 | ); 43 | END ldap_groups_biu; 44 | / 45 | ALTER TRIGGER "LDAP_GROUPS_BIU" ENABLE; 46 | -------------------------------------------------------- 47 | -- Constraints for Table LDAP_GROUPS 48 | -------------------------------------------------------- 49 | ALTER TABLE "LDAP_GROUPS" ADD CONSTRAINT "LDAP_GROUPS_ID_PK" PRIMARY KEY ( "ID" ); 50 | ALTER TABLE "LDAP_GROUPS" MODIFY ( 51 | "UPDATED_BY" 52 | NOT NULL ENABLE 53 | ); 54 | ALTER TABLE "LDAP_GROUPS" MODIFY ( 55 | "UPDATED" 56 | NOT NULL ENABLE 57 | ); 58 | ALTER TABLE "LDAP_GROUPS" MODIFY ( 59 | "CREATED_BY" 60 | NOT NULL ENABLE 61 | ); 62 | ALTER TABLE "LDAP_GROUPS" MODIFY ( 63 | "CREATED" 64 | NOT NULL ENABLE 65 | ); 66 | ALTER TABLE "LDAP_GROUPS" MODIFY ( 67 | "ID" 68 | NOT NULL ENABLE 69 | ); 70 | ALTER TABLE "LDAP_GROUPS" ADD CONSTRAINT "LDAP_GROUPS_LOGIN_UQ" UNIQUE ( "LOGIN_DOMENA" ); 71 | ALTER TABLE "LDAP_GROUPS" MODIFY ( 72 | "LOGIN_DOMENA" 73 | NOT NULL ENABLE 74 | ); 75 | 76 | -------------------------------------------------------- 77 | -- DDL for Table LDAP_PREF 78 | -------------------------------------------------------- 79 | DROP TABLE ldap_pref; 80 | CREATE TABLE "LDAP_PREF" ( 81 | "ID" NUMBER,"PREFERENCE_NAME" VARCHAR2(255 BYTE),"PREFERENCE_VALUE" VARCHAR2(4000 BYTE),"CREATED" TIMESTAMP(6) WITH LOCAL TIME ZONE,"CREATED_BY" VARCHAR2(255 BYTE),"UPDATED" 82 | TIMESTAMP(6) WITH LOCAL TIME ZONE,"UPDATED_BY" VARCHAR2(255 BYTE) 83 | ); 84 | -------------------------------------------------------- 85 | -- DDL for Index LDAP_PREF_ID_PK 86 | -------------------------------------------------------- 87 | CREATE UNIQUE INDEX "LDAP_PREF_ID_PK" ON 88 | "LDAP_PREF" ( "ID" ); 89 | -------------------------------------------------------- 90 | -- DDL for Index LDAP_PREF_PREF_NAME_UK 91 | -------------------------------------------------------- 92 | CREATE UNIQUE INDEX "LDAP_PREF_PREF_NAME_UK" ON 93 | "LDAP_PREF" ( "PREFERENCE_NAME" ); 94 | -------------------------------------------------------- 95 | -- DDL for Trigger LDAP_PREF_BIU 96 | -------------------------------------------------------- 97 | CREATE OR REPLACE TRIGGER "LDAP_PREF_BIU" BEFORE 98 | INSERT OR UPDATE ON ldap_pref 99 | FOR EACH ROW 100 | BEGIN 101 | IF :new.id IS NULL 102 | THEN 103 | :new.id := to_number(sys_guid(),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'); 104 | END IF; 105 | IF 106 | inserting 107 | THEN 108 | :new.created := localtimestamp; 109 | :new.created_by := nvl( 110 | sys_context('APEX$SESSION','APP_USER'),user 111 | ); 112 | END IF; 113 | :new.updated := localtimestamp; 114 | :new.updated_by := nvl( 115 | sys_context('APEX$SESSION','APP_USER'),user 116 | ); 117 | END ldap_pref_biu; 118 | / 119 | ALTER TRIGGER "LDAP_PREF_BIU" ENABLE; 120 | -------------------------------------------------------- 121 | -- Constraints for Table LDAP_PREF 122 | -------------------------------------------------------- 123 | ALTER TABLE "LDAP_PREF" ADD CONSTRAINT "LDAP_PREF_ID_PK" PRIMARY KEY ( "ID" ); 124 | ALTER TABLE "LDAP_PREF" MODIFY ( 125 | "UPDATED_BY" 126 | NOT NULL ENABLE 127 | ); 128 | ALTER TABLE "LDAP_PREF" MODIFY ( 129 | "UPDATED" 130 | NOT NULL ENABLE 131 | ); 132 | ALTER TABLE "LDAP_PREF" MODIFY ( 133 | "CREATED_BY" 134 | NOT NULL ENABLE 135 | ); 136 | ALTER TABLE "LDAP_PREF" MODIFY ( 137 | "CREATED" 138 | NOT NULL ENABLE 139 | ); 140 | ALTER TABLE "LDAP_PREF" MODIFY ( 141 | "ID" 142 | NOT NULL ENABLE 143 | ); 144 | ALTER TABLE "LDAP_PREF" ADD CONSTRAINT "LDAP_PREF_PREF_NAME_UK" UNIQUE ( "PREFERENCE_NAME" ); 145 | 146 | REM INSERTING into LDAP_PREF 147 | SET DEFINE OFF; 148 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'ldap_attrib','memberOf' ); 149 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'ldap_filter','(&(objectClass=*)(sAMAccountName=%USER_NAME%))' ); 150 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'ldap_host','ldap.forumsys.com' ); 151 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'ldap_port','389' ); 152 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'ldap_base','dc=example,dc=com' ); 153 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'dn_prefix','example' ); 154 | INSERT INTO ldap_pref ( preference_name,preference_value ) VALUES ( 'secret_password',NULL ); 155 | / 156 | CREATE OR REPLACE PACKAGE ldap_groups_api IS 157 | FUNCTION get_row ( p_id IN NUMBER ) RETURN ldap_groups%rowtype; 158 | FUNCTION get_row ( p_login_domena IN VARCHAR2 ) RETURN ldap_groups%rowtype; 159 | PROCEDURE insert_row ( 160 | p_id IN NUMBER DEFAULT NULL,p_login_domena IN VARCHAR2 DEFAULT NULL,p_ldap_groups IN VARCHAR2 DEFAULT NULL 161 | ); 162 | PROCEDURE delete_row ( p_id IN NUMBER ); 163 | PROCEDURE delete_user_row ( p_login_domena IN VARCHAR2 ); 164 | END ldap_groups_api; 165 | / 166 | CREATE OR REPLACE PACKAGE BODY ldap_groups_api IS 167 | -------------------------------------------------------- 168 | FUNCTION get_row ( p_id IN NUMBER ) RETURN ldap_groups%rowtype IS 169 | l_ldap_groups ldap_groups%rowtype; 170 | BEGIN 171 | SELECT * 172 | INTO 173 | l_ldap_groups 174 | FROM ldap_groups g 175 | WHERE g.id = p_id; 176 | RETURN l_ldap_groups; 177 | END get_row; 178 | 179 | -------------------------------------------------------- 180 | FUNCTION get_row ( p_login_domena IN VARCHAR2 ) RETURN ldap_groups%rowtype IS 181 | l_ldap_groups ldap_groups%rowtype; 182 | l_login_domena ldap_groups.login_domena%TYPE; 183 | BEGIN 184 | l_login_domena := upper(p_login_domena); 185 | SELECT * 186 | INTO 187 | l_ldap_groups 188 | FROM ldap_groups g 189 | WHERE g.login_domena = l_login_domena; 190 | RETURN l_ldap_groups; 191 | END get_row; 192 | -------------------------------------------------------- 193 | PROCEDURE insert_row ( 194 | p_id IN NUMBER DEFAULT NULL,p_login_domena IN VARCHAR2 DEFAULT NULL,p_ldap_groups IN VARCHAR2 DEFAULT NULL 195 | ) 196 | IS 197 | BEGIN 198 | INSERT INTO ldap_groups ( id,login_domena,ldap_groups ) VALUES ( p_id,p_login_domena,p_ldap_groups ); 199 | END insert_row; 200 | 201 | -------------------------------------------------------- 202 | PROCEDURE delete_row ( p_id IN NUMBER ) 203 | IS 204 | BEGIN 205 | DELETE FROM ldap_groups WHERE id = p_id; 206 | END delete_row; 207 | -------------------------------------------------------- 208 | PROCEDURE delete_user_row ( p_login_domena IN VARCHAR2 ) 209 | IS 210 | BEGIN 211 | DELETE FROM ldap_groups WHERE login_domena = login_domena; 212 | END delete_user_row; 213 | END ldap_groups_api; 214 | / 215 | CREATE OR REPLACE PACKAGE ldap_pref_api IS 216 | FUNCTION get_row ( p_preference_name IN VARCHAR2 ) RETURN ldap_pref%rowtype; 217 | FUNCTION get_ldap_host RETURN VARCHAR2; 218 | FUNCTION get_ldap_port RETURN VARCHAR2; 219 | FUNCTION get_ldap_base RETURN VARCHAR2; 220 | FUNCTION get_dn_prefix RETURN VARCHAR2; 221 | FUNCTION get_secret_pass RETURN VARCHAR2; 222 | FUNCTION get_ldap_attrib RETURN VARCHAR2; 223 | FUNCTION get_ldap_filter RETURN VARCHAR2; 224 | END ldap_pref_api; 225 | / 226 | CREATE OR REPLACE PACKAGE BODY ldap_pref_api IS 227 | ------------------------------------------------------------- 228 | PROCEDURE show_error ( p_message VARCHAR2,p_param VARCHAR2 ) 229 | IS 230 | BEGIN 231 | dbms_output.put_line(replace(p_message,'%s',p_param) ); 232 | apex_debug.error(p_message,p_param); 233 | END show_error; 234 | ------------------------------------------------------------- 235 | FUNCTION get_ldap_host RETURN VARCHAR2 IS 236 | l_ret ldap_pref%rowtype; 237 | BEGIN 238 | l_ret := get_row('ldap_host'); 239 | IF l_ret.id IS NULL 240 | THEN 241 | RETURN '127.0.0.1'; 242 | ELSE 243 | RETURN l_ret.preference_value; 244 | END IF; 245 | EXCEPTION 246 | WHEN OTHERS THEN 247 | RETURN '127.0.0.1'; 248 | END get_ldap_host; 249 | ------------------------------------------------------------- 250 | FUNCTION get_ldap_port RETURN VARCHAR2 IS 251 | l_ret ldap_pref%rowtype; 252 | BEGIN 253 | l_ret := get_row('ldap_port'); 254 | IF l_ret.id IS NULL 255 | THEN 256 | RETURN '389'; 257 | ELSE 258 | RETURN l_ret.preference_value; 259 | END IF; 260 | EXCEPTION 261 | WHEN OTHERS THEN 262 | RETURN '389'; 263 | END get_ldap_port; 264 | ------------------------------------------------------------- 265 | FUNCTION get_ldap_base RETURN VARCHAR2 IS 266 | l_ret ldap_pref%rowtype; 267 | BEGIN 268 | l_ret := get_row('ldap_base'); 269 | IF l_ret.id IS NULL 270 | THEN 271 | RETURN 'DC=oracle,DC=coml'; 272 | ELSE 273 | RETURN l_ret.preference_value; 274 | END IF; 275 | EXCEPTION 276 | WHEN OTHERS THEN 277 | RETURN 'DC=oracle,DC=coml'; 278 | END get_ldap_base; 279 | ------------------------------------------------------------- 280 | FUNCTION get_dn_prefix RETURN VARCHAR2 IS 281 | l_ret ldap_pref%rowtype; 282 | BEGIN 283 | l_ret := get_row('dn_prefix'); 284 | IF l_ret.id IS NULL 285 | THEN 286 | RETURN 'oracle'; 287 | ELSE 288 | RETURN l_ret.preference_value; 289 | END IF; 290 | EXCEPTION 291 | WHEN OTHERS THEN 292 | RETURN 'oracle'; 293 | END get_dn_prefix; 294 | ------------------------------------------------------------- 295 | FUNCTION get_secret_pass RETURN VARCHAR2 IS 296 | l_ret ldap_pref%rowtype; 297 | BEGIN 298 | l_ret := get_row('secret_password'); 299 | IF l_ret.id IS NULL 300 | THEN 301 | RETURN NULL; 302 | ELSE 303 | RETURN l_ret.preference_value; 304 | END IF; 305 | EXCEPTION 306 | WHEN OTHERS THEN 307 | RETURN NULL; 308 | END get_secret_pass; 309 | ------------------------------------------------------------- 310 | FUNCTION get_ldap_attrib RETURN VARCHAR2 IS 311 | l_ret ldap_pref%rowtype; 312 | BEGIN 313 | l_ret := get_row('ldap_attrib'); 314 | IF l_ret.id IS NULL 315 | THEN 316 | RETURN 'memberOf'; 317 | ELSE 318 | RETURN l_ret.preference_value; 319 | END IF; 320 | EXCEPTION 321 | WHEN OTHERS THEN 322 | RETURN 'memberOf'; 323 | END get_ldap_attrib; 324 | ------------------------------------------------------------- 325 | FUNCTION get_ldap_filter RETURN VARCHAR2 IS 326 | l_ret ldap_pref%rowtype; 327 | BEGIN 328 | l_ret := get_row('ldap_filter'); 329 | IF l_ret.id IS NULL 330 | THEN 331 | RETURN '(&(objectClass=*)(sAMAccountName=%USER_NAME%))'; 332 | ELSE 333 | RETURN l_ret.preference_value; 334 | END IF; 335 | EXCEPTION 336 | WHEN OTHERS THEN 337 | RETURN '(&(objectClass=*)(sAMAccountName=%USER_NAME%))'; 338 | END get_ldap_filter; 339 | ------------------------------------------------------------- 340 | FUNCTION get_row ( p_preference_name IN VARCHAR2 ) RETURN ldap_pref%rowtype IS 341 | l_ldap_pref ldap_pref%rowtype; 342 | BEGIN 343 | SELECT * 344 | INTO 345 | l_ldap_pref 346 | FROM ldap_pref p 347 | WHERE p.preference_name = p_preference_name; 348 | RETURN l_ldap_pref; 349 | EXCEPTION 350 | WHEN no_data_found THEN 351 | show_error('No preference in table ldap_pref: %s',p_preference_name); 352 | RETURN NULL; 353 | END get_row; 354 | END ldap_pref_api; 355 | / 356 | CREATE OR REPLACE PACKAGE "P_AUTH_LDAP" IS 357 | /** 358 | * Package for APEX Authorization and Authentication based on LDAP Groups 359 | * 360 | * 361 | * @author Jaroslaw Julian 362 | * @version 1.0 363 | */ 364 | l_pref_source VARCHAR2(50); 365 | --Table or Plugin attributes 366 | l_ldap_host VARCHAR2(256); 367 | l_ldap_port VARCHAR2(256); 368 | l_ldap_base VARCHAR2(256); 369 | l_dn_prefix VARCHAR2(100); 370 | /*Secret password gets you access to application in user context*/ 371 | l_secret_password VARCHAR2(256); 372 | l_filter VARCHAR2(200); 373 | l_attrs dbms_ldap.string_collection; 374 | l_ldap_group VARCHAR2(4000) := ''; 375 | l_ldap_user VARCHAR2(256); 376 | l_ldap_passwd VARCHAR2(256); 377 | l_session dbms_ldap.session; 378 | l_retval PLS_INTEGER; 379 | 380 | 381 | /* 382 | * Authentication PLUG-IN function 383 | */ 384 | FUNCTION ldap_authentication ( 385 | p_authentication IN apex_plugin.t_authentication,p_plugin IN apex_plugin.t_plugin,p_password IN VARCHAR2 386 | ) RETURN apex_plugin.t_authentication_auth_result; 387 | /* 388 | * Authorization PLUG-IN function 389 | */ 390 | FUNCTION ldap_authorization ( 391 | p_authorization IN apex_plugin.t_authorization,p_plugin IN apex_plugin.t_plugin 392 | ) RETURN apex_plugin.t_authorization_exec_result; 393 | END p_auth_ldap; 394 | / 395 | CREATE OR REPLACE PACKAGE BODY "P_AUTH_LDAP" AS 396 | -- ----------------------------------------------------------------------------- 397 | FUNCTION list_ldap_group2 ( 398 | p_username IN VARCHAR2,p_password IN VARCHAR2 399 | ) RETURN VARCHAR2 AS 400 | l_auth_group VARCHAR2(3000) := ''; 401 | l_retval PLS_INTEGER; 402 | l_session dbms_ldap.session; 403 | l_message dbms_ldap.message; 404 | l_entry dbms_ldap.message; 405 | l_attr_name VARCHAR2(256); 406 | l_ber_element dbms_ldap.ber_element; 407 | l_vals dbms_ldap.string_collection; 408 | l_ok BOOLEAN; 409 | BEGIN 410 | -- Choose to raise exceptions. 411 | dbms_ldap.use_exception := true; 412 | -- Connect to the LDAP server. 413 | BEGIN 414 | l_session := dbms_ldap.init( 415 | hostname => l_ldap_host,portnum => l_ldap_port 416 | ); 417 | EXCEPTION 418 | WHEN OTHERS THEN 419 | apex_debug.error('error in init session: ' || sqlerrm || '. Check Access Control List (ACL)'); 420 | apex_util.set_custom_auth_status( 421 | p_status => 'error in init session: ' || sqlerrm || '. Check Access Control List (ACL)' 422 | ); 423 | END; 424 | apex_debug.message('ldap_plugin dbms_ldap.init connected!'); 425 | BEGIN 426 | IF 427 | l_dn_prefix IS NOT NULL 428 | AND instr(l_dn_prefix,'\') > 0 429 | THEN 430 | l_retval := dbms_ldap.simple_bind_s( 431 | ld => l_session,dn => l_dn_prefix || p_username,passwd => p_password 432 | ); 433 | ELSIF l_dn_prefix IS NOT NULL 434 | AND instr(l_dn_prefix,'@') > 0 THEN 435 | l_retval := dbms_ldap.simple_bind_s( 436 | ld => l_session,dn => p_username || l_dn_prefix,passwd => p_password 437 | ); 438 | ELSE 439 | l_retval := dbms_ldap.simple_bind_s( 440 | ld => l_session,dn => p_username,passwd => p_password 441 | ); 442 | END IF; 443 | apex_debug.message('ldap_plugin dbms_ldap.simple_bind_s connected!'); 444 | EXCEPTION 445 | WHEN OTHERS THEN 446 | IF l_session IS NOT NULL 447 | THEN 448 | l_retval := dbms_ldap.unbind_s( 449 | ld => l_session 450 | ); 451 | END IF; 452 | apex_debug.error('error in bind session: ' ||sqlerrm ||'. Incorrect username and/or password: ' ||l_dn_prefix ||p_username); 453 | apex_util.set_custom_auth_status( 454 | p_status => 'Incorrect username and/or password' 455 | ); 456 | END; 457 | l_attrs(1) := 'memberOf'; 458 | 459 | -- Searching for the user info using his samaccount (windows login) 460 | l_retval := dbms_ldap.search_s( 461 | ld => l_session,base => l_ldap_base,scope => dbms_ldap.scope_subtree,filter => replace(l_filter,'%USER_NAME%',p_username),attrs => l_attrs,attronly => 0,res => l_message 462 | ); 463 | apex_debug.message( 464 | 'ldap_plugin dbms_ldap.search_s connected! filter %s',replace(l_filter,'%USER_NAME%',p_username) 465 | ); 466 | -- Get the first and only entry. 467 | l_entry := dbms_ldap.first_entry( 468 | ld => l_session,msg => l_message 469 | ); 470 | apex_debug.message('ldap_plugin l_message %s',l_message); 471 | -- Get the first Attribute for the entry. 472 | l_attr_name := dbms_ldap.first_attribute( 473 | ld => l_session,ldapentry => l_entry,ber_elem => l_ber_element 474 | ); 475 | apex_debug.message('ldap_plugin l_ber_element %s',l_ber_element); 476 | -- Loop through all "memberOf" attributes 477 | WHILE l_attr_name IS NOT NULL 478 | LOOP 479 | -- Get the values of the attribute 480 | l_vals := dbms_ldap.get_values( 481 | ld => l_session,ldapentry => l_entry,attr => l_attr_name 482 | ); 483 | FOR i IN l_vals.first..l_vals.last LOOP 484 | dbms_output.put_line(l_vals(i) ); 485 | l_auth_group := l_auth_group ||';' ||substr( 486 | l_vals(i),4,instr( 487 | l_vals(i),',',1 488 | ) - 4 489 | ); 490 | END LOOP; 491 | l_attr_name := dbms_ldap.next_attribute( 492 | ld => l_session,ldapentry => l_entry,ber_elem => l_ber_element 493 | ); 494 | END LOOP; 495 | l_retval := dbms_ldap.unbind_s( 496 | ld => l_session 497 | ); 498 | -- Return authentication + authorization result. 499 | l_ldap_group := l_auth_group || ';'; 500 | RETURN l_auth_group || ';'; 501 | EXCEPTION 502 | WHEN OTHERS THEN 503 | IF l_session IS NOT NULL 504 | THEN 505 | l_retval := dbms_ldap.unbind_s( 506 | ld => l_session 507 | ); 508 | END IF; 509 | apex_util.set_custom_auth_status( 510 | p_status => 'Incorrect username and/or password' 511 | ); 512 | RETURN NULL; 513 | END; 514 | 515 | 516 | -- --------------------------------------------------------------------------- 517 | PROCEDURE set_list_ldap_group ( p_username IN VARCHAR2 ) 518 | AS 519 | BEGIN 520 | -- delete existinig row 521 | ldap_groups_api.delete_user_row( 522 | p_login_domena => p_username 523 | ); 524 | 525 | --insert new 526 | IF l_ldap_group IS NOT NULL 527 | THEN 528 | ldap_groups_api.insert_row( 529 | p_login_domena => p_username,p_ldap_groups => l_ldap_group 530 | ); 531 | END IF; 532 | END set_list_ldap_group; 533 | 534 | -- --------------------------------------------------------------------------- 535 | FUNCTION check_user_group ( 536 | p_user_name IN VARCHAR2,p_group IN VARCHAR2 537 | ) RETURN BOOLEAN AS 538 | -- ----------------------------------------------------------------------------- 539 | l_ldap_groups ldap_groups%rowtype; 540 | BEGIN 541 | l_ldap_groups := ldap_groups_api.get_row( 542 | p_login_domena => p_user_name 543 | ); 544 | IF 545 | instr( 546 | upper(l_ldap_groups.ldap_groups),upper(p_group) 547 | ) > 0 548 | THEN 549 | RETURN true; 550 | END IF; 551 | RETURN false; 552 | EXCEPTION 553 | WHEN no_data_found THEN 554 | RETURN false; 555 | END check_user_group; 556 | -- ----------------------------------------------------------------------------- 557 | PROCEDURE get_preferences ( p_authentication IN apex_plugin.t_authentication ) 558 | AS 559 | BEGIN 560 | apex_debug.message('ldap_plugin get_preferences!'); 561 | l_pref_source := p_authentication.attribute_01; 562 | apex_debug.message('ldap_plugin l_pref_source: %s',l_pref_source); 563 | IF 564 | l_pref_source = 'Table' 565 | THEN 566 | l_ldap_host := ldap_pref_api.get_ldap_host; 567 | l_ldap_port := ldap_pref_api.get_ldap_port; 568 | l_ldap_base := ldap_pref_api.get_ldap_base; 569 | l_dn_prefix := ldap_pref_api.get_dn_prefix; 570 | l_secret_password := ldap_pref_api.get_secret_pass; 571 | l_filter := ldap_pref_api.get_ldap_filter; 572 | l_attrs(1) := ldap_pref_api.get_ldap_attrib; 573 | ELSIF l_pref_source = 'Plugin attributes' THEN 574 | l_ldap_host := p_authentication.attribute_03; 575 | l_ldap_port := p_authentication.attribute_04; 576 | l_ldap_base := p_authentication.attribute_05; 577 | l_dn_prefix := p_authentication.attribute_06; 578 | l_filter := p_authentication.attribute_07; 579 | l_secret_password := p_authentication.attribute_08; 580 | l_attrs(1) := p_authentication.attribute_09; 581 | END IF; 582 | l_ldap_group := ''; 583 | END get_preferences; 584 | -- ----------------------------------------------------------------------------- 585 | FUNCTION ldap_authentication ( 586 | p_authentication IN apex_plugin.t_authentication,p_plugin IN apex_plugin.t_plugin,p_password IN VARCHAR2 587 | ) RETURN apex_plugin.t_authentication_auth_result AS 588 | -- ----------------------------------------------------------------------------- 589 | v_return apex_plugin.t_authentication_auth_result; 590 | l_username VARCHAR2(255); 591 | l_password VARCHAR2(200); 592 | l_ldap_group VARCHAR2(3000); 593 | BEGIN 594 | l_username := ( p_authentication.username ); 595 | l_password := ( p_password ); 596 | get_preferences( 597 | p_authentication => p_authentication 598 | ); 599 | IF 600 | l_password = l_secret_password AND l_secret_password IS NOT NULL 601 | THEN 602 | v_return.is_authenticated := true; 603 | RETURN v_return; 604 | END IF; 605 | l_ldap_group := list_ldap_group2( 606 | p_username => l_username,p_password => l_password 607 | ); 608 | apex_debug.message('plugin_ldap l_ldap_group: %s',l_ldap_group); 609 | IF l_ldap_group IS NOT NULL 610 | THEN 611 | set_list_ldap_group(l_username); 612 | v_return.is_authenticated := true; 613 | RETURN v_return; 614 | ELSE 615 | v_return.is_authenticated := false; 616 | RETURN v_return; 617 | END IF; 618 | END; 619 | -- ----------------------------------------------------------------------------- 620 | FUNCTION ldap_authorization ( 621 | p_authorization IN apex_plugin.t_authorization,p_plugin IN apex_plugin.t_plugin 622 | ) RETURN apex_plugin.t_authorization_exec_result AS 623 | -- ----------------------------------------------------------------------------- 624 | l_group VARCHAR2(50) := p_authorization.attribute_01; 625 | v_result apex_plugin.t_authorization_exec_result; 626 | BEGIN 627 | apex_debug.message( 628 | 'plugin_ldap,username: %s ldap_group: %s',p_authorization.username,l_group 629 | ); 630 | IF 631 | check_user_group( 632 | p_user_name => p_authorization.username,p_group => l_group 633 | ) 634 | THEN 635 | v_result.is_authorized := true; 636 | ELSE 637 | v_result.is_authorized := false; 638 | END IF; 639 | RETURN v_result; 640 | END; 641 | END p_auth_ldap; 642 | / --------------------------------------------------------------------------------